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.43 2006/09/02 06:44:59 christos 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.43 2006/09/02 06:44:59 christos 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 
   62 #include <machine/stdarg.h>
   63 
   64 struct sockaddr key_dst = { .sa_len = 2, .sa_family = PF_KEY, };
   65 struct sockaddr key_src = { .sa_len = 2, .sa_family = PF_KEY, };
   66 
   67 struct pfkeystat pfkeystat;
   68 
   69 static int key_receive __P((struct socket *, struct mbuf **, struct uio *,
   70         struct mbuf **, struct mbuf **, int *));
   71 
   72 static int key_sendup0 __P((struct rawcb *, struct mbuf *, int, int));
   73 
   74 static int
   75 key_receive(struct socket *so, struct mbuf **paddr, struct uio *uio,
   76         struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
   77 {
   78         struct rawcb *rp = sotorawcb(so);
   79         struct keycb *kp = (struct keycb *)rp;
   80         int error;
   81         int s;
   82 
   83         error = (*kp->kp_receive)(so, paddr, uio, mp0, controlp, flagsp);
   84 
   85         /*
   86          * now we might have enough receive buffer space.
   87          * pull packets from kp_queue as many as possible.
   88          */
   89         s = splsoftnet();
   90         while (/*CONSTCOND*/ 1) {
   91                 struct mbuf *m;
   92 
   93                 m = kp->kp_queue;
   94                 if (m == NULL || sbspace(&so->so_rcv) < m->m_pkthdr.len)
   95                         break;
   96                 kp->kp_queue = m->m_nextpkt;
   97                 m->m_nextpkt = NULL; /* safety */
   98                 if (key_sendup0(rp, m, 0, 1))
   99                         break;
  100         }
  101         splx(s);
  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                 kp = (struct keycb *)malloc(sizeof(*kp), M_PCB,
  124                     M_WAITOK|M_ZERO);
  125                 so->so_pcb = (caddr_t)kp;
  126                 kp->kp_receive = so->so_receive;
  127                 so->so_receive = key_receive;
  128         }
  129         if (req == PRU_DETACH && kp) {
  130                 int af = kp->kp_raw.rcb_proto.sp_protocol;
  131                 struct mbuf *n;
  132 
  133                 if (af == PF_KEY)
  134                         key_cb.key_count--;
  135                 key_cb.any_count--;
  136 
  137                 key_freereg(so);
  138 
  139                 while (kp->kp_queue) {
  140                         n = kp->kp_queue->m_nextpkt;
  141                         kp->kp_queue->m_nextpkt = NULL;
  142                         m_freem(kp->kp_queue);
  143                         kp->kp_queue = n;
  144                 }
  145         }
  146 
  147         error = raw_usrreq(so, req, m, nam, control, l);
  148         m = control = NULL;     /* reclaimed in raw_usrreq */
  149         kp = (struct keycb *)sotorawcb(so);
  150         if (req == PRU_ATTACH && kp) {
  151                 int af = kp->kp_raw.rcb_proto.sp_protocol;
  152                 if (error) {
  153                         pfkeystat.sockerr++;
  154                         free((caddr_t)kp, M_PCB);
  155                         so->so_pcb = (caddr_t) 0;
  156                         splx(s);
  157                         return (error);
  158                 }
  159 
  160                 kp->kp_promisc = kp->kp_registered = 0;
  161 
  162                 if (af == PF_KEY)
  163                         key_cb.key_count++;
  164                 key_cb.any_count++;
  165                 kp->kp_raw.rcb_laddr = &key_src;
  166                 kp->kp_raw.rcb_faddr = &key_dst;
  167                 soisconnected(so);
  168                 so->so_options |= SO_USELOOPBACK;
  169         }
  170         splx(s);
  171         return (error);
  172 }
  173 
  174 /*
  175  * key_output()
  176  */
  177 int
  178 key_output(struct mbuf *m, ...)
  179 {
  180         struct sadb_msg *msg;
  181         int len, error = 0;
  182         int s;
  183         struct socket *so;
  184         va_list ap;
  185 
  186         va_start(ap, m);
  187         so = va_arg(ap, struct socket *);
  188         va_end(ap);
  189 
  190         if (m == 0)
  191                 panic("key_output: NULL pointer was passed.");
  192 
  193         pfkeystat.out_total++;
  194         pfkeystat.out_bytes += m->m_pkthdr.len;
  195 
  196         len = m->m_pkthdr.len;
  197         if (len < sizeof(struct sadb_msg)) {
  198                 pfkeystat.out_tooshort++;
  199                 error = EINVAL;
  200                 goto end;
  201         }
  202 
  203         if (m->m_len < sizeof(struct sadb_msg)) {
  204                 if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
  205                         pfkeystat.out_nomem++;
  206                         error = ENOBUFS;
  207                         goto end;
  208                 }
  209         }
  210 
  211         if ((m->m_flags & M_PKTHDR) == 0)
  212                 panic("key_output: not M_PKTHDR ??");
  213 
  214         KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
  215 
  216         msg = mtod(m, struct sadb_msg *);
  217         pfkeystat.out_msgtype[msg->sadb_msg_type]++;
  218         if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
  219                 pfkeystat.out_invlen++;
  220                 error = EINVAL;
  221                 goto end;
  222         }
  223 
  224         /*XXX giant lock*/
  225         s = splsoftnet();
  226         error = key_parse(m, so);
  227         m = NULL;
  228         splx(s);
  229 end:
  230         if (m)
  231                 m_freem(m);
  232         return error;
  233 }
  234 
  235 /*
  236  * send message to the socket.
  237  */
  238 static int
  239 key_sendup0(rp, m, promisc, canwait)
  240         struct rawcb *rp;
  241         struct mbuf *m;
  242         int promisc;
  243         int canwait;
  244 {
  245         struct keycb *kp = (struct keycb *)rp;
  246         struct mbuf *n;
  247         int error = 0;
  248 
  249         if (promisc) {
  250                 struct sadb_msg *pmsg;
  251 
  252                 M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
  253                 if (m && m->m_len < sizeof(struct sadb_msg))
  254                         m = m_pullup(m, sizeof(struct sadb_msg));
  255                 if (!m) {
  256                         pfkeystat.in_nomem++;
  257                         return ENOBUFS;
  258                 }
  259                 m->m_pkthdr.len += sizeof(*pmsg);
  260 
  261                 pmsg = mtod(m, struct sadb_msg *);
  262                 bzero(pmsg, sizeof(*pmsg));
  263                 pmsg->sadb_msg_version = PF_KEY_V2;
  264                 pmsg->sadb_msg_type = SADB_X_PROMISC;
  265                 pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
  266                 /* pid and seq? */
  267 
  268                 pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
  269         }
  270 
  271         if (canwait) {
  272                 if (kp->kp_queue) {
  273                         for (n = kp->kp_queue; n && n->m_nextpkt;
  274                             n = n->m_nextpkt)
  275                                 ;
  276                         n->m_nextpkt = m;
  277                         m = kp->kp_queue;
  278                         kp->kp_queue = NULL;
  279                 } else
  280                         m->m_nextpkt = NULL;    /* just for safety */
  281         } else
  282                 m->m_nextpkt = NULL;
  283 
  284         for (; m && error == 0; m = n) {
  285                 n = m->m_nextpkt;
  286 
  287                 if (canwait &&
  288                     sbspace(&rp->rcb_socket->so_rcv) < m->m_pkthdr.len) {
  289                         error = EAGAIN;
  290                         goto recovery;
  291                 }
  292 
  293                 m->m_nextpkt = NULL;
  294 
  295                 if (!sbappendaddr(&rp->rcb_socket->so_rcv,
  296                     (struct sockaddr *)&key_src, m, NULL)) {
  297                         pfkeystat.in_nomem++;
  298                         error = ENOBUFS;
  299                         goto recovery;
  300                 } else {
  301                         sorwakeup(rp->rcb_socket);
  302                         error = 0;
  303                 }
  304         }
  305         return (error);
  306 
  307 recovery:
  308         if (kp->kp_queue) {
  309                 /*
  310                  * kp_queue != NULL implies !canwait.
  311                  */
  312                 KASSERT(!canwait);
  313                 KASSERT(m->m_nextpkt == NULL);
  314                 /*
  315                  * insert m to the head of queue, as normally mbuf on the queue
  316                  * is less important than others.
  317                  */
  318                 if (m) {
  319                         m->m_nextpkt = kp->kp_queue;
  320                         kp->kp_queue = m;
  321                 }
  322         } else {
  323                 /* recover the queue */
  324                 if (!m) {
  325                         /* first ENOBUFS case */
  326                         kp->kp_queue = n;
  327                 } else {
  328                         kp->kp_queue = m;
  329                         m->m_nextpkt = n;
  330                 }
  331         }
  332         return (error);
  333 }
  334 
  335 /* so can be NULL if target != KEY_SENDUP_ONE */
  336 int
  337 key_sendup_mbuf(so, m, target)
  338         struct socket *so;
  339         struct mbuf *m;
  340         int target;
  341 {
  342         struct mbuf *n;
  343         struct keycb *kp;
  344         int sendup;
  345         struct rawcb *rp;
  346         int error = 0;
  347         int canwait;
  348 
  349         if (m == NULL)
  350                 panic("key_sendup_mbuf: NULL pointer was passed.");
  351         if (so == NULL && target == KEY_SENDUP_ONE)
  352                 panic("key_sendup_mbuf: NULL pointer was passed.");
  353 
  354         canwait = target & KEY_SENDUP_CANWAIT;
  355         target &= ~KEY_SENDUP_CANWAIT;
  356 
  357         pfkeystat.in_total++;
  358         pfkeystat.in_bytes += m->m_pkthdr.len;
  359         if (m->m_len < sizeof(struct sadb_msg)) {
  360                 m = m_pullup(m, sizeof(struct sadb_msg));
  361                 if (m == NULL) {
  362                         pfkeystat.in_nomem++;
  363                         return ENOBUFS;
  364                 }
  365         }
  366         if (m->m_len >= sizeof(struct sadb_msg)) {
  367                 struct sadb_msg *msg;
  368                 msg = mtod(m, struct sadb_msg *);
  369                 pfkeystat.in_msgtype[msg->sadb_msg_type]++;
  370         }
  371 
  372         for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next)
  373         {
  374                 if (rp->rcb_proto.sp_family != PF_KEY)
  375                         continue;
  376                 if (rp->rcb_proto.sp_protocol &&
  377                     rp->rcb_proto.sp_protocol != PF_KEY_V2) {
  378                         continue;
  379                 }
  380 
  381                 kp = (struct keycb *)rp;
  382 
  383                 /*
  384                  * If you are in promiscuous mode, and when you get broadcasted
  385                  * reply, you'll get two PF_KEY messages.
  386                  * (based on pf_key@inner.net message on 14 Oct 1998)
  387                  */
  388                 if (((struct keycb *)rp)->kp_promisc) {
  389                         if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
  390                                 (void)key_sendup0(rp, n, 1, canwait);
  391                                 n = NULL;
  392                         }
  393                 }
  394 
  395                 /* the exact target will be processed later */
  396                 if (so && sotorawcb(so) == rp)
  397                         continue;
  398 
  399                 sendup = 0;
  400                 switch (target) {
  401                 case KEY_SENDUP_ONE:
  402                         /* the statement has no effect */
  403                         if (so && sotorawcb(so) == rp)
  404                                 sendup++;
  405                         break;
  406                 case KEY_SENDUP_ALL:
  407                         sendup++;
  408                         break;
  409                 case KEY_SENDUP_REGISTERED:
  410                         if (kp->kp_registered)
  411                                 sendup++;
  412                         break;
  413                 }
  414                 pfkeystat.in_msgtarget[target]++;
  415 
  416                 if (!sendup)
  417                         continue;
  418 
  419                 if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
  420                         m_freem(m);
  421                         pfkeystat.in_nomem++;
  422                         return ENOBUFS;
  423                 }
  424 
  425                 /*
  426                  * ignore error even if queue is full.  PF_KEY does not
  427                  * guarantee the delivery of the message.
  428                  * this is important when target == KEY_SENDUP_ALL.
  429                  */
  430                 key_sendup0(rp, n, 0, canwait);
  431 
  432                 n = NULL;
  433         }
  434 
  435         if (so) {
  436                 error = key_sendup0(sotorawcb(so), m, 0, canwait);
  437                 m = NULL;
  438         } else {
  439                 error = 0;
  440                 m_freem(m);
  441         }
  442         return error;
  443 }
  444 
  445 
  446 /*
  447  * Definitions of protocols supported in the KEY domain.
  448  */
  449 
  450 DOMAIN_DEFINE(keydomain);
  451 
  452 const struct protosw keysw[] = {
  453 { SOCK_RAW,     &keydomain,     PF_KEY_V2,      PR_ATOMIC|PR_ADDR,
  454   0,            key_output,     raw_ctlinput,   0,
  455   key_usrreq,
  456   raw_init,     0,              0,              0,
  457 }
  458 };
  459 
  460 struct domain keydomain = {
  461         .dom_family = PF_KEY,
  462         .dom_name = "key",
  463         .dom_init = key_init,
  464         .dom_protosw = keysw,
  465         .dom_protoswNPROTOSW = &keysw[sizeof(keysw)/sizeof(keysw[0])],
  466 };

Cache object: ee39d86313a7c2193ace5e6df755b1ee


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