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/netipsec/subr_ipsec.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) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include "opt_inet.h"
   28 #include "opt_inet6.h"
   29 #include "opt_ipsec.h"
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/lock.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/module.h>
   41 #include <sys/priv.h>
   42 #include <sys/socket.h>
   43 #include <sys/sockopt.h>
   44 #include <sys/syslog.h>
   45 #include <sys/proc.h>
   46 
   47 #include <netinet/in.h>
   48 #include <netinet/in_pcb.h>
   49 #include <netinet/ip.h>
   50 #include <netinet/ip6.h>
   51 
   52 #include <netipsec/ipsec_support.h>
   53 #include <netipsec/ipsec.h>
   54 #include <netipsec/ipsec6.h>
   55 #include <netipsec/key.h>
   56 #include <netipsec/key_debug.h>
   57 
   58 #include <machine/atomic.h>
   59 /*
   60  * This file is build in the kernel only when 'options IPSEC' or
   61  * 'options IPSEC_SUPPORT' is enabled.
   62  */
   63 
   64 #ifdef INET
   65 void
   66 ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
   67     union sockaddr_union *dst)
   68 {
   69         static const struct sockaddr_in template = {
   70                 sizeof (struct sockaddr_in),
   71                 AF_INET,
   72                 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
   73         };
   74 
   75         src->sin = template;
   76         dst->sin = template;
   77 
   78         if (m->m_len < sizeof (struct ip)) {
   79                 m_copydata(m, offsetof(struct ip, ip_src),
   80                            sizeof (struct  in_addr),
   81                            (caddr_t) &src->sin.sin_addr);
   82                 m_copydata(m, offsetof(struct ip, ip_dst),
   83                            sizeof (struct  in_addr),
   84                            (caddr_t) &dst->sin.sin_addr);
   85         } else {
   86                 const struct ip *ip = mtod(m, const struct ip *);
   87                 src->sin.sin_addr = ip->ip_src;
   88                 dst->sin.sin_addr = ip->ip_dst;
   89         }
   90 }
   91 #endif
   92 #ifdef INET6
   93 void
   94 ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
   95     union sockaddr_union *dst)
   96 {
   97         struct ip6_hdr ip6buf;
   98         const struct ip6_hdr *ip6;
   99 
  100         if (m->m_len >= sizeof(*ip6))
  101                 ip6 = mtod(m, const struct ip6_hdr *);
  102         else {
  103                 m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
  104                 ip6 = &ip6buf;
  105         }
  106 
  107         bzero(&src->sin6, sizeof(struct sockaddr_in6));
  108         src->sin6.sin6_family = AF_INET6;
  109         src->sin6.sin6_len = sizeof(struct sockaddr_in6);
  110         bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
  111         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
  112                 src->sin6.sin6_addr.s6_addr16[1] = 0;
  113                 src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
  114         }
  115 
  116         bzero(&dst->sin6, sizeof(struct sockaddr_in6));
  117         dst->sin6.sin6_family = AF_INET6;
  118         dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
  119         bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
  120         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
  121                 dst->sin6.sin6_addr.s6_addr16[1] = 0;
  122                 dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
  123         }
  124 }
  125 #endif
  126 
  127 #ifdef IPSEC_SUPPORT
  128 /*
  129  * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
  130  * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
  131  * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
  132  *   IPSEC_SUPPORT.
  133  */
  134 #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
  135 #define IPSEC_MODULE_INCR       2
  136 static int
  137 ipsec_kmod_enter(volatile u_int *cntr)
  138 {
  139         u_int old, new;
  140 
  141         do {
  142                 old = *cntr;
  143                 if ((old & IPSEC_MODULE_ENABLED) == 0)
  144                         return (ENXIO);
  145                 new = old + IPSEC_MODULE_INCR;
  146         } while(atomic_cmpset_acq_int(cntr, old, new) == 0);
  147         return (0);
  148 }
  149 
  150 static void
  151 ipsec_kmod_exit(volatile u_int *cntr)
  152 {
  153         u_int old, new;
  154 
  155         do {
  156                 old = *cntr;
  157                 new = old - IPSEC_MODULE_INCR;
  158         } while (atomic_cmpset_rel_int(cntr, old, new) == 0);
  159 }
  160 
  161 static void
  162 ipsec_kmod_drain(volatile u_int *cntr)
  163 {
  164         u_int old, new;
  165 
  166         do {
  167                 old = *cntr;
  168                 new = old & ~IPSEC_MODULE_ENABLED;
  169         } while (atomic_cmpset_acq_int(cntr, old, new) == 0);
  170         while (atomic_cmpset_int(cntr, 0, 0) == 0)
  171                 pause("ipsecd", hz/2);
  172 }
  173 
  174 #define METHOD_DECL(...)        __VA_ARGS__
  175 #define METHOD_ARGS(...)        __VA_ARGS__
  176 #define IPSEC_KMOD_METHOD(type, name, sc, method, decl, args)           \
  177 type name (decl)                                                        \
  178 {                                                                       \
  179         type ret = (type)ipsec_kmod_enter(&sc->enabled);                \
  180         if (ret == 0) {                                                 \
  181                 ret = (*sc->methods->method)(args);                     \
  182                 ipsec_kmod_exit(&sc->enabled);                          \
  183         }                                                               \
  184         return (ret);                                                   \
  185 }
  186 
  187 static int
  188 ipsec_support_modevent(module_t mod, int type, void *data)
  189 {
  190 
  191         switch (type) {
  192         case MOD_LOAD:
  193                 return (0);
  194         case MOD_UNLOAD:
  195                 return (EBUSY);
  196         default:
  197                 return (EOPNOTSUPP);
  198         }
  199 }
  200 
  201 static moduledata_t ipsec_support_mod = {
  202         "ipsec_support",
  203         ipsec_support_modevent,
  204         0
  205 };
  206 DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
  207     SI_ORDER_ANY);
  208 MODULE_VERSION(ipsec_support, 1);
  209 #endif /* !IPSEC || !TCP_SIGNATURE */
  210 
  211 #ifndef TCP_SIGNATURE
  212 /* Declare TCP-MD5 support as kernel module. */
  213 static struct tcpmd5_support tcpmd5_ipsec = {
  214         .enabled = 0,
  215         .methods = NULL
  216 };
  217 struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
  218 
  219 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
  220     input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
  221         struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
  222 )
  223 
  224 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
  225     output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
  226         struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
  227 )
  228 
  229 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
  230     pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
  231         struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  232 )
  233 
  234 void
  235 tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
  236 {
  237 
  238         KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
  239         tcp_ipsec_support->methods = methods;
  240         tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
  241 }
  242 
  243 void
  244 tcpmd5_support_disable(void)
  245 {
  246 
  247         if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
  248                 ipsec_kmod_drain(&tcp_ipsec_support->enabled);
  249                 tcp_ipsec_support->methods = NULL;
  250         }
  251 }
  252 #endif /* !TCP_SIGNATURE */
  253 
  254 #ifndef IPSEC
  255 /*
  256  * IPsec support is build as kernel module.
  257  */
  258 #ifdef INET
  259 static struct ipsec_support ipv4_ipsec = {
  260         .enabled = 0,
  261         .methods = NULL
  262 };
  263 struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
  264 
  265 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
  266     udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  267         int off, int af), METHOD_ARGS(m, off, af)
  268 )
  269 
  270 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
  271     udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
  272         struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  273 )
  274 #endif
  275 
  276 #ifdef INET6
  277 static struct ipsec_support ipv6_ipsec = {
  278         .enabled = 0,
  279         .methods = NULL
  280 };
  281 struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
  282 #endif
  283 
  284 IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
  285     input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  286         int offset, int proto), METHOD_ARGS(m, offset, proto)
  287 )
  288 
  289 IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
  290     check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  291         struct inpcb *inp), METHOD_ARGS(m, inp)
  292 )
  293 
  294 IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
  295     forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
  296     (m)
  297 )
  298 
  299 IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
  300     output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  301         struct inpcb *inp), METHOD_ARGS(m, inp)
  302 )
  303 
  304 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
  305     pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
  306         struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  307 )
  308 
  309 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
  310     hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
  311     (inp)
  312 )
  313 
  314 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
  315     capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  316         u_int cap), METHOD_ARGS(m, cap)
  317 )
  318 
  319 int
  320 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
  321     u_int cap)
  322 {
  323 
  324         /*
  325          * Since PF_KEY is build in the kernel, we can directly
  326          * call key_havesp() without additional synchronizations.
  327          */
  328         if (cap == IPSEC_CAP_OPERABLE)
  329                 return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
  330                     key_havesp(IPSEC_DIR_OUTBOUND) != 0);
  331         return (ipsec_kmod_caps(sc, m, cap));
  332 }
  333 
  334 void
  335 ipsec_support_enable(struct ipsec_support * const sc,
  336     const struct ipsec_methods * const methods)
  337 {
  338 
  339         KASSERT(sc->enabled == 0, ("IPsec already enabled"));
  340         sc->methods = methods;
  341         sc->enabled |= IPSEC_MODULE_ENABLED;
  342 }
  343 
  344 void
  345 ipsec_support_disable(struct ipsec_support * const sc)
  346 {
  347 
  348         if (sc->enabled & IPSEC_MODULE_ENABLED) {
  349                 ipsec_kmod_drain(&sc->enabled);
  350                 sc->methods = NULL;
  351         }
  352 }
  353 #endif /* !IPSEC */
  354 #endif /* IPSEC_SUPPORT */

Cache object: 7f841f6214cca120306b3a43e01005cb


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