The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/link_proto.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: link_proto.c,v 1.40 2021/12/31 14:25:24 riastradh 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.40 2021/12/31 14:25:24 riastradh 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                                 KASSERTMSG(ifa->ifa_refcnt == 1, "ifa_refcnt=%d",
  224                                     ifa->ifa_refcnt);
  225                                 ifafree(ifa);
  226                                 ifa = NULL;
  227                         }
  228                         break;
  229                 case SIOCALIFADDR:
  230                         if (ifa == NULL) {
  231                                 ifa = if_dl_create(ifp, &nsdl);
  232                                 if (ifa == NULL) {
  233                                         error = ENOMEM;
  234                                         break;
  235                                 }
  236                                 ifa_acquire(ifa, &psref);
  237                                 sockaddr_copy(ifa->ifa_addr,
  238                                     ifa->ifa_addr->sa_len, &u.sa);
  239                                 ifa_insert(ifp, ifa);
  240                                 rt_addrmsg(RTM_ADD, ifa);
  241                         }
  242 
  243                         mkactive = (iflr->flags & IFLR_ACTIVE) != 0;
  244                         isactive = (ifa == ifp->if_dl);
  245 
  246                         if (!isactive && mkactive) {
  247                                 if_activate_sadl(ifp, ifa, nsdl);
  248                                 rt_addrmsg(RTM_CHANGE, ifa);
  249                                 error = ENETRESET;
  250                         }
  251                         break;
  252                 }
  253                 ifa_release(ifa, &psref);
  254                 if (error != ENETRESET)
  255                         return error;
  256                 else if ((ifp->if_flags & IFF_RUNNING) != 0 &&
  257                          ifp->if_init != NULL)
  258                         return if_init(ifp);
  259                 else
  260                         return 0;
  261         default:
  262                 return ENOTTY;
  263         }
  264 }
  265 
  266 static int
  267 link_attach(struct socket *so, int proto)
  268 {
  269         sosetlock(so);
  270         KASSERT(solocked(so));
  271         return 0;
  272 }
  273 
  274 static void
  275 link_detach(struct socket *so)
  276 {
  277         KASSERT(solocked(so));
  278         sofree(so);
  279 }
  280 
  281 static int
  282 link_accept(struct socket *so, struct sockaddr *nam)
  283 {
  284         KASSERT(solocked(so));
  285 
  286         return EOPNOTSUPP;
  287 }
  288 
  289 static int
  290 link_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
  291 {
  292         KASSERT(solocked(so));
  293 
  294         return EOPNOTSUPP;
  295 }
  296 
  297 static int
  298 link_listen(struct socket *so, struct lwp *l)
  299 {
  300         KASSERT(solocked(so));
  301 
  302         return EOPNOTSUPP;
  303 }
  304 
  305 static int
  306 link_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
  307 {
  308         KASSERT(solocked(so));
  309 
  310         return EOPNOTSUPP;
  311 }
  312 
  313 static int
  314 link_connect2(struct socket *so, struct socket *so2)
  315 {
  316         KASSERT(solocked(so));
  317 
  318         return EOPNOTSUPP;
  319 }
  320 
  321 static int
  322 link_disconnect(struct socket *so)
  323 {
  324         KASSERT(solocked(so));
  325 
  326         return EOPNOTSUPP;
  327 }
  328 
  329 static int
  330 link_shutdown(struct socket *so)
  331 {
  332         KASSERT(solocked(so));
  333 
  334         return EOPNOTSUPP;
  335 }
  336 
  337 static int
  338 link_abort(struct socket *so)
  339 {
  340         KASSERT(solocked(so));
  341 
  342         return EOPNOTSUPP;
  343 }
  344 
  345 static int
  346 link_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
  347 {
  348         return link_control(so, cmd, nam, ifp);
  349 }
  350 
  351 static int
  352 link_stat(struct socket *so, struct stat *ub)
  353 {
  354         KASSERT(solocked(so));
  355 
  356         return 0;
  357 }
  358 
  359 static int
  360 link_peeraddr(struct socket *so, struct sockaddr *nam)
  361 {
  362         KASSERT(solocked(so));
  363 
  364         return EOPNOTSUPP;
  365 }
  366 
  367 static int
  368 link_sockaddr(struct socket *so, struct sockaddr *nam)
  369 {
  370         KASSERT(solocked(so));
  371 
  372         return EOPNOTSUPP;
  373 }
  374 
  375 static int
  376 link_rcvd(struct socket *so, int flags, struct lwp *l)
  377 {
  378         KASSERT(solocked(so));
  379 
  380         return EOPNOTSUPP;
  381 }
  382 
  383 static int
  384 link_recvoob(struct socket *so, struct mbuf *m, int flags)
  385 {
  386         KASSERT(solocked(so));
  387 
  388         return EOPNOTSUPP;
  389 }
  390 
  391 static int
  392 link_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
  393     struct mbuf *control, struct lwp *l)
  394 {
  395         KASSERT(solocked(so));
  396 
  397         return EOPNOTSUPP;
  398 }
  399 
  400 static int
  401 link_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
  402 {
  403         KASSERT(solocked(so));
  404 
  405         m_freem(m);
  406         m_freem(control);
  407 
  408         return EOPNOTSUPP;
  409 }
  410 
  411 static int
  412 link_purgeif(struct socket *so, struct ifnet *ifp)
  413 {
  414 
  415         return EOPNOTSUPP;
  416 }
  417 
  418 /* Compare the field at byte offsets [fieldstart, fieldend) in
  419  * two memory regions, [l, l + llen) and [r, r + llen).
  420  */
  421 static inline int
  422 submemcmp(const void *l, const void *r,
  423     const uint_fast8_t llen, const uint_fast8_t rlen,
  424     const uint_fast8_t fieldstart, const uint_fast8_t fieldend)
  425 {
  426         uint_fast8_t cmpend, minlen;
  427         const uint8_t *lb = l, *rb = r;
  428         int rc;
  429 
  430         minlen = MIN(llen, rlen);
  431 
  432         /* The field is missing from one region.  The shorter region is the
  433          * lesser region.
  434          */
  435         if (fieldstart >= minlen)
  436                 return llen - rlen;
  437 
  438         /* Two empty, present fields are always equal. */
  439         if (fieldstart > fieldend)
  440                 return 0;
  441 
  442         cmpend = MIN(fieldend, minlen);
  443 
  444         rc = memcmp(&lb[fieldstart], &rb[fieldstart], cmpend - fieldstart);
  445 
  446         if (rc != 0)
  447                 return rc;
  448         /* If one or both fields are truncated, then the shorter is the lesser
  449          * field.
  450          */
  451         if (minlen < fieldend)
  452                 return llen - rlen;
  453         /* Fields are full-length and equal.  The fields are equal. */
  454         return 0;
  455 }
  456 
  457 uint8_t
  458 sockaddr_dl_measure(uint8_t namelen, uint8_t addrlen)
  459 {
  460         return offsetof(struct sockaddr_dl, sdl_data[namelen + addrlen]);
  461 }
  462 
  463 struct sockaddr *
  464 sockaddr_dl_alloc(uint16_t ifindex, uint8_t type,
  465     const void *name, uint8_t namelen, const void *addr, uint8_t addrlen,
  466     int flags)
  467 {
  468         struct sockaddr *sa;
  469         socklen_t len;
  470 
  471         len = sockaddr_dl_measure(namelen, addrlen);
  472         sa = sockaddr_alloc(AF_LINK, len, flags);
  473 
  474         if (sa == NULL)
  475                 return NULL;
  476 
  477         if (sockaddr_dl_init(satosdl(sa), len, ifindex, type, name, namelen,
  478             addr, addrlen) == NULL) {
  479                 sockaddr_free(sa);
  480                 return NULL;
  481         }
  482 
  483         return sa;
  484 }
  485 
  486 struct sockaddr_dl *
  487 sockaddr_dl_init(struct sockaddr_dl *sdl, socklen_t socklen, uint16_t ifindex,
  488     uint8_t type, const void *name, uint8_t namelen, const void *addr,
  489     uint8_t addrlen)
  490 {
  491         socklen_t len;
  492 
  493         sdl->sdl_family = AF_LINK;
  494         sdl->sdl_slen = 0;
  495         len = sockaddr_dl_measure(namelen, addrlen);
  496         if (len > socklen) {
  497                 sdl->sdl_len = socklen;
  498 #ifdef DIAGNOSTIC
  499                 printf("%s: too long: %u > %u\n", __func__, (u_int)len,
  500                     (u_int)socklen);
  501 #endif
  502                 return NULL;
  503         }
  504         sdl->sdl_len = len;
  505         sdl->sdl_index = ifindex;
  506         sdl->sdl_type = type;
  507         memset(&sdl->sdl_data[0], 0, namelen + addrlen);
  508         if (name != NULL) {
  509                 memcpy(&sdl->sdl_data[0], name, namelen);
  510                 sdl->sdl_nlen = namelen;
  511         } else
  512                 sdl->sdl_nlen = 0;
  513         if (addr != NULL) {
  514                 memcpy(&sdl->sdl_data[sdl->sdl_nlen], addr, addrlen);
  515                 sdl->sdl_alen = addrlen;
  516         } else
  517                 sdl->sdl_alen = 0;
  518         return sdl;
  519 }
  520 
  521 static int
  522 sockaddr_dl_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
  523 {
  524         int rc;
  525         const uint_fast8_t indexofs = offsetof(struct sockaddr_dl, sdl_index);
  526         const uint_fast8_t nlenofs = offsetof(struct sockaddr_dl, sdl_nlen);
  527         uint_fast8_t dataofs = offsetof(struct sockaddr_dl, sdl_data[0]);
  528         const struct sockaddr_dl *sdl1, *sdl2;
  529 
  530         sdl1 = satocsdl(sa1);
  531         sdl2 = satocsdl(sa2);
  532 
  533         rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
  534             indexofs, nlenofs);
  535 
  536         if (rc != 0)
  537                 return rc;
  538 
  539         rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
  540             dataofs, dataofs + MIN(sdl1->sdl_nlen, sdl2->sdl_nlen));
  541 
  542         if (rc != 0)
  543                 return rc;
  544 
  545         if (sdl1->sdl_nlen != sdl2->sdl_nlen)
  546                 return sdl1->sdl_nlen - sdl2->sdl_nlen;
  547 
  548         dataofs += sdl1->sdl_nlen;
  549 
  550         rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
  551             dataofs, dataofs + MIN(sdl1->sdl_alen, sdl2->sdl_alen));
  552 
  553         if (rc != 0)
  554                 return rc;
  555 
  556         if (sdl1->sdl_alen != sdl2->sdl_alen)
  557                 return sdl1->sdl_alen - sdl2->sdl_alen;
  558 
  559         dataofs += sdl1->sdl_alen;
  560 
  561         rc = submemcmp(sdl1, sdl2, sdl1->sdl_len, sdl2->sdl_len,
  562             dataofs, dataofs + MIN(sdl1->sdl_slen, sdl2->sdl_slen));
  563 
  564         if (sdl1->sdl_slen != sdl2->sdl_slen)
  565                 return sdl1->sdl_slen - sdl2->sdl_slen;
  566 
  567         return sdl1->sdl_len - sdl2->sdl_len;
  568 }
  569 
  570 struct sockaddr_dl *
  571 sockaddr_dl_setaddr(struct sockaddr_dl *sdl, socklen_t socklen,
  572     const void *addr, uint8_t addrlen)
  573 {
  574         socklen_t len;
  575 
  576         len = sockaddr_dl_measure(sdl->sdl_nlen, addrlen);
  577         if (len > socklen) {
  578 #ifdef DIAGNOSTIC
  579                 printf("%s: too long: %u > %u\n", __func__, (u_int)len,
  580                     (u_int)socklen);
  581 #endif
  582                 return NULL;
  583         }
  584         memcpy(&sdl->sdl_data[sdl->sdl_nlen], addr, addrlen);
  585         sdl->sdl_alen = addrlen;
  586         sdl->sdl_len = len;
  587         return sdl;
  588 }

Cache object: d0c805ad558b93d94b923fe5c277d607


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.