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/netkey/keysock.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: keysock.c,v 1.48.10.1 2009/11/15 06:01:49 snj Exp $    */
    2 /*      $KAME: keysock.c,v 1.32 2003/08/22 05:45:08 itojun Exp $        */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: keysock.c,v 1.48.10.1 2009/11/15 06:01:49 snj Exp $");
   35 
   36 #include "opt_inet.h"
   37 
   38 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/socket.h>
   45 #include <sys/socketvar.h>
   46 #include <sys/domain.h>
   47 #include <sys/protosw.h>
   48 #include <sys/errno.h>
   49 #include <sys/proc.h>
   50 #include <sys/queue.h>
   51 
   52 #include <net/raw_cb.h>
   53 #include <net/route.h>
   54 #include <netinet/in.h>
   55 
   56 #include <net/pfkeyv2.h>
   57 #include <netkey/keydb.h>
   58 #include <netkey/key.h>
   59 #include <netkey/keysock.h>
   60 #include <netkey/key_debug.h>
   61 #include <netkey/key_private.h>
   62 
   63 #include <machine/stdarg.h>
   64 
   65 struct sockaddr key_dst = { .sa_len = 2, .sa_family = PF_KEY, };
   66 struct sockaddr key_src = { .sa_len = 2, .sa_family = PF_KEY, };
   67 
   68 static int key_receive __P((struct socket *, struct mbuf **, struct uio *,
   69         struct mbuf **, struct mbuf **, int *));
   70 
   71 static int key_sendup0 __P((struct rawcb *, struct mbuf *, int, int));
   72 
   73 static int
   74 key_receive(struct socket *so, struct mbuf **paddr, struct uio *uio,
   75         struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
   76 {
   77         struct rawcb *rp = sotorawcb(so);
   78         struct keycb *kp = (struct keycb *)rp;
   79         int error;
   80 
   81         error = (*kp->kp_receive)(so, paddr, uio, mp0, controlp, flagsp);
   82 
   83         /*
   84          * now we might have enough receive buffer space.
   85          * pull packets from kp_queue as many as possible.
   86          */
   87         mutex_enter(softnet_lock);
   88         KERNEL_LOCK(1, NULL);
   89         while (/*CONSTCOND*/ 1) {
   90                 struct mbuf *m;
   91 
   92                 m = kp->kp_queue;
   93                 if (m == NULL || sbspace(&so->so_rcv) < m->m_pkthdr.len)
   94                         break;
   95                 kp->kp_queue = m->m_nextpkt;
   96                 m->m_nextpkt = NULL; /* safety */
   97                 if (key_sendup0(rp, m, 0, 1))
   98                         break;
   99         }
  100         KERNEL_UNLOCK_ONE(NULL);
  101         mutex_exit(softnet_lock);
  102 
  103         return error;
  104 }
  105 
  106 /*
  107  * key_usrreq()
  108  * derived from net/rtsock.c:route_usrreq()
  109  */
  110 int
  111 key_usrreq(so, req, m, nam, control, l)
  112         struct socket *so;
  113         int req;
  114         struct mbuf *m, *nam, *control;
  115         struct lwp *l;
  116 {
  117         int error = 0;
  118         struct keycb *kp = (struct keycb *)sotorawcb(so);
  119         int s;
  120 
  121         s = splsoftnet();
  122         if (req == PRU_ATTACH) {
  123                 sosetlock(so);
  124                 kp = (struct keycb *)malloc(sizeof(*kp), M_PCB,
  125                     M_WAITOK|M_ZERO);
  126                 so->so_pcb = (void *)kp;
  127                 kp->kp_receive = so->so_receive;
  128                 so->so_receive = key_receive;
  129         }
  130         if (req == PRU_DETACH && kp) {
  131                 int af = kp->kp_raw.rcb_proto.sp_protocol;
  132                 struct mbuf *n;
  133 
  134                 if (af == PF_KEY)
  135                         key_cb.key_count--;
  136                 key_cb.any_count--;
  137 
  138                 key_freereg(so);
  139 
  140                 while (kp->kp_queue) {
  141                         n = kp->kp_queue->m_nextpkt;
  142                         kp->kp_queue->m_nextpkt = NULL;
  143                         m_freem(kp->kp_queue);
  144                         kp->kp_queue = n;
  145                 }
  146         }
  147 
  148         error = raw_usrreq(so, req, m, nam, control, l);
  149         m = control = NULL;     /* reclaimed in raw_usrreq */
  150         kp = (struct keycb *)sotorawcb(so);
  151         if (req == PRU_ATTACH && kp) {
  152                 int af = kp->kp_raw.rcb_proto.sp_protocol;
  153                 if (error) {
  154                         PFKEY_STATINC(PFKEY_STAT_SOCKERR);
  155                         free((void *)kp, M_PCB);
  156                         so->so_pcb = (void *) 0;
  157                         splx(s);
  158                         return (error);
  159                 }
  160 
  161                 kp->kp_promisc = kp->kp_registered = 0;
  162 
  163                 if (af == PF_KEY)
  164                         key_cb.key_count++;
  165                 key_cb.any_count++;
  166                 kp->kp_raw.rcb_laddr = &key_src;
  167                 kp->kp_raw.rcb_faddr = &key_dst;
  168                 soisconnected(so);
  169                 so->so_options |= SO_USELOOPBACK;
  170         }
  171         splx(s);
  172         return (error);
  173 }
  174 
  175 /*
  176  * key_output()
  177  */
  178 int
  179 key_output(struct mbuf *m, ...)
  180 {
  181         struct sadb_msg *msg;
  182         int len, error = 0;
  183         int s;
  184         struct socket *so;
  185         va_list ap;
  186 
  187         va_start(ap, m);
  188         so = va_arg(ap, struct socket *);
  189         va_end(ap);
  190 
  191         if (m == 0)
  192                 panic("key_output: NULL pointer was passed.");
  193 
  194         {
  195                 uint64_t *ps = PFKEY_STAT_GETREF();
  196                 ps[PFKEY_STAT_OUT_TOTAL]++;
  197                 ps[PFKEY_STAT_OUT_BYTES] += m->m_pkthdr.len;
  198                 PFKEY_STAT_PUTREF();
  199         }
  200 
  201         len = m->m_pkthdr.len;
  202         if (len < sizeof(struct sadb_msg)) {
  203                 PFKEY_STATINC(PFKEY_STAT_OUT_TOOSHORT);
  204                 error = EINVAL;
  205                 goto end;
  206         }
  207 
  208         if (m->m_len < sizeof(struct sadb_msg)) {
  209                 if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
  210                         PFKEY_STATINC(PFKEY_STAT_OUT_NOMEM);
  211                         error = ENOBUFS;
  212                         goto end;
  213                 }
  214         }
  215 
  216         if ((m->m_flags & M_PKTHDR) == 0)
  217                 panic("key_output: not M_PKTHDR ??");
  218 
  219         KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
  220 
  221         msg = mtod(m, struct sadb_msg *);
  222         PFKEY_STATINC(PFKEY_STAT_OUT_MSGTYPE + msg->sadb_msg_type);
  223         if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
  224                 PFKEY_STATINC(PFKEY_STAT_OUT_INVLEN);
  225                 error = EINVAL;
  226                 goto end;
  227         }
  228 
  229         /*XXX giant lock*/
  230         s = splsoftnet();
  231         error = key_parse(m, so);
  232         m = NULL;
  233         splx(s);
  234 end:
  235         if (m)
  236                 m_freem(m);
  237         return error;
  238 }
  239 
  240 /*
  241  * send message to the socket.
  242  */
  243 static int
  244 key_sendup0(rp, m, promisc, canwait)
  245         struct rawcb *rp;
  246         struct mbuf *m;
  247         int promisc;
  248         int canwait;
  249 {
  250         struct keycb *kp = (struct keycb *)rp;
  251         struct mbuf *n;
  252         int error = 0;
  253 
  254         if (promisc) {
  255                 struct sadb_msg *pmsg;
  256 
  257                 M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
  258                 if (m && m->m_len < sizeof(struct sadb_msg))
  259                         m = m_pullup(m, sizeof(struct sadb_msg));
  260                 if (!m) {
  261                         PFKEY_STATINC(PFKEY_STAT_OUT_NOMEM);
  262                         return ENOBUFS;
  263                 }
  264                 m->m_pkthdr.len += sizeof(*pmsg);
  265 
  266                 pmsg = mtod(m, struct sadb_msg *);
  267                 bzero(pmsg, sizeof(*pmsg));
  268                 pmsg->sadb_msg_version = PF_KEY_V2;
  269                 pmsg->sadb_msg_type = SADB_X_PROMISC;
  270                 pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
  271                 /* pid and seq? */
  272 
  273                 PFKEY_STATINC(PFKEY_STAT_IN_MSGTYPE + pmsg->sadb_msg_type);
  274         }
  275 
  276         if (canwait) {
  277                 if (kp->kp_queue) {
  278                         for (n = kp->kp_queue; n && n->m_nextpkt;
  279                             n = n->m_nextpkt)
  280                                 ;
  281                         n->m_nextpkt = m;
  282                         m = kp->kp_queue;
  283                         kp->kp_queue = NULL;
  284                 } else
  285                         m->m_nextpkt = NULL;    /* just for safety */
  286         } else
  287                 m->m_nextpkt = NULL;
  288 
  289         for (; m && error == 0; m = n) {
  290                 n = m->m_nextpkt;
  291 
  292                 if (canwait &&
  293                     sbspace(&rp->rcb_socket->so_rcv) < m->m_pkthdr.len) {
  294                         error = EAGAIN;
  295                         goto recovery;
  296                 }
  297 
  298                 m->m_nextpkt = NULL;
  299 
  300                 if (!sbappendaddr(&rp->rcb_socket->so_rcv,
  301                     (struct sockaddr *)&key_src, m, NULL)) {
  302                         PFKEY_STATINC(PFKEY_STAT_IN_NOMEM);
  303                         error = ENOBUFS;
  304                         goto recovery;
  305                 } else {
  306                         sorwakeup(rp->rcb_socket);
  307                         error = 0;
  308                 }
  309         }
  310         return (error);
  311 
  312 recovery:
  313         if (kp->kp_queue) {
  314                 /*
  315                  * kp_queue != NULL implies !canwait.
  316                  */
  317                 KASSERT(!canwait);
  318                 KASSERT(m->m_nextpkt == NULL);
  319                 /*
  320                  * insert m to the head of queue, as normally mbuf on the queue
  321                  * is less important than others.
  322                  */
  323                 if (m) {
  324                         m->m_nextpkt = kp->kp_queue;
  325                         kp->kp_queue = m;
  326                 }
  327         } else {
  328                 /* recover the queue */
  329                 if (!m) {
  330                         /* first ENOBUFS case */
  331                         kp->kp_queue = n;
  332                 } else {
  333                         kp->kp_queue = m;
  334                         m->m_nextpkt = n;
  335                 }
  336         }
  337         return (error);
  338 }
  339 
  340 /* so can be NULL if target != KEY_SENDUP_ONE */
  341 int
  342 key_sendup_mbuf(so, m, target)
  343         struct socket *so;
  344         struct mbuf *m;
  345         int target;
  346 {
  347         struct mbuf *n;
  348         struct keycb *kp;
  349         int sendup;
  350         struct rawcb *rp;
  351         int error = 0;
  352         int canwait;
  353 
  354         if (m == NULL)
  355                 panic("key_sendup_mbuf: NULL pointer was passed.");
  356         if (so == NULL && target == KEY_SENDUP_ONE)
  357                 panic("key_sendup_mbuf: NULL pointer was passed.");
  358 
  359         canwait = target & KEY_SENDUP_CANWAIT;
  360         target &= ~KEY_SENDUP_CANWAIT;
  361 
  362         {
  363                 uint64_t *ps = PFKEY_STAT_GETREF();
  364                 ps[PFKEY_STAT_IN_TOTAL]++;
  365                 ps[PFKEY_STAT_IN_BYTES] += m->m_pkthdr.len;
  366                 PFKEY_STAT_PUTREF();
  367         }
  368         if (m->m_len < sizeof(struct sadb_msg)) {
  369                 m = m_pullup(m, sizeof(struct sadb_msg));
  370                 if (m == NULL) {
  371                         PFKEY_STATINC(PFKEY_STAT_IN_NOMEM);
  372                         return ENOBUFS;
  373                 }
  374         }
  375         if (m->m_len >= sizeof(struct sadb_msg)) {
  376                 struct sadb_msg *msg;
  377                 msg = mtod(m, struct sadb_msg *);
  378                 PFKEY_STATINC(PFKEY_STAT_IN_MSGTYPE + msg->sadb_msg_type);
  379         }
  380 
  381         for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next)
  382         {
  383                 if (rp->rcb_proto.sp_family != PF_KEY)
  384                         continue;
  385                 if (rp->rcb_proto.sp_protocol &&
  386                     rp->rcb_proto.sp_protocol != PF_KEY_V2) {
  387                         continue;
  388                 }
  389 
  390                 kp = (struct keycb *)rp;
  391 
  392                 /*
  393                  * If you are in promiscuous mode, and when you get broadcasted
  394                  * reply, you'll get two PF_KEY messages.
  395                  * (based on pf_key@inner.net message on 14 Oct 1998)
  396                  */
  397                 if (((struct keycb *)rp)->kp_promisc) {
  398                         if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
  399                                 (void)key_sendup0(rp, n, 1, canwait);
  400                                 n = NULL;
  401                         }
  402                 }
  403 
  404                 /* the exact target will be processed later */
  405                 if (so && sotorawcb(so) == rp)
  406                         continue;
  407 
  408                 sendup = 0;
  409                 switch (target) {
  410                 case KEY_SENDUP_ONE:
  411                         /* the statement has no effect */
  412                         if (so && sotorawcb(so) == rp)
  413                                 sendup++;
  414                         break;
  415                 case KEY_SENDUP_ALL:
  416                         sendup++;
  417                         break;
  418                 case KEY_SENDUP_REGISTERED:
  419                         if (kp->kp_registered)
  420                                 sendup++;
  421                         break;
  422                 }
  423                 PFKEY_STATINC(PFKEY_STAT_IN_MSGTARGET + target);
  424 
  425                 if (!sendup)
  426                         continue;
  427 
  428                 if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
  429                         m_freem(m);
  430                         PFKEY_STATINC(PFKEY_STAT_IN_NOMEM);
  431                         return ENOBUFS;
  432                 }
  433 
  434                 /*
  435                  * ignore error even if queue is full.  PF_KEY does not
  436                  * guarantee the delivery of the message.
  437                  * this is important when target == KEY_SENDUP_ALL.
  438                  */
  439                 key_sendup0(rp, n, 0, canwait);
  440 
  441                 n = NULL;
  442         }
  443 
  444         if (so) {
  445                 error = key_sendup0(sotorawcb(so), m, 0, canwait);
  446                 m = NULL;
  447         } else {
  448                 error = 0;
  449                 m_freem(m);
  450         }
  451         return error;
  452 }
  453 
  454 
  455 /*
  456  * Definitions of protocols supported in the KEY domain.
  457  */
  458 
  459 DOMAIN_DEFINE(keydomain);
  460 
  461 PR_WRAP_USRREQ(key_usrreq)
  462 
  463 #define key_usrreq      key_usrreq_wrapper
  464 
  465 const struct protosw keysw[] = {
  466 { .pr_type = SOCK_RAW,
  467   .pr_domain = &keydomain,
  468   .pr_protocol = PF_KEY_V2,
  469   .pr_flags = PR_ATOMIC|PR_ADDR,
  470   .pr_input = 0,
  471   .pr_output = key_output,
  472   .pr_ctlinput = raw_ctlinput,
  473   .pr_ctloutput = 0,
  474   .pr_usrreq = key_usrreq,
  475   .pr_init = raw_init,
  476   .pr_fasttimo = 0,
  477   .pr_slowtimo = 0,
  478   .pr_drain = 0,
  479 }
  480 };
  481 
  482 struct domain keydomain = {
  483         .dom_family = PF_KEY,
  484         .dom_name = "key",
  485         .dom_init = key_init,
  486         .dom_protosw = keysw,
  487         .dom_protoswNPROTOSW = &keysw[sizeof(keysw)/sizeof(keysw[0])],
  488 };

Cache object: d347983fc8c4c08780a775a1e43ab0bc


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