link_proto.c revision 1.19 1 /* $NetBSD: link_proto.c,v 1.19 2014/07/31 03:39:35 rtr Exp $ */
2
3 /*-
4 * Copyright (c) 1982, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)uipc_proto.c 8.2 (Berkeley) 2/14/95
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: link_proto.c,v 1.19 2014/07/31 03:39:35 rtr Exp $");
36
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/protosw.h>
40 #include <sys/domain.h>
41 #include <sys/mbuf.h>
42 #include <sys/un.h>
43 #include <sys/socketvar.h>
44
45 #include <net/if.h>
46 #include <net/if_dl.h>
47 #include <net/raw_cb.h>
48 #include <net/route.h>
49
50 static int sockaddr_dl_cmp(const struct sockaddr *, const struct sockaddr *);
51 static int link_attach(struct socket *, int);
52 static void link_detach(struct socket *);
53 static int link_accept(struct socket *, struct mbuf *);
54 static int link_bind(struct socket *, struct mbuf *);
55 static int link_listen(struct socket *);
56 static int link_disconnect(struct socket *);
57 static int link_shutdown(struct socket *);
58 static int link_abort(struct socket *);
59 static int link_ioctl(struct socket *, u_long, void *, struct ifnet *);
60 static int link_stat(struct socket *, struct stat *);
61 static int link_peeraddr(struct socket *, struct mbuf *);
62 static int link_sockaddr(struct socket *, struct mbuf *);
63 static int link_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
64 struct mbuf *, struct lwp *);
65 static void link_init(void);
66
67 /*
68 * Definitions of protocols supported in the link-layer domain.
69 */
70
71 DOMAIN_DEFINE(linkdomain); /* forward define and add to link set */
72
73 static const struct pr_usrreqs link_usrreqs = {
74 .pr_attach = link_attach,
75 .pr_detach = link_detach,
76 .pr_accept = link_accept,
77 .pr_bind = link_bind,
78 .pr_listen = link_listen,
79 .pr_disconnect = link_disconnect,
80 .pr_shutdown = link_shutdown,
81 .pr_abort = link_abort,
82 .pr_ioctl = link_ioctl,
83 .pr_stat = link_stat,
84 .pr_peeraddr = link_peeraddr,
85 .pr_sockaddr = link_sockaddr,
86 .pr_generic = link_usrreq,
87 };
88
89 const struct protosw linksw[] = {
90 { .pr_type = SOCK_DGRAM,
91 .pr_domain = &linkdomain,
92 .pr_protocol = 0, /* XXX */
93 .pr_flags = PR_ATOMIC|PR_ADDR|PR_PURGEIF,
94 .pr_input = NULL,
95 .pr_ctlinput = NULL,
96 .pr_ctloutput = NULL,
97 .pr_usrreqs = &link_usrreqs,
98 .pr_init = link_init,
99 },
100 };
101
102 struct domain linkdomain = {
103 .dom_family = AF_LINK,
104 .dom_name = "link",
105 .dom_externalize = NULL,
106 .dom_dispose = NULL,
107 .dom_protosw = linksw,
108 .dom_protoswNPROTOSW = &linksw[__arraycount(linksw)],
109 .dom_sockaddr_cmp = sockaddr_dl_cmp
110 };
111
112 static void
113 link_init(void)
114 {
115 return;
116 }
117
118 static int
119 link_control(struct socket *so, unsigned long cmd, void *data,
120 struct ifnet *ifp)
121 {
122 int error, s;
123 bool isactive, mkactive;
124 struct if_laddrreq *iflr;
125 union {
126 struct sockaddr sa;
127 struct sockaddr_dl sdl;
128 struct sockaddr_storage ss;
129 } u;
130 struct ifaddr *ifa;
131 const struct sockaddr_dl *asdl, *nsdl;
132
133 switch (cmd) {
134 case SIOCALIFADDR:
135 case SIOCDLIFADDR:
136 case SIOCGLIFADDR:
137 iflr = data;
138
139 if (iflr->addr.ss_family != AF_LINK)
140 return EINVAL;
141
142 asdl = satocsdl(sstocsa(&iflr->addr));
143
144 if (asdl->sdl_alen != ifp->if_addrlen)
145 return EINVAL;
146
147 if (sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index,
148 ifp->if_type, ifp->if_xname, strlen(ifp->if_xname),
149 CLLADDR(asdl), asdl->sdl_alen) == NULL)
150 return EINVAL;
151
152 if ((iflr->flags & IFLR_PREFIX) == 0)
153 ;
154 else if (iflr->prefixlen != NBBY * ifp->if_addrlen)
155 return EINVAL; /* XXX match with prefix */
156
157 error = 0;
158
159 s = splnet();
160
161 IFADDR_FOREACH(ifa, ifp) {
162 if (sockaddr_cmp(&u.sa, ifa->ifa_addr) == 0)
163 break;
164 }
165
166 switch (cmd) {
167 case SIOCGLIFADDR:
168 if ((iflr->flags & IFLR_PREFIX) == 0) {
169 IFADDR_FOREACH(ifa, ifp) {
170 if (ifa->ifa_addr->sa_family == AF_LINK)
171 break;
172 }
173 }
174 if (ifa == NULL) {
175 error = EADDRNOTAVAIL;
176 break;
177 }
178
179 if (ifa == ifp->if_dl)
180 iflr->flags = IFLR_ACTIVE;
181 else
182 iflr->flags = 0;
183
184 if (ifa == ifp->if_hwdl)
185 iflr->flags |= IFLR_FACTORY;
186
187 sockaddr_copy(sstosa(&iflr->addr), sizeof(iflr->addr),
188 ifa->ifa_addr);
189
190 break;
191 case SIOCDLIFADDR:
192 if (ifa == NULL)
193 error = EADDRNOTAVAIL;
194 else if (ifa == ifp->if_dl || ifa == ifp->if_hwdl)
195 error = EBUSY;
196 else {
197 /* TBD routing socket */
198 rt_newaddrmsg(RTM_DELETE, ifa, 0, NULL);
199 ifa_remove(ifp, ifa);
200 }
201 break;
202 case SIOCALIFADDR:
203 if (ifa != NULL)
204 ;
205 else if ((ifa = if_dl_create(ifp, &nsdl)) == NULL) {
206 error = ENOMEM;
207 break;
208 } else {
209 sockaddr_copy(ifa->ifa_addr,
210 ifa->ifa_addr->sa_len, &u.sa);
211 ifa_insert(ifp, ifa);
212 rt_newaddrmsg(RTM_ADD, ifa, 0, NULL);
213 }
214
215 mkactive = (iflr->flags & IFLR_ACTIVE) != 0;
216 isactive = (ifa == ifp->if_dl);
217
218 if (!isactive && mkactive) {
219 if_activate_sadl(ifp, ifa, nsdl);
220 rt_newaddrmsg(RTM_CHANGE, ifa, 0, NULL);
221 error = ENETRESET;
222 }
223 break;
224 }
225 splx(s);
226 if (error != ENETRESET)
227 return error;
228 else if ((ifp->if_flags & IFF_RUNNING) != 0 &&
229 ifp->if_init != NULL)
230 return (*ifp->if_init)(ifp);
231 else
232 return 0;
233 default:
234 return ENOTTY;
235 }
236 }
237
238 static int
239 link_attach(struct socket *so, int proto)
240 {
241 sosetlock(so);
242 KASSERT(solocked(so));
243 return 0;
244 }
245
246 static void
247 link_detach(struct socket *so)
248 {
249 KASSERT(solocked(so));
250 sofree(so);
251 }
252
253 static int
254 link_accept(struct socket *so, struct mbuf *nam)
255 {
256 KASSERT(solocked(so));
257
258 return EOPNOTSUPP;
259 }
260
261 static int
262 link_bind(struct socket *so, struct mbuf *nam)
263 {
264 KASSERT(solocked(so));
265
266 return EOPNOTSUPP;
267 }
268
269 static int
270 link_listen(struct socket *so)
271 {
272 KASSERT(solocked(so));
273
274 return EOPNOTSUPP;
275 }
276
277 static int
278 link_disconnect(struct socket *so)
279 {
280 KASSERT(solocked(so));
281
282 return EOPNOTSUPP;
283 }
284
285 static int
286 link_shutdown(struct socket *so)
287 {
288 KASSERT(solocked(so));
289
290 return EOPNOTSUPP;
291 }
292
293 static int
294 link_abort(struct socket *so)
295 {
296 KASSERT(solocked(so));
297
298 return EOPNOTSUPP;
299 }
300
301 static int
302 link_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
303 {
304 return link_control(so, cmd, nam, ifp);
305 }
306
307 static int
308 link_stat(struct socket *so, struct stat *ub)
309 {
310 KASSERT(solocked(so));
311
312 return EOPNOTSUPP;
313 }
314
315 static int
316 link_peeraddr(struct socket *so, struct mbuf *nam)
317 {
318 KASSERT(solocked(so));
319
320 return EOPNOTSUPP;
321 }
322
323 static int
324 link_sockaddr(struct socket *so, struct mbuf *nam)
325 {
326 KASSERT(solocked(so));
327
328 return EOPNOTSUPP;
329 }
330
331 static int
332 link_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
333 struct mbuf *control, struct lwp *l)
334 {
335 KASSERT(req != PRU_ATTACH);
336 KASSERT(req != PRU_DETACH);
337 KASSERT(req != PRU_ACCEPT);
338 KASSERT(req != PRU_BIND);
339 KASSERT(req != PRU_LISTEN);
340 KASSERT(req != PRU_DISCONNECT);
341 KASSERT(req != PRU_SHUTDOWN);
342 KASSERT(req != PRU_ABORT);
343 KASSERT(req != PRU_CONTROL);
344 KASSERT(req != PRU_SENSE);
345 KASSERT(req != PRU_PEERADDR);
346 KASSERT(req != PRU_SOCKADDR);
347
348 return EOPNOTSUPP;
349 }
350
351 /* Compare the field at byte offsets [fieldstart, fieldend) in
352 * two memory regions, [l, l + llen) and [r, r + llen).
353 */
354 static inline int
355 submemcmp(const void *l, const void *r,
356 const uint_fast8_t llen, const uint_fast8_t rlen,
357 const uint_fast8_t fieldstart, const uint_fast8_t fieldend)
358 {
359 uint_fast8_t cmpend, minlen;
360 const uint8_t *lb = l, *rb = r;
361 int rc;
362
363 minlen = MIN(llen, rlen);
364
365 /* The field is missing from one region. The shorter region is the
366 * lesser region.
367 */
368 if (fieldstart >= minlen)
369 return llen - rlen;
370
371 /* Two empty, present fields are always equal. */
372 if (fieldstart > fieldend)
373 return 0;
374
375 cmpend = MIN(fieldend, minlen);
376
377 rc = memcmp(&lb[fieldstart], &rb[fieldstart], cmpend - fieldstart);
378
379 if (rc != 0)
380 return rc;
381 /* If one or both fields are truncated, then the shorter is the lesser
382 * field.
383 */
384 if (minlen < fieldend)
385 return llen - rlen;
386 /* Fields are full-length and equal. The fields are equal. */
387 return 0;
388 }
389
390 uint8_t
391 sockaddr_dl_measure(uint8_t namelen, uint8_t addrlen)
392 {
393 return offsetof(struct sockaddr_dl, sdl_data[namelen + addrlen]);
394 }
395
396 struct sockaddr *
397 sockaddr_dl_alloc(uint16_t ifindex, uint8_t type,
398 const void *name, uint8_t namelen, const void *addr, uint8_t addrlen,
399 int flags)
400 {
401 struct sockaddr *sa;
402 socklen_t len;
403
404 len = sockaddr_dl_measure(namelen, addrlen);
405 sa = sockaddr_alloc(AF_LINK, len, flags);
406
407 if (sa == NULL)
408 return NULL;
409
410 if (sockaddr_dl_init(satosdl(sa), len, ifindex, type, name, namelen,
411 addr, addrlen) == NULL) {
412 sockaddr_free(sa);
413 return NULL;
414 }
415
416 return sa;
417 }
418
419 struct sockaddr_dl *
420 sockaddr_dl_init(struct sockaddr_dl *sdl, socklen_t socklen, uint16_t ifindex,
421 uint8_t type, const void *name, uint8_t namelen, const void *addr,
422 uint8_t addrlen)
423 {
424 socklen_t len;
425
426 sdl->sdl_family = AF_LINK;
427 sdl->sdl_slen = 0;
428 len = sockaddr_dl_measure(namelen, addrlen);
429 if (len > socklen) {
430 sdl->sdl_len = socklen;
431 #ifdef DIAGNOSTIC
432 printf("%s: too long: %u > %u\n", __func__, (u_int)len,
433 (u_int)socklen);
434 #endif
435 return NULL;
436 }
437 sdl->sdl_len = len;
438 sdl->sdl_index = ifindex;
439 sdl->sdl_type = type;
440 memset(&sdl->sdl_data[0], 0, namelen + addrlen);
441 if (name != NULL) {
442 memcpy(&sdl->sdl_data[0], name, namelen);
443 sdl->sdl_nlen = namelen;
444 } else
445 sdl->sdl_nlen = 0;
446 if (addr != NULL) {
447 memcpy(&sdl->sdl_data[sdl->sdl_nlen], addr, addrlen);
448 sdl->sdl_alen = addrlen;
449 } else
450 sdl->sdl_alen = 0;
451 return sdl;
452 }
453
454 static int
455 sockaddr_dl_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
456 {
457 int rc;
458 const uint_fast8_t indexofs = offsetof(struct sockaddr_dl, sdl_index);
459 const uint_fast8_t nlenofs = offsetof(struct sockaddr_dl, sdl_nlen);
460 uint_fast8_t dataofs = offsetof(struct sockaddr_dl, sdl_data[0]);
461 const struct sockaddr_dl *sdl1, *sdl2;
462
463 sdl1 = satocsdl(sa1);
464 sdl2 = satocsdl(sa2);
465
466 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
467 indexofs, nlenofs);
468
469 if (rc != 0)
470 return rc;
471
472 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
473 dataofs, dataofs + MIN(sdl1->sdl_nlen, sdl2->sdl_nlen));
474
475 if (rc != 0)
476 return rc;
477
478 if (sdl1->sdl_nlen != sdl2->sdl_nlen)
479 return sdl1->sdl_nlen - sdl2->sdl_nlen;
480
481 dataofs += sdl1->sdl_nlen;
482
483 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
484 dataofs, dataofs + MIN(sdl1->sdl_alen, sdl2->sdl_alen));
485
486 if (rc != 0)
487 return rc;
488
489 if (sdl1->sdl_alen != sdl2->sdl_alen)
490 return sdl1->sdl_alen - sdl2->sdl_alen;
491
492 dataofs += sdl1->sdl_alen;
493
494 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
495 dataofs, dataofs + MIN(sdl1->sdl_slen, sdl2->sdl_slen));
496
497 if (sdl1->sdl_slen != sdl2->sdl_slen)
498 return sdl1->sdl_slen - sdl2->sdl_slen;
499
500 return sdl1->sdl_len - sdl2->sdl_len;
501 }
502
503 struct sockaddr_dl *
504 sockaddr_dl_setaddr(struct sockaddr_dl *sdl, socklen_t socklen,
505 const void *addr, uint8_t addrlen)
506 {
507 socklen_t len;
508
509 len = sockaddr_dl_measure(sdl->sdl_nlen, addrlen);
510 if (len > socklen) {
511 #ifdef DIAGNOSTIC
512 printf("%s: too long: %u > %u\n", __func__, (u_int)len,
513 (u_int)socklen);
514 #endif
515 return NULL;
516 }
517 memcpy(&sdl->sdl_data[sdl->sdl_nlen], addr, addrlen);
518 sdl->sdl_alen = addrlen;
519 sdl->sdl_len = len;
520 return sdl;
521 }
522