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/kern/kern_control.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) 1999 Apple Computer, Inc. */
   26 
   27 /*
   28  * NKE management domain - allows control connections to
   29  *  an NKE and to read/write data.
   30  *
   31  * Christophe Allie, 010928
   32  * Justin C. Walker, 990319
   33  */
   34 
   35 #include <sys/types.h>
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/syslog.h>
   39 #include <sys/socket.h>
   40 #include <sys/socketvar.h>
   41 #include <sys/protosw.h>
   42 #include <sys/domain.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mbuf.h>
   45 #include <net/kext_net.h>
   46 #include <sys/sys_domain.h>
   47 #include <sys/kern_event.h>
   48 #include <sys/kern_control.h>
   49 #include <net/if_var.h>
   50 
   51 #include <mach/vm_types.h>
   52 #include <mach/kmod.h>
   53 
   54 #include <kern/thread.h>
   55 
   56 
   57 /*
   58  * Definitions and vars for we support
   59  */
   60 
   61 #define CTL_SENDSIZE    (2 * 1024)      /* default buffer size */
   62 #define CTL_RECVSIZE    (8 * 1024)      /* default buffer size */
   63 
   64 /*
   65  internal structure maintained for each register controller 
   66 */
   67 struct ctl
   68 {
   69     TAILQ_ENTRY(ctl)    next;           /* controller chain */
   70     struct socket       *skt;           /* current controlling socket */
   71 
   72     /* controller information provided when registering */
   73     u_int32_t   id;                     /* unique nke identifier, provided by DTS */
   74     u_int32_t   unit;                   /* unit number for use by the nke */
   75     void        *userdata;              /* for private use by nke */
   76     
   77     /* misc communication information */
   78     u_int32_t   flags;                  /* support flags */
   79     u_int32_t   recvbufsize;            /* request more than the default buffer size */
   80     u_int32_t   sendbufsize;            /* request more than the default buffer size */
   81     
   82     /* Dispatch functions */
   83     int         (*connect)(kern_ctl_ref, void *);                       /* Make contact */
   84     void        (*disconnect)(kern_ctl_ref, void *);                    /* Break contact */
   85     int         (*write) (kern_ctl_ref, void *, struct mbuf *);         /* Send data to nke */
   86     int         (*set)(kern_ctl_ref, void *, int, void *, size_t );     /* set ctl configuration */
   87     int         (*get)(kern_ctl_ref, void *, int, void *, size_t *);    /* get ctl configuration */
   88 };
   89 
   90 
   91 /* all the controllers are chained */
   92 TAILQ_HEAD(, ctl)       ctl_head;
   93 
   94 int ctl_attach(struct socket *, int, struct proc *);
   95 int ctl_connect(struct socket *, struct sockaddr *, struct proc *);
   96 int ctl_disconnect(struct socket *);
   97 int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
   98                   struct ifnet *ifp, struct proc *p);
   99 int ctl_send(struct socket *, int, struct mbuf *,
  100             struct sockaddr *, struct mbuf *, struct proc *);
  101 int ctl_ctloutput(struct socket *, struct sockopt *);
  102 
  103 struct ctl *ctl_find(u_int32_t, u_int32_t unit);
  104 void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit);
  105 
  106 
  107 struct pr_usrreqs ctl_usrreqs =
  108 {
  109         pru_abort_notsupp, pru_accept_notsupp, ctl_attach, pru_bind_notsupp,
  110         ctl_connect, pru_connect2_notsupp, ctl_ioctl, pru_detach_notsupp,
  111         ctl_disconnect, pru_listen_notsupp, pru_peeraddr_notsupp,
  112         pru_rcvd_notsupp, pru_rcvoob_notsupp, ctl_send,
  113         pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp,
  114         sosend, soreceive, sopoll
  115 };
  116 
  117 struct protosw ctlsw =
  118 {
  119         SOCK_DGRAM, &systemdomain, SYSPROTO_CONTROL, PR_ATOMIC|PR_CONNREQUIRED,
  120         NULL, NULL, NULL, ctl_ctloutput,
  121         NULL, NULL,
  122         NULL, NULL, NULL, NULL, &ctl_usrreqs
  123 };
  124 
  125 /*
  126  * Install the protosw's for the NKE manager.
  127  */
  128 int
  129 kern_control_init(void)
  130 {
  131     int retval;
  132 
  133     retval = net_add_proto(&ctlsw, &systemdomain);
  134     if (retval) {
  135         log(LOG_WARNING, "Can't install Kernel Controller Manager (%d)\n", retval);
  136         return retval;
  137     }
  138 
  139     TAILQ_INIT(&ctl_head);
  140     
  141     return(KERN_SUCCESS);
  142 }
  143 
  144 
  145 /*
  146  * Kernel Controller user-request functions
  147  */
  148 int
  149 ctl_attach (struct socket *so, int proto, struct proc *p)
  150 {       
  151     /* 
  152      * attach function must exist and succeed 
  153      * detach not necessary since we use 
  154      * connect/disconnect to handle so_pcb
  155      */
  156     
  157     return 0;
  158 }
  159 
  160 int
  161 ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
  162 {       
  163     struct ctl          *ctl;
  164     int                 error = 0;
  165     struct sockaddr_ctl *sa = (struct sockaddr_ctl *)nam;
  166 
  167     ctl = ctl_find(sa->sc_id, sa->sc_unit);
  168     if (ctl == NULL)
  169         return(EADDRNOTAVAIL);
  170 
  171     if (ctl->flags & CTL_FLAG_PRIVILEGED) {
  172         if (p == 0)
  173             return(EINVAL);
  174         if (error = suser(p->p_ucred, &p->p_acflag))
  175             return error;
  176     }
  177 
  178     if (ctl->skt != NULL)
  179         return(EBUSY);
  180 
  181     error = soreserve(so, 
  182         ctl->sendbufsize ? ctl->sendbufsize : CTL_SENDSIZE,
  183         ctl->recvbufsize ? ctl->recvbufsize : CTL_RECVSIZE);
  184     if (error)
  185         return error;
  186     
  187     ctl->skt = so;
  188     
  189     if (ctl->connect)
  190         error = (*ctl->connect)(ctl, ctl->userdata);
  191     if (error) {
  192         ctl->skt = NULL;
  193         return error;
  194     }
  195     
  196     so->so_pcb = (caddr_t)ctl;
  197     soisconnected(so);
  198     
  199     return error;
  200 }
  201 
  202 int
  203 ctl_disconnect(struct socket *so)
  204 {
  205     struct ctl          *ctl;
  206 
  207     if ((ctl = (struct ctl *)so->so_pcb))
  208     {
  209         if (ctl->disconnect)
  210             (*ctl->disconnect)(ctl, ctl->userdata);
  211         ctl->skt = NULL;
  212         so->so_pcb = NULL;
  213         soisdisconnected(so);
  214     }
  215     return 0;
  216 }
  217 
  218 int
  219 ctl_send(struct socket *so, int flags, struct mbuf *m,
  220             struct sockaddr *addr, struct mbuf *control,
  221             struct proc *p)
  222 {
  223     struct ctl  *ctl = (struct ctl *)so->so_pcb;
  224     int         error = 0;
  225 
  226     if (ctl == NULL)
  227         return(ENOTCONN);
  228         
  229     if (ctl->write)
  230         error = (*ctl->write)(ctl, ctl->userdata, m);
  231     
  232     return error;
  233 }
  234 
  235 int
  236 ctl_enqueuembuf(void *ctlref, struct mbuf *m, u_int32_t flags)
  237 {
  238     struct ctl          *ctl = (struct ctl *)ctlref;
  239     struct socket       *so = (struct socket *)ctl->skt;
  240 
  241     if (ctl == NULL)    /* sanity check */
  242         return(EINVAL);
  243 
  244     if (so == NULL)
  245         return(ENOTCONN);
  246 
  247     if (sbspace(&so->so_rcv) < m->m_pkthdr.len)
  248         return(ENOBUFS);
  249 
  250     sbappend(&so->so_rcv, m);
  251     if ((flags & CTL_DATA_NOWAKEUP) == 0)
  252         sorwakeup(so);
  253     return 0;
  254 }
  255 
  256 int
  257 ctl_enqueuedata(void *ctlref, void *data, size_t len, u_int32_t flags)
  258 {
  259     struct ctl          *ctl = (struct ctl *)ctlref;
  260     struct socket       *so = (struct socket *)ctl->skt;
  261     struct mbuf         *m;
  262 
  263     if (ctl == NULL)    /* sanity check */
  264         return(EINVAL);
  265 
  266     if (so == NULL)
  267         return(ENOTCONN);
  268 
  269     if (len > MCLBYTES)
  270         return(EMSGSIZE);
  271 
  272     if (sbspace(&so->so_rcv) < len)
  273         return(ENOBUFS);
  274         
  275     if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
  276         return (ENOBUFS);
  277     
  278     if (len > MHLEN) {
  279         MCLGET(m, M_NOWAIT);
  280         if (!(m->m_flags & M_EXT)) {
  281             m_freem(m);
  282             return(ENOBUFS);
  283         }
  284     }
  285 
  286     bcopy(data, mtod(m, void *), len);
  287     m->m_pkthdr.len = m->m_len = len;
  288 
  289     sbappend(&so->so_rcv, m);
  290     if ((flags & CTL_DATA_NOWAKEUP) == 0)
  291         sorwakeup(so);
  292     return 0;
  293 }
  294 
  295 int
  296 ctl_ctloutput(struct socket *so, struct sockopt *sopt)
  297 {
  298     struct ctl  *ctl = (struct ctl *)so->so_pcb;
  299     int         error = 0, s;
  300     void        *data;
  301     size_t      len;
  302 
  303     if (sopt->sopt_level != SYSPROTO_CONTROL) {
  304         return(EINVAL);
  305     }
  306 
  307     if (ctl == NULL)
  308         return(ENOTCONN);
  309         
  310     switch (sopt->sopt_dir) {
  311         case SOPT_SET:
  312             if (ctl->set == NULL)
  313                 return(ENOTSUP);
  314             MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
  315             if (data == NULL)
  316                 return(ENOMEM);
  317             error = sooptcopyin(sopt, data, sopt->sopt_valsize, sopt->sopt_valsize);
  318             if (error == 0)
  319                 error = (*ctl->set)(ctl, ctl->userdata, sopt->sopt_name, data, sopt->sopt_valsize);
  320             FREE(data, M_TEMP);
  321             break;
  322 
  323         case SOPT_GET:
  324             if (ctl->get == NULL)
  325                 return(ENOTSUP);
  326             data = NULL;
  327             if (sopt->sopt_valsize && sopt->sopt_val) {
  328                 MALLOC(data, void *, sopt->sopt_valsize, M_TEMP, M_WAITOK);
  329                 if (data == NULL)
  330                     return(ENOMEM);
  331             }
  332             len = sopt->sopt_valsize;
  333             error = (*ctl->get)(ctl, ctl->userdata, sopt->sopt_name, data, &len);
  334             if (error == 0) {
  335                 if (data != NULL)
  336                     error = sooptcopyout(sopt, data, len);
  337                 else 
  338                     sopt->sopt_valsize = len;
  339             }
  340             if (data != NULL)
  341                 FREE(data, M_TEMP);                
  342             break;
  343     }
  344     return error;
  345 }
  346 
  347 int ctl_ioctl(struct socket *so, u_long cmd, caddr_t data,
  348                   struct ifnet *ifp, struct proc *p)
  349 {
  350     int         error = ENOTSUP, s, n;
  351     struct ctl  *ctl = (struct ctl *)so->so_pcb;
  352     
  353     switch (cmd) {
  354         /* get the number of controllers */
  355         case CTLIOCGCOUNT:
  356             n = 0;
  357             TAILQ_FOREACH(ctl, &ctl_head, next)
  358                 n++;
  359             *(u_int32_t *)data = n;
  360             error = 0;
  361             break;
  362         
  363 
  364         /* add controls to get list of NKEs */
  365 
  366     }
  367     
  368     return error;
  369 }
  370 
  371 /*
  372  * Register/unregister a NKE
  373  */
  374 int
  375 ctl_register(struct kern_ctl_reg *userctl, void *userdata, kern_ctl_ref *ctlref)
  376 {       
  377     struct ctl  *ctl;
  378 
  379     if (userctl == NULL)        /* sanity check */
  380         return(EINVAL);
  381 
  382     ctl = ctl_find(userctl->ctl_id, userctl->ctl_unit);
  383     if (ctl != NULL)
  384         return(EEXIST);
  385     
  386     MALLOC(ctl, struct ctl *, sizeof(*ctl), M_TEMP, M_WAITOK);
  387     if (ctl == NULL)
  388         return(ENOMEM);
  389         
  390     bzero((char *)ctl, sizeof(*ctl));
  391 
  392     ctl->id = userctl->ctl_id;
  393     ctl->unit = userctl->ctl_unit;
  394     ctl->flags = userctl->ctl_flags;
  395     ctl->sendbufsize = userctl->ctl_sendsize;
  396     ctl->recvbufsize = userctl->ctl_recvsize;
  397     ctl->userdata = userdata;
  398     ctl->connect = userctl->ctl_connect;
  399     ctl->disconnect = userctl->ctl_disconnect;
  400     ctl->write = userctl->ctl_write;
  401     ctl->set = userctl->ctl_set;
  402     ctl->get = userctl->ctl_get;
  403 
  404     TAILQ_INSERT_TAIL(&ctl_head, ctl, next);
  405     
  406     *ctlref = ctl;
  407 
  408     ctl_post_msg(KEV_CTL_REGISTERED, ctl->id, ctl->unit);
  409     return(0);
  410 }
  411 
  412 int
  413 ctl_deregister(void *ctlref)
  414 {       
  415     struct ctl          *ctl = (struct ctl *)ctlref;
  416     struct socket       *so;
  417 
  418     if (ctl == NULL)    /* sanity check */
  419         return(EINVAL);
  420 
  421     TAILQ_REMOVE(&ctl_head, ctl, next);
  422 
  423     if (ctl->skt) {
  424         ctl->skt->so_pcb = 0;
  425         soisdisconnected(ctl->skt);
  426     }
  427     
  428     ctl_post_msg(KEV_CTL_DEREGISTERED, ctl->id, ctl->unit);
  429     FREE(ctl, M_TEMP);
  430     return(0);
  431 }
  432 
  433 /*
  434  * Locate a NKE
  435  */
  436 struct ctl *
  437 ctl_find(u_int32_t id, u_int32_t unit)
  438 {       
  439     struct ctl  *ctl;
  440 
  441     TAILQ_FOREACH(ctl, &ctl_head, next)
  442         if ((ctl->id == id) && (ctl->unit == unit))
  443             return ctl;
  444 
  445     return NULL;
  446 }
  447 
  448 void ctl_post_msg(u_long event_code, u_int32_t id, u_int32_t unit) 
  449 {
  450     struct ctl_event_data       ctl_ev_data;
  451     struct kev_msg              ev_msg;
  452     
  453     ev_msg.vendor_code    = KEV_VENDOR_APPLE;
  454     
  455     ev_msg.kev_class      = KEV_SYSTEM_CLASS;
  456     ev_msg.kev_subclass   = KEV_CTL_SUBCLASS;
  457     ev_msg.event_code     = event_code;    
  458         
  459     /* common nke subclass data */
  460     bzero(&ctl_ev_data, sizeof(ctl_ev_data));
  461     ctl_ev_data.ctl_id = id;
  462     ctl_ev_data.ctl_unit = unit;
  463     ev_msg.dv[0].data_ptr    = &ctl_ev_data;    
  464     ev_msg.dv[0].data_length = sizeof(ctl_ev_data);
  465 
  466     ev_msg.dv[1].data_length = 0;
  467 
  468     kev_post_msg(&ev_msg);
  469 }
  470 

Cache object: aa6af3eac86e5ac68c8655a714c22be1


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