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/bsd/net/ndrv.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 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
   26 /*
   27  *      @(#)ndrv.c      1.1 (MacOSX) 6/10/43
   28  * Justin Walker, 970604
   29  *   AF_NDRV support
   30  * 980130 - Cleanup, reorg, performance improvemements
   31  * 000816 - Removal of Y adapter cruft
   32  */
   33 
   34 /*
   35  * PF_NDRV allows raw access to a specified network device, directly
   36  *  with a socket.  Expected use involves a socket option to request
   37  *  protocol packets.  This lets ndrv_output() call dlil_output(), and
   38  *  lets DLIL find the proper recipient for incoming packets.
   39  *  The purpose here is for user-mode protocol implementation.
   40  * Note that "pure raw access" will still be accomplished with BPF.
   41  *
   42  * In addition to the former use, when combined with socket NKEs,
   43  * PF_NDRV permits a fairly flexible mechanism for implementing
   44  * strange protocol support.  One of the main ones will be the
   45  * BlueBox/Classic Shared IP Address support.
   46  */
   47 #include <mach/mach_types.h>
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/malloc.h>
   53 #include <sys/mbuf.h>
   54 #include <sys/protosw.h>
   55 #include <sys/domain.h>
   56 #include <sys/socket.h>
   57 #include <sys/socketvar.h>
   58 #include <sys/ioctl.h>
   59 #include <sys/errno.h>
   60 #include <sys/syslog.h>
   61 #include <sys/proc.h>
   62 
   63 #include <kern/queue.h>
   64 
   65 #include <net/ndrv.h>
   66 #include <net/netisr.h>
   67 #include <net/route.h>
   68 #include <net/if_llc.h>
   69 #include <net/if_dl.h>
   70 #include <net/if_types.h>
   71 #include <net/ndrv_var.h>
   72 
   73 #if INET
   74 #include <netinet/in.h>
   75 #include <netinet/in_var.h>
   76 #endif
   77 #include <netinet/if_ether.h>
   78 
   79 #include <machine/spl.h>
   80 
   81 int ndrv_do_detach(struct ndrv_cb *);
   82 int ndrv_do_disconnect(struct ndrv_cb *);
   83 struct ndrv_cb *ndrv_find_tag(unsigned int);
   84 void ndrv_read_event(struct socket* inSo, caddr_t ref, int waitf);
   85 int ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt);
   86 int ndrv_delspec(struct ndrv_cb *);
   87 int ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil);
   88 void ndrv_handle_ifp_detach(u_long family, short unit);
   89 static int ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt);
   90 static int ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt);
   91 static struct ndrv_multiaddr* ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* addr);
   92 static void ndrv_remove_all_multicast(struct ndrv_cb *np);
   93 
   94 unsigned long  ndrv_sendspace = NDRVSNDQ;
   95 unsigned long  ndrv_recvspace = NDRVRCVQ;
   96 struct ndrv_cb ndrvl;           /* Head of controlblock list */
   97 
   98 struct domain ndrvdomain;
   99 struct protosw ndrvsw;
  100 static struct socket* ndrv_so;
  101 
  102 
  103 /*
  104  * Protocol init function for NDRV protocol
  105  * Init the control block list.
  106  */
  107 void
  108 ndrv_init()
  109 {
  110     int retval;
  111     struct kev_request kev_request;
  112     
  113         ndrvl.nd_next = ndrvl.nd_prev = &ndrvl;
  114     
  115     /* Create a PF_SYSTEM socket so we can listen for events */
  116     retval = socreate(PF_SYSTEM, &ndrv_so, SOCK_RAW, SYSPROTO_EVENT);
  117     if (retval != 0 || ndrv_so == NULL)
  118         retval = KERN_FAILURE;
  119     
  120     /* Install a callback function for the socket */
  121     ndrv_so->so_rcv.sb_flags |= SB_NOTIFY|SB_UPCALL;
  122     ndrv_so->so_upcall = ndrv_read_event;
  123     ndrv_so->so_upcallarg = NULL;
  124     
  125     /* Configure the socket to receive the events we're interested in */
  126     kev_request.vendor_code = KEV_VENDOR_APPLE;
  127     kev_request.kev_class = KEV_NETWORK_CLASS;
  128     kev_request.kev_subclass = KEV_DL_SUBCLASS;
  129     retval = ndrv_so->so_proto->pr_usrreqs->pru_control(ndrv_so, SIOCSKEVFILT, (caddr_t)&kev_request, 0, 0);
  130     if (retval != 0)
  131     {
  132         /*
  133          * We will not get attaching or detaching events in this case.
  134          * We should probably prevent any sockets from binding so we won't
  135          * panic later if the interface goes away.
  136          */
  137         log(LOG_WARNING, "PF_NDRV: ndrv_init - failed to set event filter (%d)",
  138             retval);
  139     }
  140 }
  141 
  142 /*
  143  * Protocol output - Called to output a raw network packet directly
  144  *  to the driver.
  145  */
  146 int
  147 ndrv_output(register struct mbuf *m, register struct socket *so)
  148 {
  149     register struct ndrv_cb *np = sotondrvcb(so);
  150         register struct ifnet *ifp = np->nd_if;
  151         extern void kprintf(const char *, ...);
  152     int result = 0;
  153 
  154 #if NDRV_DEBUG
  155         kprintf("NDRV output: %x, %x, %x\n", m, so, np);
  156 #endif
  157 
  158         /*
  159          * No header is a format error
  160          */
  161         if ((m->m_flags&M_PKTHDR) == 0)
  162                 return(EINVAL);
  163 
  164         /*
  165      * Call DLIL if we can. DLIL is much safer than calling the
  166      * ifp directly.
  167      */
  168     if (np->nd_tag != 0)
  169         result = dlil_output(np->nd_tag, m, (caddr_t)NULL,
  170                             (struct sockaddr*)NULL, 1);
  171     else if (np->nd_send_tag != 0)
  172         result = dlil_output(np->nd_send_tag, m, (caddr_t)NULL,
  173                             (struct sockaddr*)NULL, 1);
  174     else
  175         result = ENXIO;
  176         return (result);
  177 }
  178 
  179 /* Our input routine called from DLIL */
  180 int
  181 ndrv_input(struct mbuf *m,
  182            char *frame_header,
  183            struct ifnet *ifp,
  184            u_long  dl_tag,
  185            int sync_ok)
  186 {
  187         struct socket *so;
  188         struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV};
  189         register struct ndrv_cb *np;
  190 
  191 
  192     /* move packet from if queue to socket */
  193         /* Should be media-independent */
  194     ndrvsrc.sdl_type = IFT_ETHER;
  195     ndrvsrc.sdl_nlen = 0;
  196     ndrvsrc.sdl_alen = 6;
  197     ndrvsrc.sdl_slen = 0;
  198     bcopy(frame_header, &ndrvsrc.sdl_data, 6);
  199 
  200         np = ndrv_find_tag(dl_tag);
  201         if (np == NULL)
  202         {
  203                 return(ENOENT);
  204         }
  205         so = np->nd_socket;
  206     /* prepend the frame header */
  207     m = m_prepend(m, ifp->if_data.ifi_hdrlen, M_NOWAIT);
  208     if (m == NULL)
  209         return EJUSTRETURN;
  210     bcopy(frame_header, m->m_data, ifp->if_data.ifi_hdrlen);
  211         if (sbappendaddr(&(so->so_rcv), (struct sockaddr *)&ndrvsrc,
  212                          m, (struct mbuf *)0) == 0)
  213         {
  214         /* yes, sbappendaddr returns zero if the sockbuff is full... */
  215         /* caller will free m */
  216                 return(ENOMEM);
  217         } else
  218                 sorwakeup(so);
  219         return(0);
  220 }
  221 
  222 int
  223 ndrv_control(struct socket *so, u_long cmd, caddr_t data,
  224                   struct ifnet *ifp, struct proc *p)
  225 {
  226         return (0);
  227 }
  228 
  229 /*
  230  * Allocate an ndrv control block and some buffer space for the socket
  231  */
  232 int
  233 ndrv_attach(struct socket *so, int proto, struct proc *p)
  234 {
  235     int error;
  236         register struct ndrv_cb *np = sotondrvcb(so);
  237 
  238         if ((so->so_state & SS_PRIV) == 0)
  239                 return(EPERM);
  240 
  241 #if NDRV_DEBUG
  242         kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
  243 #endif
  244 
  245         if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
  246                 return(error);
  247 
  248         MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK);
  249         if (np == NULL)
  250                 return (ENOMEM);
  251     so->so_pcb = (caddr_t)np;
  252     bzero(np, sizeof(*np));
  253 #if NDRV_DEBUG
  254         kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
  255 #endif
  256         TAILQ_INIT(&np->nd_dlist);
  257         np->nd_signature = NDRV_SIGNATURE;
  258         np->nd_socket = so;
  259         np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
  260         np->nd_proto.sp_protocol = proto;
  261     np->nd_if = NULL;
  262     np->nd_tag = 0;
  263     np->nd_family = 0;
  264     np->nd_unit = 0;
  265         insque((queue_t)np, (queue_t)&ndrvl);
  266         return(0);
  267 }
  268 
  269 /*
  270  * Destroy state just before socket deallocation.
  271  * Flush data or not depending on the options.
  272  */
  273 
  274 int
  275 ndrv_detach(struct socket *so)
  276 {
  277         register struct ndrv_cb *np = sotondrvcb(so);
  278 
  279         if (np == 0)
  280                 return EINVAL;
  281         return ndrv_do_detach(np);
  282 }
  283 
  284 
  285 /*
  286  * If a socket isn't bound to a single address,
  287  * the ndrv input routine will hand it anything
  288  * within that protocol family (assuming there's
  289  * nothing else around it should go to).
  290  *
  291  * Don't expect this to be used.
  292  */
  293 
  294 int ndrv_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
  295 {
  296         register struct ndrv_cb *np = sotondrvcb(so);
  297     int result = 0;
  298 
  299         if (np == 0)
  300                 return EINVAL;
  301 
  302         if (np->nd_faddr)
  303                 return EISCONN;
  304     
  305     /* Allocate memory to store the remote address */
  306     MALLOC(np->nd_faddr, struct sockaddr_ndrv*,
  307                 nam->sa_len, M_IFADDR, M_WAITOK);
  308     if (result != 0)
  309         return result;
  310     if (np->nd_faddr == NULL)
  311         return ENOMEM;
  312     
  313         bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, nam->sa_len);
  314         soisconnected(so);
  315         return 0;
  316 }
  317 
  318 /*
  319  * This is the "driver open" hook - we 'bind' to the
  320  *  named driver.
  321  * Here's where we latch onto the driver.
  322  */
  323 int
  324 ndrv_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
  325 {
  326     register struct sockaddr_ndrv *sa = (struct sockaddr_ndrv *) nam;
  327         register char *dname;
  328         register struct ndrv_cb *np;
  329         register struct ifnet *ifp;
  330         extern int name_cmp(struct ifnet *, char *);
  331     int result;
  332 
  333         if TAILQ_EMPTY(&ifnet)
  334                 return(EADDRNOTAVAIL); /* Quick sanity check */
  335         np = sotondrvcb(so);
  336         if (np == 0)
  337                 return EINVAL;
  338 
  339         if (np->nd_laddr)
  340                 return EINVAL;                  /* XXX */
  341 
  342         /* I think we just latch onto a copy here; the caller frees */
  343         np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK);
  344         if (np->nd_laddr == NULL)
  345                 return(ENOMEM);
  346         bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
  347         dname = sa->snd_name;
  348         if (*dname == '\0')
  349                 return(EINVAL);
  350 #if NDRV_DEBUG
  351         kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
  352 #endif
  353         /* Track down the driver and its ifnet structure.
  354          * There's no internal call for this so we have to dup the code
  355          *  in if.c/ifconf()
  356          */
  357         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  358                 if (name_cmp(ifp, dname) == 0)
  359                         break;
  360         }
  361 
  362         if (ifp == NULL)
  363                 return(EADDRNOTAVAIL);
  364     
  365     /* 
  366      * Loopback demuxing doesn't work with PF_NDRV.
  367      * The first 4 bytes of the packet must be the
  368      * protocol ptr. Can't get that from userland.
  369      */
  370     if (ifp->if_family == APPLE_IF_FAM_LOOPBACK)
  371         return (ENOTSUP);
  372     
  373     if ((dlil_find_dltag(ifp->if_family, ifp->if_unit,
  374                          PF_NDRV, &np->nd_send_tag) != 0) &&
  375         (ifp->if_family != APPLE_IF_FAM_PPP)) {
  376         /* NDRV isn't registered on this interface, lets change that */
  377         struct dlil_proto_reg_str       ndrv_proto;
  378         int     result = 0;
  379         bzero(&ndrv_proto, sizeof(ndrv_proto));
  380         TAILQ_INIT(&ndrv_proto.demux_desc_head);
  381         
  382         ndrv_proto.interface_family = ifp->if_family;
  383         ndrv_proto.protocol_family = PF_NDRV;
  384         ndrv_proto.unit_number = ifp->if_unit;
  385         
  386         result = dlil_attach_protocol(&ndrv_proto, &np->nd_send_tag);
  387         
  388         /*
  389          * If the interface does not allow PF_NDRV to attach, we will
  390          * respect it's wishes. Sending will be disabled. No error is
  391          * returned because the client may later attach a real protocol
  392          * that the interface may accept.
  393          */
  394         if (result != 0)
  395             np->nd_send_tag = 0;
  396     }
  397     
  398         np->nd_if = ifp;
  399     np->nd_family = ifp->if_family;
  400     np->nd_unit = ifp->if_unit;
  401     
  402         return(0);
  403 }
  404 
  405 int
  406 ndrv_disconnect(struct socket *so)
  407 {
  408         register struct ndrv_cb *np = sotondrvcb(so);
  409 
  410         if (np == 0)
  411                 return EINVAL;
  412 
  413         if (np->nd_faddr == 0)
  414                 return ENOTCONN;
  415 
  416         ndrv_do_disconnect(np);
  417         return 0;
  418 }
  419 
  420 /*
  421  * Accessor function
  422  */
  423 struct ifnet*
  424 ndrv_get_ifp(caddr_t ndrv_pcb)
  425 {
  426     struct ndrv_cb*     np = (struct ndrv_cb*)ndrv_pcb;
  427     
  428 #if DEBUG
  429     {
  430         struct ndrv_cb* temp = ndrvl.nd_next;
  431         /* Verify existence of pcb */
  432         for (temp = ndrvl.nd_next; temp != &ndrvl; temp = temp->nd_next)
  433         {
  434             if (temp == np)
  435                 break;
  436         }
  437         
  438         if (temp != np)
  439         {
  440             log(LOG_WARNING, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
  441             return NULL;
  442         }
  443     }
  444 #endif
  445     
  446     return np->nd_if;
  447 }
  448 
  449 /*
  450  * Mark the connection as being incapable of further input.
  451  */
  452 int
  453 ndrv_shutdown(struct socket *so)
  454 {
  455         socantsendmore(so);
  456         return 0;
  457 }
  458 
  459 /*
  460  * Ship a packet out.  The ndrv output will pass it
  461  *  to the appropriate driver.  The really tricky part
  462  *  is the destination address...
  463  */
  464 int
  465 ndrv_send(struct socket *so, int flags, struct mbuf *m,
  466           struct sockaddr *addr, struct mbuf *control,
  467           struct proc *p)
  468 {
  469         int error;
  470 
  471         if (control)
  472                 return EOPNOTSUPP;
  473 
  474         error = ndrv_output(m, so);
  475         m = NULL;
  476         return error;
  477 }
  478 
  479 
  480 int
  481 ndrv_abort(struct socket *so)
  482 {
  483         register struct ndrv_cb *np = sotondrvcb(so);
  484 
  485         if (np == 0)
  486                 return EINVAL;
  487 
  488         ndrv_do_disconnect(np);
  489         return 0;
  490 }
  491 
  492 int
  493 ndrv_sense(struct socket *so, struct stat *sb)
  494 {
  495         /*
  496          * stat: don't bother with a blocksize.
  497          */
  498         return (0);
  499 }
  500 
  501 int
  502 ndrv_sockaddr(struct socket *so, struct sockaddr **nam)
  503 {
  504         register struct ndrv_cb *np = sotondrvcb(so);
  505         int len;
  506 
  507         if (np == 0)
  508                 return EINVAL;
  509 
  510         if (np->nd_laddr == 0)
  511                 return EINVAL;
  512 
  513         len = np->nd_laddr->snd_len;
  514         bcopy((caddr_t)np->nd_laddr, *nam,
  515               (unsigned)len);
  516         return 0;
  517 }
  518 
  519 
  520 int
  521 ndrv_peeraddr(struct socket *so, struct sockaddr **nam)
  522 {
  523         register struct ndrv_cb *np = sotondrvcb(so);
  524         int len;
  525 
  526         if (np == 0)
  527                 return EINVAL;
  528 
  529         if (np->nd_faddr == 0)
  530                 return ENOTCONN;
  531 
  532         len = np->nd_faddr->snd_len;
  533         bcopy((caddr_t)np->nd_faddr, *nam,
  534               (unsigned)len);
  535         return 0;
  536 }
  537 
  538 
  539 /* Control input */
  540 
  541 void
  542 ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3)
  543 {
  544 }
  545 
  546 /* Control output */
  547 
  548 int
  549 ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
  550 {
  551     register struct ndrv_cb *np = sotondrvcb(so);
  552         int error = 0;
  553     
  554     switch(sopt->sopt_name)
  555     {
  556         case NDRV_DELDMXSPEC: /* Delete current spec */
  557             /* Verify no parameter was passed */
  558             if (sopt->sopt_val != NULL || sopt->sopt_valsize != 0) {
  559                 /*
  560                  * We don't support deleting a specific demux, it's
  561                  * all or nothing.
  562                  */
  563                 return EINVAL;
  564             }
  565             error = ndrv_delspec(np);
  566             break;
  567         case NDRV_SETDMXSPEC: /* Set protocol spec */
  568             error = ndrv_setspec(np, sopt);
  569             break;
  570         case NDRV_ADDMULTICAST:
  571             error = ndrv_do_add_multicast(np, sopt);
  572             break;
  573         case NDRV_DELMULTICAST:
  574             error = ndrv_do_remove_multicast(np, sopt);
  575             break;
  576         default:
  577             error = ENOTSUP;
  578     }
  579 #ifdef NDRV_DEBUG
  580         log(LOG_WARNING, "NDRV CTLOUT: %x returns %d\n", sopt->sopt_name,
  581             error);
  582 #endif
  583         return(error);
  584 }
  585 
  586 /* Drain the queues */
  587 void
  588 ndrv_drain()
  589 {
  590 }
  591 
  592 /* Sysctl hook for NDRV */
  593 int
  594 ndrv_sysctl()
  595 {
  596         return(0);
  597 }
  598 
  599 int
  600 ndrv_do_detach(register struct ndrv_cb *np)
  601 {
  602     struct ndrv_cb*     cur_np = NULL;
  603     struct socket *so = np->nd_socket;
  604     struct ndrv_multicast*      next;
  605     int error = 0;
  606 
  607 #if NDRV_DEBUG
  608         kprintf("NDRV detach: %x, %x\n", so, np);
  609 #endif
  610     ndrv_remove_all_multicast(np);
  611     
  612     if (np->nd_tag != 0)
  613     {
  614         error = dlil_detach_protocol(np->nd_tag);
  615         if (error)
  616         {
  617             log(LOG_WARNING, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
  618                 error, np->nd_tag);
  619             return error;
  620         }
  621     }
  622     
  623     /* Remove from the linked list of control blocks */
  624         remque((queue_t)np);
  625     
  626     if (np->nd_send_tag != 0)
  627     {
  628         /* Check if this is the last socket attached to this interface */
  629         for (cur_np = ndrvl.nd_next; cur_np != &ndrvl; cur_np = cur_np->nd_next)
  630         {
  631             if (cur_np->nd_family == np->nd_family &&
  632                 cur_np->nd_unit == np->nd_unit)
  633             {
  634                 break;
  635             }
  636         }
  637         
  638         /* If there are no other interfaces, detach PF_NDRV from the interface */
  639         if (cur_np == &ndrvl)
  640         {
  641             dlil_detach_protocol(np->nd_send_tag);
  642         }
  643     }
  644     
  645         FREE((caddr_t)np, M_PCB);
  646         so->so_pcb = 0;
  647         sofree(so);
  648         return error;
  649 }
  650 
  651 int
  652 ndrv_do_disconnect(register struct ndrv_cb *np)
  653 {
  654 #if NDRV_DEBUG
  655         kprintf("NDRV disconnect: %x\n", np);
  656 #endif
  657         if (np->nd_faddr)
  658         {
  659         FREE(np->nd_faddr, M_IFADDR);
  660                 np->nd_faddr = 0;
  661         }
  662         if (np->nd_socket->so_state & SS_NOFDREF)
  663                 ndrv_do_detach(np);
  664         soisdisconnected(np->nd_socket);
  665         return(0);
  666 }
  667 
  668 /*
  669  * Try to compare a device name (q) with one of the funky ifnet
  670  *  device names (ifp).
  671  */
  672 int name_cmp(register struct ifnet *ifp, register char *q)
  673 {       register char *r;
  674         register int len;
  675         char buf[IFNAMSIZ];
  676         static char *sprint_d();
  677 
  678         r = buf;
  679         len = strlen(ifp->if_name);
  680         strncpy(r, ifp->if_name, IFNAMSIZ);
  681         r += len;
  682         (void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
  683 #if NDRV_DEBUG
  684         kprintf("Comparing %s, %s\n", buf, q);
  685 #endif
  686         return(strncmp(buf, q, IFNAMSIZ));
  687 }
  688 
  689 /* Hackery - return a string version of a decimal number */
  690 static char *
  691 sprint_d(n, buf, buflen)
  692         u_int n;
  693         char *buf;
  694         int buflen;
  695 {       char dbuf[IFNAMSIZ];
  696         register char *cp = dbuf+IFNAMSIZ-1;
  697 
  698         *cp = 0;
  699         do {    buflen--;
  700                 cp--;
  701                 *cp = "0123456789"[n % 10];
  702                 n /= 10;
  703         } while (n != 0 && buflen > 0);
  704         strncpy(buf, cp, IFNAMSIZ-buflen);
  705         return (cp);
  706 }
  707 
  708 /*
  709  * When closing, dump any enqueued mbufs.
  710  */
  711 void
  712 ndrv_flushq(register struct ifqueue *q)
  713 {
  714     register struct mbuf *m;
  715         for (;;)
  716         {
  717                 IF_DEQUEUE(q, m);
  718                 if (m == NULL)
  719                         break;
  720                 IF_DROP(q);
  721                 if (m)
  722                         m_freem(m);
  723         }
  724 }
  725 
  726 int
  727 ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt)
  728 {
  729     struct dlil_proto_reg_str   dlilSpec;
  730     struct ndrv_protocol_desc   ndrvSpec;
  731     struct dlil_demux_desc*             dlilDemux = NULL;
  732     struct ndrv_demux_desc*             ndrvDemux = NULL;
  733     int                                                 error = 0;
  734     
  735     /* Sanity checking */
  736     if (np->nd_tag)
  737         return EBUSY;
  738     if (np->nd_if == NULL)
  739         return EINVAL;
  740     if (sopt->sopt_valsize != sizeof(struct ndrv_protocol_desc))
  741         return EINVAL;
  742     
  743     /* Copy the ndrvSpec */
  744     error = sooptcopyin(sopt, &ndrvSpec, sizeof(struct ndrv_protocol_desc),
  745                         sizeof(struct ndrv_protocol_desc));
  746     if (error != 0)
  747         return error;
  748     
  749     /* Verify the parameter */
  750     if (ndrvSpec.version > NDRV_PROTOCOL_DESC_VERS)
  751         return ENOTSUP; // version is too new!
  752     else if (ndrvSpec.version < 1)
  753         return EINVAL; // version is not valid
  754     
  755     /* Allocate storage for demux array */
  756     MALLOC(ndrvDemux, struct ndrv_demux_desc*,
  757             ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc), M_TEMP, M_WAITOK);
  758     if (ndrvDemux == NULL)
  759         return ENOMEM;
  760     
  761     /* Allocate enough dlil_demux_descs */
  762     MALLOC(dlilDemux, struct dlil_demux_desc*,
  763             sizeof(*dlilDemux) * ndrvSpec.demux_count, M_TEMP, M_WAITOK);
  764     if (dlilDemux == NULL)
  765         error = ENOMEM;
  766     
  767     if (error == 0)
  768     {
  769         /* Copy the ndrv demux array from userland */
  770         error = copyin(ndrvSpec.demux_list, ndrvDemux,
  771                     ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc));
  772         ndrvSpec.demux_list = ndrvDemux;
  773     }
  774     
  775     if (error == 0)
  776     {
  777         /* At this point, we've at least got enough bytes to start looking around */
  778         u_long  demuxOn = 0;
  779         
  780         bzero(&dlilSpec, sizeof(dlilSpec));
  781         TAILQ_INIT(&dlilSpec.demux_desc_head);
  782         dlilSpec.interface_family = np->nd_family;
  783         dlilSpec.unit_number = np->nd_unit;
  784         dlilSpec.input = ndrv_input;
  785         dlilSpec.protocol_family = ndrvSpec.protocol_family;
  786         
  787         for (demuxOn = 0; demuxOn < ndrvSpec.demux_count; demuxOn++)
  788         {
  789             /* Convert an ndrv_demux_desc to a dlil_demux_desc */
  790             error = ndrv_to_dlil_demux(&ndrvSpec.demux_list[demuxOn], &dlilDemux[demuxOn]);
  791             if (error)
  792                 break;
  793             
  794             /* Add the dlil_demux_desc to the list */
  795             TAILQ_INSERT_TAIL(&dlilSpec.demux_desc_head, &dlilDemux[demuxOn], next);
  796         }
  797     }
  798     
  799     if (error == 0)
  800     {
  801         /* We've got all our ducks lined up...lets attach! */
  802         error = dlil_attach_protocol(&dlilSpec, &np->nd_tag);
  803     }
  804     
  805     /* Free any memory we've allocated */
  806     if (dlilDemux)
  807         FREE(dlilDemux, M_TEMP);
  808     if (ndrvDemux)
  809         FREE(ndrvDemux, M_TEMP);
  810     
  811     return error;
  812 }
  813 
  814 
  815 int
  816 ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil)
  817 {
  818     bzero(dlil, sizeof(*dlil));
  819     
  820     if (ndrv->type < DLIL_DESC_ETYPE2)
  821     {
  822         /* using old "type", not supported */
  823         return ENOTSUP;
  824     }
  825     
  826     if (ndrv->length > 28)
  827     {
  828         return EINVAL;
  829     }
  830     
  831     dlil->type = ndrv->type;
  832     dlil->native_type = ndrv->data.other;
  833     dlil->variants.native_type_length = ndrv->length;
  834     
  835     return 0;
  836 }
  837 
  838 int
  839 ndrv_delspec(struct ndrv_cb *np)
  840 {
  841     int result = 0;
  842     
  843     if (np->nd_tag == 0)
  844         return EINVAL;
  845     
  846     /* Detach the protocol */
  847     result = dlil_detach_protocol(np->nd_tag);
  848     if (result == 0)
  849     {
  850         np->nd_tag = 0;
  851     }
  852     
  853         return result;
  854 }
  855 
  856 struct ndrv_cb *
  857 ndrv_find_tag(unsigned int tag)
  858 {
  859     struct ndrv_cb* np;
  860         int i;
  861     
  862     if (tag == 0)
  863         return NULL;
  864     
  865     for (np = ndrvl.nd_next; np != NULL; np = np->nd_next)
  866     {
  867         if (np->nd_tag == tag)
  868         {
  869             return np;
  870         }
  871     }
  872     
  873         return NULL;
  874 }
  875 
  876 void ndrv_dominit()
  877 {
  878         static int ndrv_dominited = 0;
  879 
  880         if (ndrv_dominited == 0 &&
  881             net_add_proto(&ndrvsw, &ndrvdomain) == 0)
  882                 ndrv_dominited = 1;
  883 }
  884 
  885 void
  886 ndrv_read_event(struct socket* so, caddr_t ref, int waitf)
  887 {
  888     // Read an event
  889     struct mbuf *m = NULL;
  890     struct kern_event_msg *msg;
  891     struct uio auio = {0};
  892     int result = 0;
  893     int flags = 0;
  894     
  895     // Get the data
  896     auio.uio_resid = 1000000; // large number to get all of the data
  897     flags = MSG_DONTWAIT;
  898     result = soreceive(so, (struct sockaddr**)NULL, &auio, &m,
  899         (struct mbuf**)NULL, &flags);
  900     if (result != 0 || m == NULL)
  901         return;
  902     
  903     // cast the mbuf to a kern_event_msg
  904     // this is dangerous, doesn't handle linked mbufs
  905     msg = mtod(m, struct kern_event_msg*);
  906     
  907     // check for detaches, assume even filtering is working
  908     if (msg->event_code == KEV_DL_IF_DETACHING ||
  909         msg->event_code == KEV_DL_IF_DETACHED)
  910     {
  911         struct net_event_data *ev_data;
  912         ev_data = (struct net_event_data*)msg->event_data;
  913         ndrv_handle_ifp_detach(ev_data->if_family, ev_data->if_unit);
  914     }
  915     
  916     m_free(m);
  917 }
  918 
  919 void
  920 ndrv_handle_ifp_detach(u_long family, short unit)
  921 {
  922     struct ndrv_cb* np;
  923     u_long                      dl_tag;
  924     
  925     /* Find all sockets using this interface. */
  926     for (np = ndrvl.nd_next; np != &ndrvl; np = np->nd_next)
  927     {
  928         if (np->nd_family == family &&
  929             np->nd_unit == unit)
  930         {
  931             /* This cb is using the detaching interface, but not for long. */
  932             /* Let the protocol go */
  933             if (np->nd_tag != 0)
  934                 ndrv_delspec(np);
  935             
  936             /* Delete the multicasts first */
  937             ndrv_remove_all_multicast(np);
  938             
  939             /* Disavow all knowledge of the ifp */
  940             np->nd_if = NULL;
  941             np->nd_unit = 0;
  942             np->nd_family = 0;
  943             np->nd_send_tag = 0;
  944             
  945             /* Make sure sending returns an error */
  946             /* Is this safe? Will we drop the funnel? */
  947             socantsendmore(np->nd_socket);
  948             socantrcvmore(np->nd_socket);
  949         }
  950     }
  951     
  952     /* Unregister our protocol */
  953     if (dlil_find_dltag(family, unit, PF_NDRV, &dl_tag) == 0) {
  954         dlil_detach_protocol(dl_tag);
  955     }
  956 }
  957 
  958 static int
  959 ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt)
  960 {
  961     struct ndrv_multiaddr*      ndrv_multi;
  962     int                                         result;
  963     
  964     if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
  965         sopt->sopt_level != SOL_NDRVPROTO)
  966         return EINVAL;
  967     if (np->nd_if == NULL)
  968         return ENXIO;
  969     
  970     // Allocate storage
  971     MALLOC(ndrv_multi, struct ndrv_multiaddr*, sizeof(struct ndrv_multiaddr) -
  972         sizeof(struct sockaddr) + sopt->sopt_valsize, M_IFADDR, M_WAITOK);
  973     if (ndrv_multi == NULL)
  974         return ENOMEM;
  975     
  976     // Copy in the address
  977     result = copyin(sopt->sopt_val, &ndrv_multi->addr, sopt->sopt_valsize);
  978     
  979     // Validate the sockaddr
  980     if (result == 0 && sopt->sopt_valsize != ndrv_multi->addr.sa_len)
  981         result = EINVAL;
  982     
  983     if (result == 0 && ndrv_have_multicast(np, &ndrv_multi->addr))
  984         result = EEXIST;
  985     
  986     if (result == 0)
  987     {
  988         // Try adding the multicast
  989         result = if_addmulti(np->nd_if, &ndrv_multi->addr, NULL);
  990     }
  991     
  992     if (result == 0)
  993     {
  994         // Add to our linked list
  995         ndrv_multi->next = np->nd_multiaddrs;
  996         np->nd_multiaddrs = ndrv_multi;
  997     }
  998     else
  999     {
 1000         // Free up the memory, something went wrong
 1001         FREE(ndrv_multi, M_IFADDR);
 1002     }
 1003     
 1004     return result;
 1005 }
 1006 
 1007 static int
 1008 ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
 1009 {
 1010     struct sockaddr*            multi_addr;
 1011     struct ndrv_multiaddr*      ndrv_entry = NULL;
 1012     int                                 result;
 1013     
 1014     if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
 1015         sopt->sopt_level != SOL_NDRVPROTO)
 1016         return EINVAL;
 1017     if (np->nd_if == NULL)
 1018         return ENXIO;
 1019     
 1020     // Allocate storage
 1021     MALLOC(multi_addr, struct sockaddr*, sopt->sopt_valsize,
 1022             M_TEMP, M_WAITOK);
 1023     if (multi_addr == NULL)
 1024         return ENOMEM;
 1025     
 1026     // Copy in the address
 1027     result = copyin(sopt->sopt_val, multi_addr, sopt->sopt_valsize);
 1028     
 1029     // Validate the sockaddr
 1030     if (result == 0 && sopt->sopt_valsize != multi_addr->sa_len)
 1031         result = EINVAL;
 1032     
 1033     if (result == 0)
 1034     {
 1035         /* Find the old entry */
 1036         ndrv_entry = ndrv_have_multicast(np, multi_addr);
 1037         
 1038         if (ndrv_entry == NULL)
 1039             result = ENOENT;
 1040     }
 1041     
 1042     if (result == 0)
 1043     {
 1044         // Try deleting the multicast
 1045         result = if_delmulti(np->nd_if, &ndrv_entry->addr);
 1046     }
 1047     
 1048     if (result == 0)
 1049     {
 1050         // Remove from our linked list
 1051         struct ndrv_multiaddr*  cur = np->nd_multiaddrs;
 1052         
 1053         if (cur == ndrv_entry)
 1054         {
 1055             np->nd_multiaddrs = cur->next;
 1056         }
 1057         else
 1058         {
 1059             for (cur = cur->next; cur != NULL; cur = cur->next)
 1060             {
 1061                 if (cur->next == ndrv_entry)
 1062                 {
 1063                     cur->next = cur->next->next;
 1064                     break;
 1065                 }
 1066             }
 1067         }
 1068         
 1069         // Free the memory
 1070         FREE(ndrv_entry, M_IFADDR);
 1071     }
 1072     FREE(multi_addr, M_TEMP);
 1073     
 1074     return result;
 1075 }
 1076 
 1077 static struct ndrv_multiaddr*
 1078 ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* inAddr)
 1079 {
 1080     struct ndrv_multiaddr*      cur;
 1081     for (cur = np->nd_multiaddrs; cur != NULL; cur = cur->next)
 1082     {
 1083         
 1084         if ((inAddr->sa_len == cur->addr.sa_len) &&
 1085             (bcmp(&cur->addr, inAddr, inAddr->sa_len) == 0))
 1086         {
 1087             // Found a match
 1088             return cur;
 1089         }
 1090     }
 1091     
 1092     return NULL;
 1093 }
 1094 
 1095 static void
 1096 ndrv_remove_all_multicast(struct ndrv_cb* np)
 1097 {
 1098     struct ndrv_multiaddr*      cur;
 1099     
 1100     if (np->nd_if != NULL)
 1101     {
 1102         while (np->nd_multiaddrs != NULL)
 1103         {
 1104             cur = np->nd_multiaddrs;
 1105             np->nd_multiaddrs = cur->next;
 1106             
 1107             if_delmulti(np->nd_if, &cur->addr);
 1108             FREE(cur, M_IFADDR);
 1109         }
 1110     }
 1111 }
 1112 
 1113 struct pr_usrreqs ndrv_usrreqs = {
 1114         ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind,
 1115         ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach,
 1116         ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp,
 1117         pru_rcvoob_notsupp, ndrv_send, ndrv_sense, ndrv_shutdown,
 1118         ndrv_sockaddr, sosend, soreceive, sopoll
 1119 };
 1120 
 1121 struct protosw ndrvsw =
 1122 {       SOCK_RAW, &ndrvdomain, NDRVPROTO_NDRV, PR_ATOMIC|PR_ADDR,
 1123     0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput,
 1124     0, ndrv_init, 0, 0,
 1125     ndrv_drain, ndrv_sysctl, &ndrv_usrreqs
 1126 };
 1127 
 1128 struct domain ndrvdomain =
 1129 {       AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
 1130         NULL,
 1131         NULL, NULL, 0, 0, 0, 0
 1132 };

Cache object: 0a177ebc9e796cac799b82eefcbbcaba


[ 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.