]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/nd6_send.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / bsd / netinet6 / nd6_send.c
1 /*
2 * Copyright (c) 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/types.h>
30 #include <sys/malloc.h>
31 #include <sys/proc.h>
32 #include <sys/sysctl.h>
33 #include <sys/syslog.h>
34
35 #include <libkern/crypto/sha1.h>
36
37 #include <net/if.h>
38
39 #include <netinet/in.h>
40 #include <netinet6/in6_var.h>
41 #include <netinet/ip6.h>
42 #include <netinet6/ip6_var.h>
43 #include <netinet6/nd6.h>
44
45 SYSCTL_DECL(_net_inet6); /* Note: Not in any common header. */
46
47 SYSCTL_NODE(_net_inet6, OID_AUTO, send, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
48 "IPv6 Secure Neighbor Discovery");
49
50 static int nd6_send_opmode = ND6_SEND_OPMODE_DISABLED;
51
52 SYSCTL_INT(_net_inet6_send, OID_AUTO, opstate, CTLFLAG_RD | CTLFLAG_LOCKED,
53 &nd6_send_opstate, 0, "current SEND operating state");
54
55 int nd6_send_opstate = ND6_SEND_OPMODE_DISABLED;
56 SYSCTL_INT(_net_inet6_send, OID_AUTO, opmode, CTLFLAG_RW | CTLFLAG_LOCKED,
57 &nd6_send_opmode, 0, "configured SEND operating mode");
58
59 static int sysctl_cga_parameters SYSCTL_HANDLER_ARGS;
60
61 SYSCTL_PROC(_net_inet6_send, OID_AUTO, cga_parameters,
62 CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0,
63 sysctl_cga_parameters, "S,nd6_send_nodecfg", "");
64
65 /*
66 * The size of the buffer is sufficient to contain a public key, its size in
67 * machine binary type for the kernel, and the CGA precalc for the global
68 * scope. This interface is not a public API, so we don't anticipate that the
69 * userland and the kernel will be mismatched between ILP32 and LP64.
70 */
71 #define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
72 2 * (sizeof (u_int16_t) + IN6_CGA_KEY_MAXSIZE) + \
73 sizeof (struct in6_cga_prepare)
74
75 static int
76 sysctl_cga_parameters SYSCTL_HANDLER_ARGS
77 {
78 #pragma unused(oidp, arg1)
79 u_int namelen;
80 char *oldp, *newp;
81 const char *fin;
82 struct in6_cga_nodecfg cfg;
83 struct iovec *iov;
84 int error;
85 char *buffer;
86 u_int16_t u16;
87
88 namelen = arg2;
89 if (namelen != 0) {
90 log(LOG_ERR, "%s: name length err [len=%u]\n", __func__,
91 namelen);
92 return (EINVAL);
93 }
94
95 if (req->newlen > SYSCTL_CGA_PARAMETERS_BUFFER_SIZE) {
96 log(LOG_ERR, "%s: input buffer size error [len=%u]\n", __func__,
97 req->newlen);
98 return (EINVAL);
99 }
100
101 MALLOC(buffer, char *, SYSCTL_CGA_PARAMETERS_BUFFER_SIZE, M_IP6CGA,
102 M_WAITOK);
103 if (buffer == NULL) {
104 log(LOG_ERR, "%s: could not allocate marshaling buffer.\n",
105 __func__);
106 return (ENOMEM);
107 }
108
109 in6_cga_node_lock();
110
111 if (req->oldptr != USER_ADDR_NULL && req->oldlen > 0) {
112 oldp = buffer;
113 fin = &buffer[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
114 if (req->oldlen < SYSCTL_CGA_PARAMETERS_BUFFER_SIZE)
115 fin = &buffer[req->oldlen];
116
117 in6_cga_query(&cfg);
118 iov = &cfg.cga_pubkey;
119 if (iov->iov_len > 0) {
120 VERIFY(iov->iov_len < UINT16_MAX);
121
122 if (&oldp[sizeof (cfg.cga_prepare)] <= fin)
123 bcopy(&cfg.cga_prepare, oldp,
124 sizeof (cfg.cga_prepare));
125 oldp += sizeof (cfg.cga_prepare);
126
127 if (&oldp[sizeof (u16)] < fin) {
128 u16 = (u_int16_t) iov->iov_len;
129 bcopy(&u16, oldp, sizeof (u16));
130 }
131 oldp += sizeof (u16);
132
133 if (&oldp[iov->iov_len] < fin)
134 bcopy(iov->iov_base, oldp, iov->iov_len);
135 oldp += iov->iov_len;
136
137 if (oldp > fin) {
138 req->oldlen = oldp - buffer;
139 log(LOG_ERR, "%s: marshalled data too large.\n",
140 __func__);
141 error = ENOMEM;
142 goto done;
143 }
144 }
145
146 error = SYSCTL_OUT(req, buffer, oldp - buffer);
147 if (error)
148 goto done;
149 }
150
151 if (req->newptr == USER_ADDR_NULL)
152 goto done;
153
154 error = proc_suser(current_proc());
155 if (error)
156 goto done;
157
158 if (req->newlen == 0) {
159 in6_cga_stop();
160 nd6_send_opstate = ND6_SEND_OPMODE_DISABLED;
161 goto done;
162 }
163
164 error = SYSCTL_IN(req, buffer, req->newlen);
165 if (error)
166 goto done;
167
168 newp = buffer;
169 fin = &buffer[req->newlen];
170
171 bzero(&cfg, sizeof cfg);
172
173 if (&newp[sizeof (cfg.cga_prepare)] <= fin)
174 bcopy(newp, &cfg.cga_prepare, sizeof (cfg.cga_prepare));
175 newp += sizeof (cfg.cga_prepare);
176
177 iov = &cfg.cga_privkey;
178 if (&newp[sizeof (u16)] < fin) {
179 bcopy(newp, &u16, sizeof (u16));
180 iov->iov_len = u16;
181
182 if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) {
183 error = EINVAL;
184 goto done;
185 }
186 }
187 newp += sizeof (u16);
188
189 iov->iov_base = newp;
190 newp += iov->iov_len;
191
192 iov = &cfg.cga_pubkey;
193 if (&newp[sizeof (u16)] < fin) {
194 bcopy(newp, &u16, sizeof (u16));
195 iov->iov_len = u16;
196
197 if (iov->iov_len > IN6_CGA_KEY_MAXSIZE) {
198 error = EINVAL;
199 goto done;
200 }
201 }
202 newp += sizeof (u16);
203
204 iov->iov_base = newp;
205 newp += iov->iov_len;
206
207 if (newp > fin) {
208 log(LOG_ERR, "%s: input too large [octets=%ld].\n", __func__,
209 newp - fin);
210 error = ENOMEM;
211 goto done;
212 }
213
214 error = in6_cga_start(&cfg);
215 if (!error)
216 nd6_send_opstate = nd6_send_opmode;
217 else
218 log(LOG_ERR, "%s: in6_cga_start error=%d.\n", __func__,
219 error);
220
221 done:
222 in6_cga_node_unlock();
223 FREE(buffer, M_IP6CGA);
224 return (error);
225 }
226
227 /* End of file */