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