1*0ad3f9daSandvar /* $NetBSD: if_ipsec.h,v 1.8 2022/01/17 20:56:03 andvar Exp $ */
24ab3af3eSknakahara
34ab3af3eSknakahara /*
44ab3af3eSknakahara * Copyright (c) 2017 Internet Initiative Japan Inc.
54ab3af3eSknakahara * All rights reserved.
64ab3af3eSknakahara *
74ab3af3eSknakahara * Redistribution and use in source and binary forms, with or without
84ab3af3eSknakahara * modification, are permitted provided that the following conditions
94ab3af3eSknakahara * are met:
104ab3af3eSknakahara * 1. Redistributions of source code must retain the above copyright
114ab3af3eSknakahara * notice, this list of conditions and the following disclaimer.
124ab3af3eSknakahara * 2. Redistributions in binary form must reproduce the above copyright
134ab3af3eSknakahara * notice, this list of conditions and the following disclaimer in the
144ab3af3eSknakahara * documentation and/or other materials provided with the distribution.
154ab3af3eSknakahara *
164ab3af3eSknakahara * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
174ab3af3eSknakahara * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
184ab3af3eSknakahara * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194ab3af3eSknakahara * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
204ab3af3eSknakahara * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214ab3af3eSknakahara * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224ab3af3eSknakahara * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
234ab3af3eSknakahara * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
244ab3af3eSknakahara * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
254ab3af3eSknakahara * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
264ab3af3eSknakahara * POSSIBILITY OF SUCH DAMAGE.
274ab3af3eSknakahara */
284ab3af3eSknakahara
294ab3af3eSknakahara /*
304ab3af3eSknakahara * if_ipsec.h
314ab3af3eSknakahara */
324ab3af3eSknakahara
334ab3af3eSknakahara #ifndef _NET_IF_IPSEC_H_
344ab3af3eSknakahara #define _NET_IF_IPSEC_H_
354ab3af3eSknakahara
364ab3af3eSknakahara #include <sys/queue.h>
374ab3af3eSknakahara #ifdef _KERNEL
38ebac3c72Sknakahara #include <sys/pserialize.h>
394ab3af3eSknakahara #include <sys/psref.h>
404ab3af3eSknakahara #endif
414ab3af3eSknakahara
424ab3af3eSknakahara #ifdef _KERNEL_OPT
434ab3af3eSknakahara #include "opt_inet.h"
444ab3af3eSknakahara #endif
454ab3af3eSknakahara
464ab3af3eSknakahara #include <netinet/in.h>
474ab3af3eSknakahara #include <netipsec/ipsec.h>
484ab3af3eSknakahara
494ab3af3eSknakahara #ifdef _KERNEL
504ab3af3eSknakahara /*
514ab3af3eSknakahara * This macro controls the upper limitation on nesting of ipsec tunnels.
524ab3af3eSknakahara * Since, setting a large value to this macro with a careless configuration
534ab3af3eSknakahara * may introduce system crash, we don't allow any nestings by default.
544ab3af3eSknakahara * If you need to configure nested ipsec tunnels, you can define this macro
554ab3af3eSknakahara * in your kernel configuration file. However, if you do so, please be
564ab3af3eSknakahara * careful to configure the tunnels so that it won't make a loop.
574ab3af3eSknakahara */
584ab3af3eSknakahara #ifndef MAX_IPSEC_NEST
594ab3af3eSknakahara #define MAX_IPSEC_NEST 1
604ab3af3eSknakahara #endif
614ab3af3eSknakahara
624ab3af3eSknakahara #define IFF_NAT_T IFF_LINK0 /* enable NAT-T */
634ab3af3eSknakahara #define IFF_ECN IFF_LINK1 /* enable ECN */
64*0ad3f9daSandvar #define IFF_FWD_IPV6 IFF_LINK2 /* forward IPv6 packet */
654ab3af3eSknakahara
664ab3af3eSknakahara extern struct psref_class *iv_psref_class;
674ab3af3eSknakahara
684ab3af3eSknakahara struct ipsec_variant {
694ab3af3eSknakahara struct ipsec_softc *iv_softc;
704ab3af3eSknakahara
714ab3af3eSknakahara struct sockaddr *iv_psrc; /* Physical src addr */
724ab3af3eSknakahara struct sockaddr *iv_pdst; /* Physical dst addr */
734ab3af3eSknakahara const struct encaptab *iv_encap_cookie4;
744ab3af3eSknakahara const struct encaptab *iv_encap_cookie6;
754ab3af3eSknakahara int (*iv_output)(struct ipsec_variant *, int, struct mbuf *);
764ab3af3eSknakahara in_port_t iv_sport;
774ab3af3eSknakahara in_port_t iv_dport;
784ab3af3eSknakahara
794ab3af3eSknakahara /*
804ab3af3eSknakahara * IPsec SPs
814ab3af3eSknakahara * Don't change directly, use if_ipsec_replace_sp().
824ab3af3eSknakahara */
834ab3af3eSknakahara struct secpolicy *iv_sp[IPSEC_DIR_MAX];
844ab3af3eSknakahara struct secpolicy *iv_sp6[IPSEC_DIR_MAX];
854ab3af3eSknakahara
864ab3af3eSknakahara struct psref_target iv_psref;
874ab3af3eSknakahara };
884ab3af3eSknakahara
894ab3af3eSknakahara struct ipsec_softc {
904ab3af3eSknakahara struct ifnet ipsec_if; /* common area - must be at the top */
912da350beSknakahara percpu_t *ipsec_ro_percpu; /* struct tunnel_ro */
924ab3af3eSknakahara struct ipsec_variant *ipsec_var; /*
934ab3af3eSknakahara * reader must use ipsec_getref_variant()
944ab3af3eSknakahara * instead of direct dereference.
954ab3af3eSknakahara */
964ab3af3eSknakahara kmutex_t ipsec_lock; /* writer lock for ipsec_var */
97ebac3c72Sknakahara pserialize_t ipsec_psz;
9893a28c82Sknakahara int ipsec_pmtu;
994ab3af3eSknakahara
1004ab3af3eSknakahara LIST_ENTRY(ipsec_softc) ipsec_list; /* list of all gifs */
1014ab3af3eSknakahara };
1024ab3af3eSknakahara
1034ab3af3eSknakahara #define IPSEC_MTU (1280) /* Default MTU */
1044ab3af3eSknakahara #define IPSEC_MTU_MIN (1280) /* Minimum MTU */
1054ab3af3eSknakahara #define IPSEC_MTU_MAX (8192) /* Maximum MTU */
1064ab3af3eSknakahara
1074ab3af3eSknakahara #define IV_SP_IN(x) ((x)->iv_sp[IPSEC_DIR_INBOUND])
1084ab3af3eSknakahara #define IV_SP_IN6(x) ((x)->iv_sp6[IPSEC_DIR_INBOUND])
1094ab3af3eSknakahara #define IV_SP_OUT(x) ((x)->iv_sp[IPSEC_DIR_OUTBOUND])
1104ab3af3eSknakahara #define IV_SP_OUT6(x) ((x)->iv_sp6[IPSEC_DIR_OUTBOUND])
1114ab3af3eSknakahara
112ec77b505Schristos static __inline bool
if_ipsec_variant_is_configured(struct ipsec_variant * var)1134ab3af3eSknakahara if_ipsec_variant_is_configured(struct ipsec_variant *var)
1144ab3af3eSknakahara {
1154ab3af3eSknakahara
1164ab3af3eSknakahara return (var->iv_psrc != NULL && var->iv_pdst != NULL);
1174ab3af3eSknakahara }
1184ab3af3eSknakahara
119ec77b505Schristos static __inline bool
if_ipsec_variant_is_unconfigured(struct ipsec_variant * var)1204ab3af3eSknakahara if_ipsec_variant_is_unconfigured(struct ipsec_variant *var)
1214ab3af3eSknakahara {
1224ab3af3eSknakahara
1234ab3af3eSknakahara return (var->iv_psrc == NULL || var->iv_pdst == NULL);
1244ab3af3eSknakahara }
1254ab3af3eSknakahara
126ec77b505Schristos static __inline void
if_ipsec_copy_variant(struct ipsec_variant * dst,struct ipsec_variant * src)1274ab3af3eSknakahara if_ipsec_copy_variant(struct ipsec_variant *dst, struct ipsec_variant *src)
1284ab3af3eSknakahara {
1294ab3af3eSknakahara
1304ab3af3eSknakahara dst->iv_softc = src->iv_softc;
1314ab3af3eSknakahara dst->iv_psrc = src->iv_psrc;
1324ab3af3eSknakahara dst->iv_pdst = src->iv_pdst;
1334ab3af3eSknakahara dst->iv_encap_cookie4 = src->iv_encap_cookie4;
1344ab3af3eSknakahara dst->iv_encap_cookie6 = src->iv_encap_cookie6;
1354ab3af3eSknakahara dst->iv_output = src->iv_output;
1364ab3af3eSknakahara dst->iv_sport = src->iv_sport;
1374ab3af3eSknakahara dst->iv_dport = src->iv_dport;
1384ab3af3eSknakahara }
1394ab3af3eSknakahara
140ec77b505Schristos static __inline void
if_ipsec_clear_config(struct ipsec_variant * var)1414ab3af3eSknakahara if_ipsec_clear_config(struct ipsec_variant *var)
1424ab3af3eSknakahara {
1434ab3af3eSknakahara
1444ab3af3eSknakahara var->iv_psrc = NULL;
1454ab3af3eSknakahara var->iv_pdst = NULL;
1464ab3af3eSknakahara var->iv_encap_cookie4 = NULL;
1474ab3af3eSknakahara var->iv_encap_cookie6 = NULL;
1484ab3af3eSknakahara var->iv_output = NULL;
1494ab3af3eSknakahara var->iv_sport = 0;
1504ab3af3eSknakahara var->iv_dport = 0;
1514ab3af3eSknakahara }
1524ab3af3eSknakahara
1534ab3af3eSknakahara /*
1544ab3af3eSknakahara * Get ipsec_variant from ipsec_softc.
1554ab3af3eSknakahara *
1564ab3af3eSknakahara * Never return NULL by contract.
1574ab3af3eSknakahara * ipsec_variant itself is protected not to be freed by lv_psref.
1584ab3af3eSknakahara * Once a reader dereference sc->sc_var by this API, the reader must not
1594ab3af3eSknakahara * re-dereference from sc->sc_var.
1604ab3af3eSknakahara */
161ec77b505Schristos static __inline struct ipsec_variant *
if_ipsec_getref_variant(struct ipsec_softc * sc,struct psref * psref)1624ab3af3eSknakahara if_ipsec_getref_variant(struct ipsec_softc *sc, struct psref *psref)
1634ab3af3eSknakahara {
1644ab3af3eSknakahara struct ipsec_variant *var;
1654ab3af3eSknakahara int s;
1664ab3af3eSknakahara
1674ab3af3eSknakahara s = pserialize_read_enter();
16847880c13Sriastradh var = atomic_load_consume(&sc->ipsec_var);
1694ab3af3eSknakahara KASSERT(var != NULL);
1704ab3af3eSknakahara psref_acquire(psref, &var->iv_psref, iv_psref_class);
1714ab3af3eSknakahara pserialize_read_exit(s);
1724ab3af3eSknakahara
1734ab3af3eSknakahara return var;
1744ab3af3eSknakahara }
1754ab3af3eSknakahara
176ec77b505Schristos static __inline void
if_ipsec_putref_variant(struct ipsec_variant * var,struct psref * psref)1774ab3af3eSknakahara if_ipsec_putref_variant(struct ipsec_variant *var, struct psref *psref)
1784ab3af3eSknakahara {
1794ab3af3eSknakahara
1804ab3af3eSknakahara KASSERT(var != NULL);
1814ab3af3eSknakahara psref_release(psref, &var->iv_psref, iv_psref_class);
1824ab3af3eSknakahara }
1834ab3af3eSknakahara
184ec77b505Schristos static __inline bool
if_ipsec_heldref_variant(struct ipsec_variant * var)1854ab3af3eSknakahara if_ipsec_heldref_variant(struct ipsec_variant *var)
1864ab3af3eSknakahara {
1874ab3af3eSknakahara
1884ab3af3eSknakahara return psref_held(&var->iv_psref, iv_psref_class);
1894ab3af3eSknakahara }
1904ab3af3eSknakahara
1914ab3af3eSknakahara void ipsecifattach(int);
1924ab3af3eSknakahara int if_ipsec_encap_func(struct mbuf *, int, int, void *);
1934ab3af3eSknakahara void if_ipsec_input(struct mbuf *, int, struct ifnet *);
1944ab3af3eSknakahara int if_ipsec_output(struct ifnet *, struct mbuf *,
1954ab3af3eSknakahara const struct sockaddr *, const struct rtentry *);
1964ab3af3eSknakahara int if_ipsec_ioctl(struct ifnet *, u_long, void *);
1974ab3af3eSknakahara #endif /* _KERNEL */
1984ab3af3eSknakahara
1994ab3af3eSknakahara /*
2004ab3af3eSknakahara * sharing SP note:
2014ab3af3eSknakahara * When ipsec(4) I/Fs use NAT-T, they can use the same src and dst address pair
2024ab3af3eSknakahara * as long as they use different port. Howerver, SPD cannot have the SPs which
2034ab3af3eSknakahara * use the same src and dst address pair and the same policy. So, such ipsec(4)
2044ab3af3eSknakahara * I/Fs share the same SPs.
2054ab3af3eSknakahara * To avoid race between ipsec0 set_tunnel/delete_tunnel and ipsec1
2064ab3af3eSknakahara * t_tunnel/delete_tunnel, any global lock is needed. See also the following
2074ab3af3eSknakahara * locking notes.
2084ab3af3eSknakahara *
2094ab3af3eSknakahara * Locking notes:
2104ab3af3eSknakahara * + ipsec_softcs.list is protected by ipsec_softcs.lock (an adaptive mutex)
2114ab3af3eSknakahara * ipsec_softc_list is list of all ipsec_softcs. It is used by ioctl
2124ab3af3eSknakahara * context only.
2134ab3af3eSknakahara * + ipsec_softc->ipsec_var is protected by
2144ab3af3eSknakahara * - ipsec_softc->ipsec_lock (an adaptive mutex) for writer
2154ab3af3eSknakahara * - ipsec_var->iv_psref for reader
2164ab3af3eSknakahara * ipsec_softc->ipsec_var is used for variant values while the ipsec tunnel
2174ab3af3eSknakahara * exists.
2182da350beSknakahara * + struct tunnel_ro->tr_ro is protected by struct tunnel_ro->tr_lock.
2194ab3af3eSknakahara * This lock is required to exclude softnet/0 lwp(such as output
2204ab3af3eSknakahara * processing softint) and processing lwp(such as DAD timer processing).
2214ab3af3eSknakahara * + if_ipsec_share_sp() and if_ipsec_unshare_sp() operations are serialized by
2224ab3af3eSknakahara * encap_lock
2234ab3af3eSknakahara * This only need to be global lock, need not to be encap_lock.
2244ab3af3eSknakahara *
2254ab3af3eSknakahara * Locking order:
2264ab3af3eSknakahara * - encap_lock => ipsec_softc->ipsec_lock => ipsec_softcs.lock
2274ab3af3eSknakahara */
2284ab3af3eSknakahara #endif /* _NET_IF_IPSEC_H_ */
229