link_proto.c revision 1.21 1 /* $NetBSD: link_proto.c,v 1.21 2014/08/05 05:24:26 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.21 2014/08/05 05:24:26 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 *, struct lwp *);
55 static int link_listen(struct socket *, struct lwp *);
56 static int link_connect(struct socket *, struct mbuf *, struct lwp *);
57 static int link_disconnect(struct socket *);
58 static int link_shutdown(struct socket *);
59 static int link_abort(struct socket *);
60 static int link_ioctl(struct socket *, u_long, void *, struct ifnet *);
61 static int link_stat(struct socket *, struct stat *);
62 static int link_peeraddr(struct socket *, struct mbuf *);
63 static int link_sockaddr(struct socket *, struct mbuf *);
64 static int link_recvoob(struct socket *, struct mbuf *, int);
65 static int link_sendoob(struct socket *, struct mbuf *, struct mbuf *);
66 static int link_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
67 struct mbuf *, struct lwp *);
68 static void link_init(void);
69
70 /*
71 * Definitions of protocols supported in the link-layer domain.
72 */
73
74 DOMAIN_DEFINE(linkdomain); /* forward define and add to link set */
75
76 static const struct pr_usrreqs link_usrreqs = {
77 .pr_attach = link_attach,
78 .pr_detach = link_detach,
79 .pr_accept = link_accept,
80 .pr_bind = link_bind,
81 .pr_listen = link_listen,
82 .pr_connect = link_connect,
83 .pr_disconnect = link_disconnect,
84 .pr_shutdown = link_shutdown,
85 .pr_abort = link_abort,
86 .pr_ioctl = link_ioctl,
87 .pr_stat = link_stat,
88 .pr_peeraddr = link_peeraddr,
89 .pr_sockaddr = link_sockaddr,
90 .pr_recvoob = link_recvoob,
91 .pr_sendoob = link_sendoob,
92 .pr_generic = link_usrreq,
93 };
94
95 const struct protosw linksw[] = {
96 { .pr_type = SOCK_DGRAM,
97 .pr_domain = &linkdomain,
98 .pr_protocol = 0, /* XXX */
99 .pr_flags = PR_ATOMIC|PR_ADDR|PR_PURGEIF,
100 .pr_input = NULL,
101 .pr_ctlinput = NULL,
102 .pr_ctloutput = NULL,
103 .pr_usrreqs = &link_usrreqs,
104 .pr_init = link_init,
105 },
106 };
107
108 struct domain linkdomain = {
109 .dom_family = AF_LINK,
110 .dom_name = "link",
111 .dom_externalize = NULL,
112 .dom_dispose = NULL,
113 .dom_protosw = linksw,
114 .dom_protoswNPROTOSW = &linksw[__arraycount(linksw)],
115 .dom_sockaddr_cmp = sockaddr_dl_cmp
116 };
117
118 static void
119 link_init(void)
120 {
121 return;
122 }
123
124 static int
125 link_control(struct socket *so, unsigned long cmd, void *data,
126 struct ifnet *ifp)
127 {
128 int error, s;
129 bool isactive, mkactive;
130 struct if_laddrreq *iflr;
131 union {
132 struct sockaddr sa;
133 struct sockaddr_dl sdl;
134 struct sockaddr_storage ss;
135 } u;
136 struct ifaddr *ifa;
137 const struct sockaddr_dl *asdl, *nsdl;
138
139 switch (cmd) {
140 case SIOCALIFADDR:
141 case SIOCDLIFADDR:
142 case SIOCGLIFADDR:
143 iflr = data;
144
145 if (iflr->addr.ss_family != AF_LINK)
146 return EINVAL;
147
148 asdl = satocsdl(sstocsa(&iflr->addr));
149
150 if (asdl->sdl_alen != ifp->if_addrlen)
151 return EINVAL;
152
153 if (sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index,
154 ifp->if_type, ifp->if_xname, strlen(ifp->if_xname),
155 CLLADDR(asdl), asdl->sdl_alen) == NULL)
156 return EINVAL;
157
158 if ((iflr->flags & IFLR_PREFIX) == 0)
159 ;
160 else if (iflr->prefixlen != NBBY * ifp->if_addrlen)
161 return EINVAL; /* XXX match with prefix */
162
163 error = 0;
164
165 s = splnet();
166
167 IFADDR_FOREACH(ifa, ifp) {
168 if (sockaddr_cmp(&u.sa, ifa->ifa_addr) == 0)
169 break;
170 }
171
172 switch (cmd) {
173 case SIOCGLIFADDR:
174 if ((iflr->flags & IFLR_PREFIX) == 0) {
175 IFADDR_FOREACH(ifa, ifp) {
176 if (ifa->ifa_addr->sa_family == AF_LINK)
177 break;
178 }
179 }
180 if (ifa == NULL) {
181 error = EADDRNOTAVAIL;
182 break;
183 }
184
185 if (ifa == ifp->if_dl)
186 iflr->flags = IFLR_ACTIVE;
187 else
188 iflr->flags = 0;
189
190 if (ifa == ifp->if_hwdl)
191 iflr->flags |= IFLR_FACTORY;
192
193 sockaddr_copy(sstosa(&iflr->addr), sizeof(iflr->addr),
194 ifa->ifa_addr);
195
196 break;
197 case SIOCDLIFADDR:
198 if (ifa == NULL)
199 error = EADDRNOTAVAIL;
200 else if (ifa == ifp->if_dl || ifa == ifp->if_hwdl)
201 error = EBUSY;
202 else {
203 /* TBD routing socket */
204 rt_newaddrmsg(RTM_DELETE, ifa, 0, NULL);
205 ifa_remove(ifp, ifa);
206 }
207 break;
208 case SIOCALIFADDR:
209 if (ifa != NULL)
210 ;
211 else if ((ifa = if_dl_create(ifp, &nsdl)) == NULL) {
212 error = ENOMEM;
213 break;
214 } else {
215 sockaddr_copy(ifa->ifa_addr,
216 ifa->ifa_addr->sa_len, &u.sa);
217 ifa_insert(ifp, ifa);
218 rt_newaddrmsg(RTM_ADD, ifa, 0, NULL);
219 }
220
221 mkactive = (iflr->flags & IFLR_ACTIVE) != 0;
222 isactive = (ifa == ifp->if_dl);
223
224 if (!isactive && mkactive) {
225 if_activate_sadl(ifp, ifa, nsdl);
226 rt_newaddrmsg(RTM_CHANGE, ifa, 0, NULL);
227 error = ENETRESET;
228 }
229 break;
230 }
231 splx(s);
232 if (error != ENETRESET)
233 return error;
234 else if ((ifp->if_flags & IFF_RUNNING) != 0 &&
235 ifp->if_init != NULL)
236 return (*ifp->if_init)(ifp);
237 else
238 return 0;
239 default:
240 return ENOTTY;
241 }
242 }
243
244 static int
245 link_attach(struct socket *so, int proto)
246 {
247 sosetlock(so);
248 KASSERT(solocked(so));
249 return 0;
250 }
251
252 static void
253 link_detach(struct socket *so)
254 {
255 KASSERT(solocked(so));
256 sofree(so);
257 }
258
259 static int
260 link_accept(struct socket *so, struct mbuf *nam)
261 {
262 KASSERT(solocked(so));
263
264 return EOPNOTSUPP;
265 }
266
267 static int
268 link_bind(struct socket *so, struct mbuf *nam, struct lwp *l)
269 {
270 KASSERT(solocked(so));
271
272 return EOPNOTSUPP;
273 }
274
275 static int
276 link_listen(struct socket *so, struct lwp *l)
277 {
278 KASSERT(solocked(so));
279
280 return EOPNOTSUPP;
281 }
282
283 static int
284 link_connect(struct socket *so, struct mbuf *nam, struct lwp *l)
285 {
286 KASSERT(solocked(so));
287
288 return EOPNOTSUPP;
289 }
290
291 static int
292 link_disconnect(struct socket *so)
293 {
294 KASSERT(solocked(so));
295
296 return EOPNOTSUPP;
297 }
298
299 static int
300 link_shutdown(struct socket *so)
301 {
302 KASSERT(solocked(so));
303
304 return EOPNOTSUPP;
305 }
306
307 static int
308 link_abort(struct socket *so)
309 {
310 KASSERT(solocked(so));
311
312 return EOPNOTSUPP;
313 }
314
315 static int
316 link_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
317 {
318 return link_control(so, cmd, nam, ifp);
319 }
320
321 static int
322 link_stat(struct socket *so, struct stat *ub)
323 {
324 KASSERT(solocked(so));
325
326 return EOPNOTSUPP;
327 }
328
329 static int
330 link_peeraddr(struct socket *so, struct mbuf *nam)
331 {
332 KASSERT(solocked(so));
333
334 return EOPNOTSUPP;
335 }
336
337 static int
338 link_sockaddr(struct socket *so, struct mbuf *nam)
339 {
340 KASSERT(solocked(so));
341
342 return EOPNOTSUPP;
343 }
344
345 static int
346 link_recvoob(struct socket *so, struct mbuf *m, int flags)
347 {
348 KASSERT(solocked(so));
349
350 return EOPNOTSUPP;
351 }
352
353 static int
354 link_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
355 {
356 KASSERT(solocked(so));
357
358 return EOPNOTSUPP;
359 }
360
361 static int
362 link_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
363 struct mbuf *control, struct lwp *l)
364 {
365 KASSERT(req != PRU_ATTACH);
366 KASSERT(req != PRU_DETACH);
367 KASSERT(req != PRU_ACCEPT);
368 KASSERT(req != PRU_BIND);
369 KASSERT(req != PRU_LISTEN);
370 KASSERT(req != PRU_CONNECT);
371 KASSERT(req != PRU_DISCONNECT);
372 KASSERT(req != PRU_SHUTDOWN);
373 KASSERT(req != PRU_ABORT);
374 KASSERT(req != PRU_CONTROL);
375 KASSERT(req != PRU_SENSE);
376 KASSERT(req != PRU_PEERADDR);
377 KASSERT(req != PRU_SOCKADDR);
378 KASSERT(req != PRU_RCVOOB);
379 KASSERT(req != PRU_SENDOOB);
380
381 return EOPNOTSUPP;
382 }
383
384 /* Compare the field at byte offsets [fieldstart, fieldend) in
385 * two memory regions, [l, l + llen) and [r, r + llen).
386 */
387 static inline int
388 submemcmp(const void *l, const void *r,
389 const uint_fast8_t llen, const uint_fast8_t rlen,
390 const uint_fast8_t fieldstart, const uint_fast8_t fieldend)
391 {
392 uint_fast8_t cmpend, minlen;
393 const uint8_t *lb = l, *rb = r;
394 int rc;
395
396 minlen = MIN(llen, rlen);
397
398 /* The field is missing from one region. The shorter region is the
399 * lesser region.
400 */
401 if (fieldstart >= minlen)
402 return llen - rlen;
403
404 /* Two empty, present fields are always equal. */
405 if (fieldstart > fieldend)
406 return 0;
407
408 cmpend = MIN(fieldend, minlen);
409
410 rc = memcmp(&lb[fieldstart], &rb[fieldstart], cmpend - fieldstart);
411
412 if (rc != 0)
413 return rc;
414 /* If one or both fields are truncated, then the shorter is the lesser
415 * field.
416 */
417 if (minlen < fieldend)
418 return llen - rlen;
419 /* Fields are full-length and equal. The fields are equal. */
420 return 0;
421 }
422
423 uint8_t
424 sockaddr_dl_measure(uint8_t namelen, uint8_t addrlen)
425 {
426 return offsetof(struct sockaddr_dl, sdl_data[namelen + addrlen]);
427 }
428
429 struct sockaddr *
430 sockaddr_dl_alloc(uint16_t ifindex, uint8_t type,
431 const void *name, uint8_t namelen, const void *addr, uint8_t addrlen,
432 int flags)
433 {
434 struct sockaddr *sa;
435 socklen_t len;
436
437 len = sockaddr_dl_measure(namelen, addrlen);
438 sa = sockaddr_alloc(AF_LINK, len, flags);
439
440 if (sa == NULL)
441 return NULL;
442
443 if (sockaddr_dl_init(satosdl(sa), len, ifindex, type, name, namelen,
444 addr, addrlen) == NULL) {
445 sockaddr_free(sa);
446 return NULL;
447 }
448
449 return sa;
450 }
451
452 struct sockaddr_dl *
453 sockaddr_dl_init(struct sockaddr_dl *sdl, socklen_t socklen, uint16_t ifindex,
454 uint8_t type, const void *name, uint8_t namelen, const void *addr,
455 uint8_t addrlen)
456 {
457 socklen_t len;
458
459 sdl->sdl_family = AF_LINK;
460 sdl->sdl_slen = 0;
461 len = sockaddr_dl_measure(namelen, addrlen);
462 if (len > socklen) {
463 sdl->sdl_len = socklen;
464 #ifdef DIAGNOSTIC
465 printf("%s: too long: %u > %u\n", __func__, (u_int)len,
466 (u_int)socklen);
467 #endif
468 return NULL;
469 }
470 sdl->sdl_len = len;
471 sdl->sdl_index = ifindex;
472 sdl->sdl_type = type;
473 memset(&sdl->sdl_data[0], 0, namelen + addrlen);
474 if (name != NULL) {
475 memcpy(&sdl->sdl_data[0], name, namelen);
476 sdl->sdl_nlen = namelen;
477 } else
478 sdl->sdl_nlen = 0;
479 if (addr != NULL) {
480 memcpy(&sdl->sdl_data[sdl->sdl_nlen], addr, addrlen);
481 sdl->sdl_alen = addrlen;
482 } else
483 sdl->sdl_alen = 0;
484 return sdl;
485 }
486
487 static int
488 sockaddr_dl_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
489 {
490 int rc;
491 const uint_fast8_t indexofs = offsetof(struct sockaddr_dl, sdl_index);
492 const uint_fast8_t nlenofs = offsetof(struct sockaddr_dl, sdl_nlen);
493 uint_fast8_t dataofs = offsetof(struct sockaddr_dl, sdl_data[0]);
494 const struct sockaddr_dl *sdl1, *sdl2;
495
496 sdl1 = satocsdl(sa1);
497 sdl2 = satocsdl(sa2);
498
499 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
500 indexofs, nlenofs);
501
502 if (rc != 0)
503 return rc;
504
505 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
506 dataofs, dataofs + MIN(sdl1->sdl_nlen, sdl2->sdl_nlen));
507
508 if (rc != 0)
509 return rc;
510
511 if (sdl1->sdl_nlen != sdl2->sdl_nlen)
512 return sdl1->sdl_nlen - sdl2->sdl_nlen;
513
514 dataofs += sdl1->sdl_nlen;
515
516 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
517 dataofs, dataofs + MIN(sdl1->sdl_alen, sdl2->sdl_alen));
518
519 if (rc != 0)
520 return rc;
521
522 if (sdl1->sdl_alen != sdl2->sdl_alen)
523 return sdl1->sdl_alen - sdl2->sdl_alen;
524
525 dataofs += sdl1->sdl_alen;
526
527 rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
528 dataofs, dataofs + MIN(sdl1->sdl_slen, sdl2->sdl_slen));
529
530 if (sdl1->sdl_slen != sdl2->sdl_slen)
531 return sdl1->sdl_slen - sdl2->sdl_slen;
532
533 return sdl1->sdl_len - sdl2->sdl_len;
534 }
535
536 struct sockaddr_dl *
537 sockaddr_dl_setaddr(struct sockaddr_dl *sdl, socklen_t socklen,
538 const void *addr, uint8_t addrlen)
539 {
540 socklen_t len;
541
542 len = sockaddr_dl_measure(sdl->sdl_nlen, addrlen);
543 if (len > socklen) {
544 #ifdef DIAGNOSTIC
545 printf("%s: too long: %u > %u\n", __func__, (u_int)len,
546 (u_int)socklen);
547 #endif
548 return NULL;
549 }
550 memcpy(&sdl->sdl_data[sdl->sdl_nlen], addr, addrlen);
551 sdl->sdl_alen = addrlen;
552 sdl->sdl_len = len;
553 return sdl;
554 }
555