xref: /freebsd/sys/netipsec/ipsec.c (revision 22bbefb2c9e93a7695900fab3ade9863a826744f)
188768458SSam Leffler /*	$FreeBSD$	*/
288768458SSam Leffler /*	$KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $	*/
388768458SSam Leffler 
4c398230bSWarner Losh /*-
588768458SSam Leffler  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
688768458SSam Leffler  * All rights reserved.
788768458SSam Leffler  *
888768458SSam Leffler  * Redistribution and use in source and binary forms, with or without
988768458SSam Leffler  * modification, are permitted provided that the following conditions
1088768458SSam Leffler  * are met:
1188768458SSam Leffler  * 1. Redistributions of source code must retain the above copyright
1288768458SSam Leffler  *    notice, this list of conditions and the following disclaimer.
1388768458SSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
1488768458SSam Leffler  *    notice, this list of conditions and the following disclaimer in the
1588768458SSam Leffler  *    documentation and/or other materials provided with the distribution.
1688768458SSam Leffler  * 3. Neither the name of the project nor the names of its contributors
1788768458SSam Leffler  *    may be used to endorse or promote products derived from this software
1888768458SSam Leffler  *    without specific prior written permission.
1988768458SSam Leffler  *
2088768458SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2188768458SSam Leffler  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2288768458SSam Leffler  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2388768458SSam Leffler  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2488768458SSam Leffler  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2588768458SSam Leffler  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2688768458SSam Leffler  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2788768458SSam Leffler  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2888768458SSam Leffler  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2988768458SSam Leffler  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3088768458SSam Leffler  * SUCH DAMAGE.
3188768458SSam Leffler  */
3288768458SSam Leffler 
3388768458SSam Leffler /*
3488768458SSam Leffler  * IPsec controller part.
3588768458SSam Leffler  */
3688768458SSam Leffler 
3788768458SSam Leffler #include "opt_inet.h"
3888768458SSam Leffler #include "opt_inet6.h"
3988768458SSam Leffler #include "opt_ipsec.h"
4088768458SSam Leffler 
4188768458SSam Leffler #include <sys/param.h>
4288768458SSam Leffler #include <sys/systm.h>
4388768458SSam Leffler #include <sys/malloc.h>
4488768458SSam Leffler #include <sys/mbuf.h>
4588768458SSam Leffler #include <sys/domain.h>
4646ee43b2SRobert Watson #include <sys/priv.h>
4788768458SSam Leffler #include <sys/protosw.h>
4888768458SSam Leffler #include <sys/socket.h>
4988768458SSam Leffler #include <sys/socketvar.h>
5088768458SSam Leffler #include <sys/errno.h>
51ef91a976SAndrey V. Elsukov #include <sys/hhook.h>
5288768458SSam Leffler #include <sys/time.h>
5388768458SSam Leffler #include <sys/kernel.h>
5488768458SSam Leffler #include <sys/syslog.h>
5588768458SSam Leffler #include <sys/sysctl.h>
5688768458SSam Leffler #include <sys/proc.h>
5788768458SSam Leffler 
5888768458SSam Leffler #include <net/if.h>
59ef91a976SAndrey V. Elsukov #include <net/if_enc.h>
6076039bc8SGleb Smirnoff #include <net/if_var.h>
61eddfbb76SRobert Watson #include <net/vnet.h>
6288768458SSam Leffler 
6388768458SSam Leffler #include <netinet/in.h>
6488768458SSam Leffler #include <netinet/in_systm.h>
6588768458SSam Leffler #include <netinet/ip.h>
6688768458SSam Leffler #include <netinet/ip_var.h>
6788768458SSam Leffler #include <netinet/in_var.h>
6888768458SSam Leffler #include <netinet/udp.h>
6988768458SSam Leffler #include <netinet/udp_var.h>
7088768458SSam Leffler #include <netinet/tcp.h>
7188768458SSam Leffler #include <netinet/udp.h>
7288768458SSam Leffler 
7388768458SSam Leffler #include <netinet/ip6.h>
7488768458SSam Leffler #ifdef INET6
7588768458SSam Leffler #include <netinet6/ip6_var.h>
7688768458SSam Leffler #endif
7788768458SSam Leffler #include <netinet/in_pcb.h>
7888768458SSam Leffler #ifdef INET6
7988768458SSam Leffler #include <netinet/icmp6.h>
8088768458SSam Leffler #endif
8188768458SSam Leffler 
822cb64cb2SGeorge V. Neville-Neil #include <sys/types.h>
8388768458SSam Leffler #include <netipsec/ipsec.h>
8488768458SSam Leffler #ifdef INET6
8588768458SSam Leffler #include <netipsec/ipsec6.h>
8688768458SSam Leffler #endif
8788768458SSam Leffler #include <netipsec/ah_var.h>
8888768458SSam Leffler #include <netipsec/esp_var.h>
8988768458SSam Leffler #include <netipsec/ipcomp.h>		/*XXX*/
9088768458SSam Leffler #include <netipsec/ipcomp_var.h>
91fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h>
9288768458SSam Leffler 
9388768458SSam Leffler #include <netipsec/key.h>
9488768458SSam Leffler #include <netipsec/keydb.h>
9588768458SSam Leffler #include <netipsec/key_debug.h>
9688768458SSam Leffler 
9788768458SSam Leffler #include <netipsec/xform.h>
9888768458SSam Leffler 
9988768458SSam Leffler #include <machine/in_cksum.h>
10088768458SSam Leffler 
1017aee3dd1SSam Leffler #include <opencrypto/cryptodev.h>
1027aee3dd1SSam Leffler 
103de47c390SBjoern A. Zeeb /* NB: name changed so netstat doesn't use it. */
104db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec4stat);
105db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec4stat);
106db8c0879SAndrey V. Elsukov 
107db8c0879SAndrey V. Elsukov #ifdef VIMAGE
108db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec4stat);
109db8c0879SAndrey V. Elsukov #endif /* VIMAGE */
110db8c0879SAndrey V. Elsukov 
111eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_offsetmask) = 0;	/* maybe IP_DF? */
112eddfbb76SRobert Watson /* DF bit on encap. 0: clear 1: set 2: copy */
113eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_dfbit) = 0;
114eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_trans_deflev) = IPSEC_LEVEL_USE;
115eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_net_deflev) = IPSEC_LEVEL_USE;
116eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE;
117eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE;
118eddfbb76SRobert Watson /* ECN ignore(-1)/forbidden(0)/allowed(1) */
119eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_ecn) = 0;
120eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_randpad) = -1;
121eddfbb76SRobert Watson 
122fcf59617SAndrey V. Elsukov static VNET_DEFINE(int, ip4_filtertunnel) = 0;
123fcf59617SAndrey V. Elsukov #define	V_ip4_filtertunnel VNET(ip4_filtertunnel)
124fcf59617SAndrey V. Elsukov static VNET_DEFINE(int, check_policy_history) = 0;
125fcf59617SAndrey V. Elsukov #define	V_check_policy_history	VNET(check_policy_history)
126fcf59617SAndrey V. Elsukov static VNET_DEFINE(struct secpolicy *, def_policy) = NULL;
12793201211SAndrey V. Elsukov #define	V_def_policy	VNET(def_policy)
128fcf59617SAndrey V. Elsukov static int
129fcf59617SAndrey V. Elsukov sysctl_def_policy(SYSCTL_HANDLER_ARGS)
130fcf59617SAndrey V. Elsukov {
131fcf59617SAndrey V. Elsukov 	int error, value;
132fcf59617SAndrey V. Elsukov 
133fcf59617SAndrey V. Elsukov 	value = V_def_policy->policy;
134fcf59617SAndrey V. Elsukov 	error = sysctl_handle_int(oidp, &value, 0, req);
135fcf59617SAndrey V. Elsukov 	if (error == 0) {
136fcf59617SAndrey V. Elsukov 		if (value != IPSEC_POLICY_DISCARD &&
137fcf59617SAndrey V. Elsukov 		    value != IPSEC_POLICY_NONE)
138fcf59617SAndrey V. Elsukov 			return (EINVAL);
139fcf59617SAndrey V. Elsukov 		V_def_policy->policy = value;
140fcf59617SAndrey V. Elsukov 	}
141fcf59617SAndrey V. Elsukov 	return (error);
142fcf59617SAndrey V. Elsukov }
143fcf59617SAndrey V. Elsukov 
14488768458SSam Leffler /*
14588768458SSam Leffler  * Crypto support requirements:
14688768458SSam Leffler  *
14788768458SSam Leffler  *  1	require hardware support
14888768458SSam Leffler  * -1	require software support
14988768458SSam Leffler  *  0	take anything
15088768458SSam Leffler  */
151eddfbb76SRobert Watson VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
152fcf59617SAndrey V. Elsukov /*
153fcf59617SAndrey V. Elsukov  * TCP/UDP checksum handling policy for transport mode NAT-T (RFC3948)
154fcf59617SAndrey V. Elsukov  *
155fcf59617SAndrey V. Elsukov  * 0 - auto: incrementally recompute, when checksum delta is known;
156fcf59617SAndrey V. Elsukov  *     if checksum delta isn't known, reset checksum to zero for UDP,
157fcf59617SAndrey V. Elsukov  *     and mark csum_flags as valid for TCP.
158fcf59617SAndrey V. Elsukov  * 1 - fully recompute TCP/UDP checksum.
159fcf59617SAndrey V. Elsukov  */
160fcf59617SAndrey V. Elsukov VNET_DEFINE(int, natt_cksum_policy) = 0;
16188768458SSam Leffler 
16213a6cf24SBjoern A. Zeeb FEATURE(ipsec, "Internet Protocol Security (IPsec)");
16313a6cf24SBjoern A. Zeeb FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')");
16413a6cf24SBjoern A. Zeeb 
16588768458SSam Leffler SYSCTL_DECL(_net_inet_ipsec);
16688768458SSam Leffler 
16788768458SSam Leffler /* net.inet.ipsec */
168fcf59617SAndrey V. Elsukov SYSCTL_PROC(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy,
169fcf59617SAndrey V. Elsukov 	CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW, 0, 0, sysctl_def_policy, "I",
170be6b1304STom Rhodes 	"IPsec default policy.");
1716df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev,
1726df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_trans_deflev), 0,
1738b615593SMarko Zec 	"Default ESP transport mode level");
1746df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev,
1756df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_net_deflev), 0,
1768b615593SMarko Zec 	"Default ESP tunnel mode level.");
1776df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev,
1786df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_trans_deflev), 0,
1798b615593SMarko Zec 	"AH transfer mode default level.");
1806df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev,
1816df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_net_deflev), 0,
1828b615593SMarko Zec 	"AH tunnel mode default level.");
1836df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos,
1846df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0,
185fcf59617SAndrey V. Elsukov 	"If set, clear type-of-service field when doing AH computation.");
1866df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, ah_offsetmask,
1876df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_offsetmask), 0,
188fcf59617SAndrey V. Elsukov 	"If not set, clear offset field mask when doing AH computation.");
1896df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, dfbit,
1906df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_dfbit), 0,
1918b615593SMarko Zec 	"Do not fragment bit on encap.");
1926df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn,
1936df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0,
194be6b1304STom Rhodes 	"Explicit Congestion Notification handling.");
1956df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support,
1966df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(crypto_support), 0,
197be6b1304STom Rhodes 	"Crypto driver selection.");
198fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, check_policy_history,
199fcf59617SAndrey V. Elsukov 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(check_policy_history), 0,
200fcf59617SAndrey V. Elsukov 	"Use strict check of inbound packets to security policy compliance.");
201fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, natt_cksum_policy,
202fcf59617SAndrey V. Elsukov 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(natt_cksum_policy), 0,
203fcf59617SAndrey V. Elsukov 	"Method to fix TCP/UDP checksum for transport mode IPsec after NAT.");
204fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, filtertunnel,
205fcf59617SAndrey V. Elsukov 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_filtertunnel), 0,
206fcf59617SAndrey V. Elsukov 	"If set, filter packets from an IPsec tunnel.");
207db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ipsec, OID_AUTO, ipsecstats, struct ipsecstat,
208db8c0879SAndrey V. Elsukov     ipsec4stat, "IPsec IPv4 statistics.");
20988768458SSam Leffler 
2106131838bSPawel Jakub Dawidek #ifdef REGRESSION
211dfa9422bSPawel Jakub Dawidek /*
212dfa9422bSPawel Jakub Dawidek  * When set to 1, IPsec will send packets with the same sequence number.
213dfa9422bSPawel Jakub Dawidek  * This allows to verify if the other side has proper replay attacks detection.
214dfa9422bSPawel Jakub Dawidek  */
215eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_replay) = 0;
2166df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay,
2176df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_replay), 0,
218eddfbb76SRobert Watson 	"Emulate replay attack");
219dfa9422bSPawel Jakub Dawidek /*
220dfa9422bSPawel Jakub Dawidek  * When set 1, IPsec will send packets with corrupted HMAC.
221dfa9422bSPawel Jakub Dawidek  * This allows to verify if the other side properly detects modified packets.
222dfa9422bSPawel Jakub Dawidek  */
223eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_integrity) = 0;
2246df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity,
2256df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_integrity), 0,
226eddfbb76SRobert Watson 	"Emulate man-in-the-middle attack");
2276131838bSPawel Jakub Dawidek #endif
228dfa9422bSPawel Jakub Dawidek 
22988768458SSam Leffler #ifdef INET6
230db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec6stat);
231db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec6stat);
232db8c0879SAndrey V. Elsukov 
233db8c0879SAndrey V. Elsukov #ifdef VIMAGE
234db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec6stat);
235db8c0879SAndrey V. Elsukov #endif /* VIMAGE */
236db8c0879SAndrey V. Elsukov 
237eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_trans_deflev) = IPSEC_LEVEL_USE;
238eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_net_deflev) = IPSEC_LEVEL_USE;
239eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_trans_deflev) = IPSEC_LEVEL_USE;
240eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_net_deflev) = IPSEC_LEVEL_USE;
241eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ipsec_ecn) = 0;	/* ECN ignore(-1)/forbidden(0)/allowed(1) */
24288768458SSam Leffler 
243fcf59617SAndrey V. Elsukov static VNET_DEFINE(int, ip6_filtertunnel) = 0;
244fcf59617SAndrey V. Elsukov #define	V_ip6_filtertunnel	VNET(ip6_filtertunnel)
245fcf59617SAndrey V. Elsukov 
24688768458SSam Leffler SYSCTL_DECL(_net_inet6_ipsec6);
24788768458SSam Leffler 
24888768458SSam Leffler /* net.inet6.ipsec6 */
249fcf59617SAndrey V. Elsukov SYSCTL_PROC(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy,
250fcf59617SAndrey V. Elsukov 	CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW, 0, 0, sysctl_def_policy, "I",
2518b615593SMarko Zec 	"IPsec default policy.");
2526df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev,
2536df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_trans_deflev), 0,
2548b615593SMarko Zec 	"Default ESP transport mode level.");
2556df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev,
2566df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_net_deflev), 0,
2578b615593SMarko Zec 	"Default ESP tunnel mode level.");
2586df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev,
2596df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_trans_deflev), 0,
2608b615593SMarko Zec 	"AH transfer mode default level.");
2616df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev,
2626df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_net_deflev), 0,
2638b615593SMarko Zec 	"AH tunnel mode default level.");
2646df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn,
2656df8a710SGleb Smirnoff 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ipsec_ecn), 0,
2663377c961STom Rhodes 	"Explicit Congestion Notification handling.");
267fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet6_ipsec6, OID_AUTO, filtertunnel,
268fcf59617SAndrey V. Elsukov 	CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_filtertunnel),  0,
269fcf59617SAndrey V. Elsukov 	"If set, filter packets from an IPsec tunnel.");
270db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet6_ipsec6, IPSECCTL_STATS, ipsecstats,
271db8c0879SAndrey V. Elsukov     struct ipsecstat, ipsec6stat, "IPsec IPv6 statistics.");
27288768458SSam Leffler #endif /* INET6 */
27388768458SSam Leffler 
274fcf59617SAndrey V. Elsukov static int ipsec_in_reject(struct secpolicy *, struct inpcb *,
275fcf59617SAndrey V. Elsukov     const struct mbuf *);
276fcf59617SAndrey V. Elsukov 
277fcf59617SAndrey V. Elsukov #ifdef INET
278fcf59617SAndrey V. Elsukov static void ipsec4_get_ulp(const struct mbuf *, struct secpolicyindex *, int);
279fcf59617SAndrey V. Elsukov static void ipsec4_setspidx_ipaddr(const struct mbuf *,
280fcf59617SAndrey V. Elsukov     struct secpolicyindex *);
281fcf59617SAndrey V. Elsukov #endif
28288768458SSam Leffler #ifdef INET6
283efb10c3cSAndrey V. Elsukov static void ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *, int);
284fcf59617SAndrey V. Elsukov static void ipsec6_setspidx_ipaddr(const struct mbuf *,
285fcf59617SAndrey V. Elsukov     struct secpolicyindex *);
28688768458SSam Leffler #endif
2876464079fSSam Leffler 
28888768458SSam Leffler /*
28988768458SSam Leffler  * Return a held reference to the default SP.
29088768458SSam Leffler  */
29188768458SSam Leffler static struct secpolicy *
292fcf59617SAndrey V. Elsukov key_allocsp_default(void)
293fcf59617SAndrey V. Elsukov {
294fcf59617SAndrey V. Elsukov 
295fcf59617SAndrey V. Elsukov 	key_addref(V_def_policy);
296fcf59617SAndrey V. Elsukov 	return (V_def_policy);
297fcf59617SAndrey V. Elsukov }
298fcf59617SAndrey V. Elsukov 
299fcf59617SAndrey V. Elsukov static void
300fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(struct inpcb *inp, u_int dir)
30188768458SSam Leffler {
30288768458SSam Leffler 	struct secpolicy *sp;
30388768458SSam Leffler 
304fcf59617SAndrey V. Elsukov 	INP_WLOCK_ASSERT(inp);
305fcf59617SAndrey V. Elsukov 	if (dir == IPSEC_DIR_OUTBOUND) {
306fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->flags & INP_INBOUND_POLICY)
307fcf59617SAndrey V. Elsukov 			return;
308fcf59617SAndrey V. Elsukov 		sp = inp->inp_sp->sp_in;
309fcf59617SAndrey V. Elsukov 		inp->inp_sp->sp_in = NULL;
310fcf59617SAndrey V. Elsukov 	} else {
311fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->flags & INP_OUTBOUND_POLICY)
312fcf59617SAndrey V. Elsukov 			return;
313fcf59617SAndrey V. Elsukov 		sp = inp->inp_sp->sp_out;
314fcf59617SAndrey V. Elsukov 		inp->inp_sp->sp_out = NULL;
31588768458SSam Leffler 	}
316fcf59617SAndrey V. Elsukov 	if (sp != NULL)
317fcf59617SAndrey V. Elsukov 		key_freesp(&sp); /* release extra reference */
31888768458SSam Leffler }
31988768458SSam Leffler 
320fcf59617SAndrey V. Elsukov static void
321fcf59617SAndrey V. Elsukov ipsec_cachepolicy(struct inpcb *inp, struct secpolicy *sp, u_int dir)
322fcf59617SAndrey V. Elsukov {
323fcf59617SAndrey V. Elsukov 	uint32_t genid;
324fcf59617SAndrey V. Elsukov 	int downgrade;
325fcf59617SAndrey V. Elsukov 
326fcf59617SAndrey V. Elsukov 	INP_LOCK_ASSERT(inp);
327fcf59617SAndrey V. Elsukov 
328fcf59617SAndrey V. Elsukov 	if (dir == IPSEC_DIR_OUTBOUND) {
329fcf59617SAndrey V. Elsukov 		/* Do we have configured PCB policy? */
330fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->flags & INP_OUTBOUND_POLICY)
331fcf59617SAndrey V. Elsukov 			return;
332fcf59617SAndrey V. Elsukov 		/* Another thread has already set cached policy */
333fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->sp_out != NULL)
334fcf59617SAndrey V. Elsukov 			return;
33588768458SSam Leffler 		/*
336fcf59617SAndrey V. Elsukov 		 * Do not cache OUTBOUND policy if PCB isn't connected,
337fcf59617SAndrey V. Elsukov 		 * i.e. foreign address is INADDR_ANY/UNSPECIFIED.
33888768458SSam Leffler 		 */
339fcf59617SAndrey V. Elsukov #ifdef INET
340fcf59617SAndrey V. Elsukov 		if ((inp->inp_vflag & INP_IPV4) != 0 &&
341fcf59617SAndrey V. Elsukov 		    inp->inp_faddr.s_addr == INADDR_ANY)
342fcf59617SAndrey V. Elsukov 			return;
343fcf59617SAndrey V. Elsukov #endif
344fcf59617SAndrey V. Elsukov #ifdef INET6
345fcf59617SAndrey V. Elsukov 		if ((inp->inp_vflag & INP_IPV6) != 0 &&
346fcf59617SAndrey V. Elsukov 		    IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
347fcf59617SAndrey V. Elsukov 			return;
348fcf59617SAndrey V. Elsukov #endif
349fcf59617SAndrey V. Elsukov 	} else {
350fcf59617SAndrey V. Elsukov 		/* Do we have configured PCB policy? */
351fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->flags & INP_INBOUND_POLICY)
352fcf59617SAndrey V. Elsukov 			return;
353fcf59617SAndrey V. Elsukov 		/* Another thread has already set cached policy */
354fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->sp_in != NULL)
355fcf59617SAndrey V. Elsukov 			return;
35688768458SSam Leffler 		/*
357fcf59617SAndrey V. Elsukov 		 * Do not cache INBOUND policy for listen socket,
358fcf59617SAndrey V. Elsukov 		 * that is bound to INADDR_ANY/UNSPECIFIED address.
35988768458SSam Leffler 		 */
360fcf59617SAndrey V. Elsukov #ifdef INET
361fcf59617SAndrey V. Elsukov 		if ((inp->inp_vflag & INP_IPV4) != 0 &&
362fcf59617SAndrey V. Elsukov 		    inp->inp_faddr.s_addr == INADDR_ANY)
363fcf59617SAndrey V. Elsukov 			return;
364fcf59617SAndrey V. Elsukov #endif
365fcf59617SAndrey V. Elsukov #ifdef INET6
366fcf59617SAndrey V. Elsukov 		if ((inp->inp_vflag & INP_IPV6) != 0 &&
367fcf59617SAndrey V. Elsukov 		    IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
368fcf59617SAndrey V. Elsukov 			return;
369fcf59617SAndrey V. Elsukov #endif
370c1fc5e96SErmal Luçi 	}
371fcf59617SAndrey V. Elsukov 	downgrade = 0;
372fcf59617SAndrey V. Elsukov 	if (!INP_WLOCKED(inp)) {
373fcf59617SAndrey V. Elsukov 		if ((downgrade = INP_TRY_UPGRADE(inp)) == 0)
374fcf59617SAndrey V. Elsukov 			return;
37588768458SSam Leffler 	}
376fcf59617SAndrey V. Elsukov 	if (dir == IPSEC_DIR_OUTBOUND)
377fcf59617SAndrey V. Elsukov 		inp->inp_sp->sp_out = sp;
37888768458SSam Leffler 	else
379fcf59617SAndrey V. Elsukov 		inp->inp_sp->sp_in = sp;
380fcf59617SAndrey V. Elsukov 	/*
381fcf59617SAndrey V. Elsukov 	 * SP is already referenced by the lookup code.
382fcf59617SAndrey V. Elsukov 	 * We take extra reference here to avoid race in the
383fcf59617SAndrey V. Elsukov 	 * ipsec_getpcbpolicy() function - SP will not be freed in the
384fcf59617SAndrey V. Elsukov 	 * time between we take SP pointer from the cache and key_addref()
385fcf59617SAndrey V. Elsukov 	 * call.
386fcf59617SAndrey V. Elsukov 	 */
387fcf59617SAndrey V. Elsukov 	key_addref(sp);
388fcf59617SAndrey V. Elsukov 	genid = key_getspgen();
389fcf59617SAndrey V. Elsukov 	if (genid != inp->inp_sp->genid) {
390fcf59617SAndrey V. Elsukov 		ipsec_invalidate_cache(inp, dir);
391fcf59617SAndrey V. Elsukov 		inp->inp_sp->genid = genid;
39288768458SSam Leffler 	}
393fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_STAMP,
394fcf59617SAndrey V. Elsukov 	    printf("%s: PCB(%p): cached %s SP(%p)\n",
395fcf59617SAndrey V. Elsukov 	    __func__, inp, dir == IPSEC_DIR_OUTBOUND ? "OUTBOUND":
396fcf59617SAndrey V. Elsukov 	    "INBOUND", sp));
397fcf59617SAndrey V. Elsukov 	if (downgrade != 0)
398fcf59617SAndrey V. Elsukov 		INP_DOWNGRADE(inp);
399fcf59617SAndrey V. Elsukov }
400fcf59617SAndrey V. Elsukov 
401fcf59617SAndrey V. Elsukov static struct secpolicy *
402fcf59617SAndrey V. Elsukov ipsec_checkpolicy(struct secpolicy *sp, struct inpcb *inp, int *error)
403fcf59617SAndrey V. Elsukov {
404fcf59617SAndrey V. Elsukov 
405fcf59617SAndrey V. Elsukov 	/* Save found OUTBOUND policy into PCB SP cache. */
406fcf59617SAndrey V. Elsukov 	if (inp != NULL && inp->inp_sp != NULL && inp->inp_sp->sp_out == NULL)
407fcf59617SAndrey V. Elsukov 		ipsec_cachepolicy(inp, sp, IPSEC_DIR_OUTBOUND);
408fcf59617SAndrey V. Elsukov 
40988768458SSam Leffler 	switch (sp->policy) {
41088768458SSam Leffler 	default:
4119ffa9677SSam Leffler 		printf("%s: invalid policy %u\n", __func__, sp->policy);
412de47c390SBjoern A. Zeeb 		/* FALLTHROUGH */
41388768458SSam Leffler 	case IPSEC_POLICY_DISCARD:
414de47c390SBjoern A. Zeeb 		*error = -EINVAL;	/* Packet is discarded by caller. */
415fcf59617SAndrey V. Elsukov 		/* FALLTHROUGH */
41688768458SSam Leffler 	case IPSEC_POLICY_BYPASS:
41788768458SSam Leffler 	case IPSEC_POLICY_NONE:
418fcf59617SAndrey V. Elsukov 		key_freesp(&sp);
419de47c390SBjoern A. Zeeb 		sp = NULL;		/* NB: force NULL result. */
42088768458SSam Leffler 		break;
42188768458SSam Leffler 	case IPSEC_POLICY_IPSEC:
422fcf59617SAndrey V. Elsukov 		/* XXXAE: handle LARVAL SP */
42388768458SSam Leffler 		break;
42488768458SSam Leffler 	}
425fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_DUMP,
426fcf59617SAndrey V. Elsukov 	    printf("%s: get SP(%p), error %d\n", __func__, sp, *error));
427de47c390SBjoern A. Zeeb 	return (sp);
42888768458SSam Leffler }
42988768458SSam Leffler 
430fcf59617SAndrey V. Elsukov static struct secpolicy *
431fcf59617SAndrey V. Elsukov ipsec_getpcbpolicy(struct inpcb *inp, u_int dir)
43288768458SSam Leffler {
433fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
434fcf59617SAndrey V. Elsukov 	int flags, downgrade;
43588768458SSam Leffler 
436fcf59617SAndrey V. Elsukov 	if (inp == NULL || inp->inp_sp == NULL)
437fcf59617SAndrey V. Elsukov 		return (NULL);
43888768458SSam Leffler 
439fcf59617SAndrey V. Elsukov 	INP_LOCK_ASSERT(inp);
440fcf59617SAndrey V. Elsukov 
441fcf59617SAndrey V. Elsukov 	flags = inp->inp_sp->flags;
442fcf59617SAndrey V. Elsukov 	if (dir == IPSEC_DIR_OUTBOUND) {
443fcf59617SAndrey V. Elsukov 		sp = inp->inp_sp->sp_out;
444fcf59617SAndrey V. Elsukov 		flags &= INP_OUTBOUND_POLICY;
44588768458SSam Leffler 	} else {
446fcf59617SAndrey V. Elsukov 		sp = inp->inp_sp->sp_in;
447fcf59617SAndrey V. Elsukov 		flags &= INP_INBOUND_POLICY;
44888768458SSam Leffler 	}
44988768458SSam Leffler 	/*
450fcf59617SAndrey V. Elsukov 	 * Check flags. If we have PCB SP, just return it.
451fcf59617SAndrey V. Elsukov 	 * Otherwise we need to check that cached SP entry isn't stale.
45288768458SSam Leffler 	 */
453fcf59617SAndrey V. Elsukov 	if (flags == 0) {
454fcf59617SAndrey V. Elsukov 		if (sp == NULL)
455fcf59617SAndrey V. Elsukov 			return (NULL);
456fcf59617SAndrey V. Elsukov 		if (inp->inp_sp->genid != key_getspgen()) {
457fcf59617SAndrey V. Elsukov 			/* Invalidate the cache. */
458fcf59617SAndrey V. Elsukov 			downgrade = 0;
459fcf59617SAndrey V. Elsukov 			if (!INP_WLOCKED(inp)) {
460fcf59617SAndrey V. Elsukov 				if ((downgrade = INP_TRY_UPGRADE(inp)) == 0)
461fcf59617SAndrey V. Elsukov 					return (NULL);
462fcf59617SAndrey V. Elsukov 			}
463fcf59617SAndrey V. Elsukov 			ipsec_invalidate_cache(inp, IPSEC_DIR_OUTBOUND);
464fcf59617SAndrey V. Elsukov 			ipsec_invalidate_cache(inp, IPSEC_DIR_INBOUND);
465fcf59617SAndrey V. Elsukov 			if (downgrade != 0)
466fcf59617SAndrey V. Elsukov 				INP_DOWNGRADE(inp);
467fcf59617SAndrey V. Elsukov 			return (NULL);
468fcf59617SAndrey V. Elsukov 		}
469fcf59617SAndrey V. Elsukov 		KEYDBG(IPSEC_STAMP,
470fcf59617SAndrey V. Elsukov 		    printf("%s: PCB(%p): cache hit SP(%p)\n",
471fcf59617SAndrey V. Elsukov 		    __func__, inp, sp));
472fcf59617SAndrey V. Elsukov 		/* Return referenced cached policy */
473fcf59617SAndrey V. Elsukov 	}
474fcf59617SAndrey V. Elsukov 	key_addref(sp);
475fcf59617SAndrey V. Elsukov 	return (sp);
47688768458SSam Leffler }
47788768458SSam Leffler 
478fcf59617SAndrey V. Elsukov #ifdef INET
47988768458SSam Leffler static void
480efb10c3cSAndrey V. Elsukov ipsec4_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx,
481efb10c3cSAndrey V. Elsukov     int needport)
48288768458SSam Leffler {
483fcf59617SAndrey V. Elsukov 	uint8_t nxt;
48488768458SSam Leffler 	int off;
48588768458SSam Leffler 
486de47c390SBjoern A. Zeeb 	/* Sanity check. */
487fcf59617SAndrey V. Elsukov 	IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),
488fcf59617SAndrey V. Elsukov 	    ("packet too short"));
48988768458SSam Leffler 
49087a25418SErmal Luçi 	if (m->m_len >= sizeof (struct ip)) {
491efb10c3cSAndrey V. Elsukov 		const struct ip *ip = mtod(m, const struct ip *);
4928f134647SGleb Smirnoff 		if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
49388768458SSam Leffler 			goto done;
49488768458SSam Leffler 		off = ip->ip_hl << 2;
49588768458SSam Leffler 		nxt = ip->ip_p;
49688768458SSam Leffler 	} else {
49788768458SSam Leffler 		struct ip ih;
49888768458SSam Leffler 
49988768458SSam Leffler 		m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih);
5008f134647SGleb Smirnoff 		if (ih.ip_off & htons(IP_MF | IP_OFFMASK))
50188768458SSam Leffler 			goto done;
50288768458SSam Leffler 		off = ih.ip_hl << 2;
50388768458SSam Leffler 		nxt = ih.ip_p;
50488768458SSam Leffler 	}
50588768458SSam Leffler 
50688768458SSam Leffler 	while (off < m->m_pkthdr.len) {
50788768458SSam Leffler 		struct ip6_ext ip6e;
50888768458SSam Leffler 		struct tcphdr th;
50988768458SSam Leffler 		struct udphdr uh;
51088768458SSam Leffler 
51188768458SSam Leffler 		switch (nxt) {
51288768458SSam Leffler 		case IPPROTO_TCP:
51388768458SSam Leffler 			spidx->ul_proto = nxt;
51488768458SSam Leffler 			if (!needport)
51588768458SSam Leffler 				goto done_proto;
51688768458SSam Leffler 			if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
51788768458SSam Leffler 				goto done;
51888768458SSam Leffler 			m_copydata(m, off, sizeof (th), (caddr_t) &th);
51988768458SSam Leffler 			spidx->src.sin.sin_port = th.th_sport;
52088768458SSam Leffler 			spidx->dst.sin.sin_port = th.th_dport;
52188768458SSam Leffler 			return;
52288768458SSam Leffler 		case IPPROTO_UDP:
52388768458SSam Leffler 			spidx->ul_proto = nxt;
52488768458SSam Leffler 			if (!needport)
52588768458SSam Leffler 				goto done_proto;
52688768458SSam Leffler 			if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
52788768458SSam Leffler 				goto done;
52888768458SSam Leffler 			m_copydata(m, off, sizeof (uh), (caddr_t) &uh);
52988768458SSam Leffler 			spidx->src.sin.sin_port = uh.uh_sport;
53088768458SSam Leffler 			spidx->dst.sin.sin_port = uh.uh_dport;
53188768458SSam Leffler 			return;
53288768458SSam Leffler 		case IPPROTO_AH:
533afa3570dSSam Leffler 			if (off + sizeof(ip6e) > m->m_pkthdr.len)
53488768458SSam Leffler 				goto done;
535de47c390SBjoern A. Zeeb 			/* XXX Sigh, this works but is totally bogus. */
53688768458SSam Leffler 			m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e);
53788768458SSam Leffler 			off += (ip6e.ip6e_len + 2) << 2;
53888768458SSam Leffler 			nxt = ip6e.ip6e_nxt;
53988768458SSam Leffler 			break;
54088768458SSam Leffler 		case IPPROTO_ICMP:
54188768458SSam Leffler 		default:
542de47c390SBjoern A. Zeeb 			/* XXX Intermediate headers??? */
54388768458SSam Leffler 			spidx->ul_proto = nxt;
54488768458SSam Leffler 			goto done_proto;
54588768458SSam Leffler 		}
54688768458SSam Leffler 	}
54788768458SSam Leffler done:
54888768458SSam Leffler 	spidx->ul_proto = IPSEC_ULPROTO_ANY;
54988768458SSam Leffler done_proto:
55088768458SSam Leffler 	spidx->src.sin.sin_port = IPSEC_PORT_ANY;
55188768458SSam Leffler 	spidx->dst.sin.sin_port = IPSEC_PORT_ANY;
552fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_DUMP,
553fcf59617SAndrey V. Elsukov 	    printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL));
55488768458SSam Leffler }
55588768458SSam Leffler 
556fcf59617SAndrey V. Elsukov static void
557efb10c3cSAndrey V. Elsukov ipsec4_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx)
55888768458SSam Leffler {
55988768458SSam Leffler 
560fcf59617SAndrey V. Elsukov 	ipsec4_setsockaddrs(m, &spidx->src, &spidx->dst);
56188768458SSam Leffler 	spidx->prefs = sizeof(struct in_addr) << 3;
56288768458SSam Leffler 	spidx->prefd = sizeof(struct in_addr) << 3;
56388768458SSam Leffler }
56488768458SSam Leffler 
565fcf59617SAndrey V. Elsukov static struct secpolicy *
566*22bbefb2SAndrey V. Elsukov ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir,
567*22bbefb2SAndrey V. Elsukov     int needport)
568fcf59617SAndrey V. Elsukov {
569fcf59617SAndrey V. Elsukov 	struct secpolicyindex spidx;
570fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
571fcf59617SAndrey V. Elsukov 
572fcf59617SAndrey V. Elsukov 	sp = ipsec_getpcbpolicy(inp, dir);
573fcf59617SAndrey V. Elsukov 	if (sp == NULL && key_havesp(dir)) {
574fcf59617SAndrey V. Elsukov 		/* Make an index to look for a policy. */
575fcf59617SAndrey V. Elsukov 		ipsec4_setspidx_ipaddr(m, &spidx);
576fcf59617SAndrey V. Elsukov 		/* Fill ports in spidx if we have inpcb. */
577*22bbefb2SAndrey V. Elsukov 		ipsec4_get_ulp(m, &spidx, needport);
578fcf59617SAndrey V. Elsukov 		spidx.dir = dir;
579fcf59617SAndrey V. Elsukov 		sp = key_allocsp(&spidx, dir);
580fcf59617SAndrey V. Elsukov 	}
581fcf59617SAndrey V. Elsukov 	if (sp == NULL)		/* No SP found, use system default. */
582fcf59617SAndrey V. Elsukov 		sp = key_allocsp_default();
583fcf59617SAndrey V. Elsukov 	return (sp);
584fcf59617SAndrey V. Elsukov }
585fcf59617SAndrey V. Elsukov 
586fcf59617SAndrey V. Elsukov /*
587fcf59617SAndrey V. Elsukov  * Check security policy for *OUTBOUND* IPv4 packet.
588fcf59617SAndrey V. Elsukov  */
589fcf59617SAndrey V. Elsukov struct secpolicy *
590*22bbefb2SAndrey V. Elsukov ipsec4_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error,
591*22bbefb2SAndrey V. Elsukov     int needport)
592fcf59617SAndrey V. Elsukov {
593fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
594fcf59617SAndrey V. Elsukov 
595fcf59617SAndrey V. Elsukov 	*error = 0;
596*22bbefb2SAndrey V. Elsukov 	sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport);
597fcf59617SAndrey V. Elsukov 	if (sp != NULL)
598fcf59617SAndrey V. Elsukov 		sp = ipsec_checkpolicy(sp, inp, error);
599fcf59617SAndrey V. Elsukov 	if (sp == NULL) {
600fcf59617SAndrey V. Elsukov 		switch (*error) {
601fcf59617SAndrey V. Elsukov 		case 0: /* No IPsec required: BYPASS or NONE */
602fcf59617SAndrey V. Elsukov 			break;
603fcf59617SAndrey V. Elsukov 		case -EINVAL:
604fcf59617SAndrey V. Elsukov 			IPSECSTAT_INC(ips_out_polvio);
605fcf59617SAndrey V. Elsukov 			break;
606fcf59617SAndrey V. Elsukov 		default:
607fcf59617SAndrey V. Elsukov 			IPSECSTAT_INC(ips_out_inval);
608fcf59617SAndrey V. Elsukov 		}
609fcf59617SAndrey V. Elsukov 	}
610fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_STAMP,
611fcf59617SAndrey V. Elsukov 	    printf("%s: using SP(%p), error %d\n", __func__, sp, *error));
612fcf59617SAndrey V. Elsukov 	if (sp != NULL)
613fcf59617SAndrey V. Elsukov 		KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp));
614fcf59617SAndrey V. Elsukov 	return (sp);
615fcf59617SAndrey V. Elsukov }
616fcf59617SAndrey V. Elsukov 
617fcf59617SAndrey V. Elsukov /*
618fcf59617SAndrey V. Elsukov  * Check IPv4 packet against *INBOUND* security policy.
619fcf59617SAndrey V. Elsukov  * This function is called from tcp_input(), udp_input(),
620fcf59617SAndrey V. Elsukov  * rip_input() and sctp_input().
621fcf59617SAndrey V. Elsukov  */
622fcf59617SAndrey V. Elsukov int
623fcf59617SAndrey V. Elsukov ipsec4_in_reject(const struct mbuf *m, struct inpcb *inp)
624fcf59617SAndrey V. Elsukov {
625fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
626fcf59617SAndrey V. Elsukov 	int result;
627fcf59617SAndrey V. Elsukov 
628*22bbefb2SAndrey V. Elsukov 	sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0);
629fcf59617SAndrey V. Elsukov 	result = ipsec_in_reject(sp, inp, m);
630fcf59617SAndrey V. Elsukov 	key_freesp(&sp);
631fcf59617SAndrey V. Elsukov 	if (result != 0)
632fcf59617SAndrey V. Elsukov 		IPSECSTAT_INC(ips_in_polvio);
633fcf59617SAndrey V. Elsukov 	return (result);
634fcf59617SAndrey V. Elsukov }
635fcf59617SAndrey V. Elsukov 
636fcf59617SAndrey V. Elsukov /*
637fcf59617SAndrey V. Elsukov  * IPSEC_CAP() method implementation for IPv4.
638fcf59617SAndrey V. Elsukov  */
639fcf59617SAndrey V. Elsukov int
640fcf59617SAndrey V. Elsukov ipsec4_capability(struct mbuf *m, u_int cap)
641fcf59617SAndrey V. Elsukov {
642fcf59617SAndrey V. Elsukov 
643fcf59617SAndrey V. Elsukov 	switch (cap) {
644fcf59617SAndrey V. Elsukov 	case IPSEC_CAP_BYPASS_FILTER:
645fcf59617SAndrey V. Elsukov 		/*
646fcf59617SAndrey V. Elsukov 		 * Bypass packet filtering for packets previously handled
647fcf59617SAndrey V. Elsukov 		 * by IPsec.
648fcf59617SAndrey V. Elsukov 		 */
649fcf59617SAndrey V. Elsukov 		if (!V_ip4_filtertunnel &&
650fcf59617SAndrey V. Elsukov 		    m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL)
651fcf59617SAndrey V. Elsukov 			return (1);
652fcf59617SAndrey V. Elsukov 		return (0);
653fcf59617SAndrey V. Elsukov 	case IPSEC_CAP_OPERABLE:
654fcf59617SAndrey V. Elsukov 		/* Do we have active security policies? */
655fcf59617SAndrey V. Elsukov 		if (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
656fcf59617SAndrey V. Elsukov 		    key_havesp(IPSEC_DIR_OUTBOUND) != 0)
657fcf59617SAndrey V. Elsukov 			return (1);
658fcf59617SAndrey V. Elsukov 		return (0);
659fcf59617SAndrey V. Elsukov 	};
660fcf59617SAndrey V. Elsukov 	return (EOPNOTSUPP);
661fcf59617SAndrey V. Elsukov }
662fcf59617SAndrey V. Elsukov 
663fcf59617SAndrey V. Elsukov #endif /* INET */
664fcf59617SAndrey V. Elsukov 
66588768458SSam Leffler #ifdef INET6
66688768458SSam Leffler static void
667efb10c3cSAndrey V. Elsukov ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx,
668efb10c3cSAndrey V. Elsukov     int needport)
66988768458SSam Leffler {
67088768458SSam Leffler 	struct tcphdr th;
67188768458SSam Leffler 	struct udphdr uh;
6720e3c2be4SBjoern A. Zeeb 	struct icmp6_hdr ih;
673fcf59617SAndrey V. Elsukov 	int off, nxt;
67488768458SSam Leffler 
675fcf59617SAndrey V. Elsukov 	IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip6_hdr),
676fcf59617SAndrey V. Elsukov 	    ("packet too short"));
67788768458SSam Leffler 
678de47c390SBjoern A. Zeeb 	/* Set default. */
67988768458SSam Leffler 	spidx->ul_proto = IPSEC_ULPROTO_ANY;
680fcf59617SAndrey V. Elsukov 	spidx->src.sin6.sin6_port = IPSEC_PORT_ANY;
681fcf59617SAndrey V. Elsukov 	spidx->dst.sin6.sin6_port = IPSEC_PORT_ANY;
68288768458SSam Leffler 
68388768458SSam Leffler 	nxt = -1;
68488768458SSam Leffler 	off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
68588768458SSam Leffler 	if (off < 0 || m->m_pkthdr.len < off)
68688768458SSam Leffler 		return;
68788768458SSam Leffler 
68888768458SSam Leffler 	switch (nxt) {
68988768458SSam Leffler 	case IPPROTO_TCP:
69088768458SSam Leffler 		spidx->ul_proto = nxt;
69188768458SSam Leffler 		if (!needport)
69288768458SSam Leffler 			break;
69388768458SSam Leffler 		if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
69488768458SSam Leffler 			break;
69588768458SSam Leffler 		m_copydata(m, off, sizeof(th), (caddr_t)&th);
696fcf59617SAndrey V. Elsukov 		spidx->src.sin6.sin6_port = th.th_sport;
697fcf59617SAndrey V. Elsukov 		spidx->dst.sin6.sin6_port = th.th_dport;
69888768458SSam Leffler 		break;
69988768458SSam Leffler 	case IPPROTO_UDP:
70088768458SSam Leffler 		spidx->ul_proto = nxt;
70188768458SSam Leffler 		if (!needport)
70288768458SSam Leffler 			break;
70388768458SSam Leffler 		if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
70488768458SSam Leffler 			break;
70588768458SSam Leffler 		m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
706fcf59617SAndrey V. Elsukov 		spidx->src.sin6.sin6_port = uh.uh_sport;
707fcf59617SAndrey V. Elsukov 		spidx->dst.sin6.sin6_port = uh.uh_dport;
70888768458SSam Leffler 		break;
70988768458SSam Leffler 	case IPPROTO_ICMPV6:
7100e3c2be4SBjoern A. Zeeb 		spidx->ul_proto = nxt;
7110e3c2be4SBjoern A. Zeeb 		if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len)
7120e3c2be4SBjoern A. Zeeb 			break;
7130e3c2be4SBjoern A. Zeeb 		m_copydata(m, off, sizeof(ih), (caddr_t)&ih);
714fcf59617SAndrey V. Elsukov 		spidx->src.sin6.sin6_port = htons((uint16_t)ih.icmp6_type);
715fcf59617SAndrey V. Elsukov 		spidx->dst.sin6.sin6_port = htons((uint16_t)ih.icmp6_code);
7160e3c2be4SBjoern A. Zeeb 		break;
71788768458SSam Leffler 	default:
718de47c390SBjoern A. Zeeb 		/* XXX Intermediate headers??? */
71988768458SSam Leffler 		spidx->ul_proto = nxt;
72088768458SSam Leffler 		break;
72188768458SSam Leffler 	}
722fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_DUMP,
723fcf59617SAndrey V. Elsukov 	    printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL));
72488768458SSam Leffler }
72588768458SSam Leffler 
726fcf59617SAndrey V. Elsukov static void
727efb10c3cSAndrey V. Elsukov ipsec6_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx)
72888768458SSam Leffler {
72988768458SSam Leffler 
730fcf59617SAndrey V. Elsukov 	ipsec6_setsockaddrs(m, &spidx->src, &spidx->dst);
73188768458SSam Leffler 	spidx->prefs = sizeof(struct in6_addr) << 3;
73288768458SSam Leffler 	spidx->prefd = sizeof(struct in6_addr) << 3;
73388768458SSam Leffler }
734fcf59617SAndrey V. Elsukov 
735fcf59617SAndrey V. Elsukov static struct secpolicy *
736*22bbefb2SAndrey V. Elsukov ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir,
737*22bbefb2SAndrey V. Elsukov     int needport)
738fcf59617SAndrey V. Elsukov {
739fcf59617SAndrey V. Elsukov 	struct secpolicyindex spidx;
740fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
741fcf59617SAndrey V. Elsukov 
742fcf59617SAndrey V. Elsukov 	sp = ipsec_getpcbpolicy(inp, dir);
743fcf59617SAndrey V. Elsukov 	if (sp == NULL && key_havesp(dir)) {
744fcf59617SAndrey V. Elsukov 		/* Make an index to look for a policy. */
745fcf59617SAndrey V. Elsukov 		ipsec6_setspidx_ipaddr(m, &spidx);
746fcf59617SAndrey V. Elsukov 		/* Fill ports in spidx if we have inpcb. */
747*22bbefb2SAndrey V. Elsukov 		ipsec6_get_ulp(m, &spidx, needport);
748fcf59617SAndrey V. Elsukov 		spidx.dir = dir;
749fcf59617SAndrey V. Elsukov 		sp = key_allocsp(&spidx, dir);
750fcf59617SAndrey V. Elsukov 	}
751fcf59617SAndrey V. Elsukov 	if (sp == NULL)		/* No SP found, use system default. */
752fcf59617SAndrey V. Elsukov 		sp = key_allocsp_default();
753fcf59617SAndrey V. Elsukov 	return (sp);
754fcf59617SAndrey V. Elsukov }
755fcf59617SAndrey V. Elsukov 
756fcf59617SAndrey V. Elsukov /*
757fcf59617SAndrey V. Elsukov  * Check security policy for *OUTBOUND* IPv6 packet.
758fcf59617SAndrey V. Elsukov  */
759fcf59617SAndrey V. Elsukov struct secpolicy *
760*22bbefb2SAndrey V. Elsukov ipsec6_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error,
761*22bbefb2SAndrey V. Elsukov     int needport)
762fcf59617SAndrey V. Elsukov {
763fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
764fcf59617SAndrey V. Elsukov 
765fcf59617SAndrey V. Elsukov 	*error = 0;
766*22bbefb2SAndrey V. Elsukov 	sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport);
767fcf59617SAndrey V. Elsukov 	if (sp != NULL)
768fcf59617SAndrey V. Elsukov 		sp = ipsec_checkpolicy(sp, inp, error);
769fcf59617SAndrey V. Elsukov 	if (sp == NULL) {
770fcf59617SAndrey V. Elsukov 		switch (*error) {
771fcf59617SAndrey V. Elsukov 		case 0: /* No IPsec required: BYPASS or NONE */
772fcf59617SAndrey V. Elsukov 			break;
773fcf59617SAndrey V. Elsukov 		case -EINVAL:
774fcf59617SAndrey V. Elsukov 			IPSEC6STAT_INC(ips_out_polvio);
775fcf59617SAndrey V. Elsukov 			break;
776fcf59617SAndrey V. Elsukov 		default:
777fcf59617SAndrey V. Elsukov 			IPSEC6STAT_INC(ips_out_inval);
778fcf59617SAndrey V. Elsukov 		}
779fcf59617SAndrey V. Elsukov 	}
780fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_STAMP,
781fcf59617SAndrey V. Elsukov 	    printf("%s: using SP(%p), error %d\n", __func__, sp, *error));
782fcf59617SAndrey V. Elsukov 	if (sp != NULL)
783fcf59617SAndrey V. Elsukov 		KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp));
784fcf59617SAndrey V. Elsukov 	return (sp);
785fcf59617SAndrey V. Elsukov }
786fcf59617SAndrey V. Elsukov 
787fcf59617SAndrey V. Elsukov /*
788fcf59617SAndrey V. Elsukov  * Check IPv6 packet against inbound security policy.
789fcf59617SAndrey V. Elsukov  * This function is called from tcp6_input(), udp6_input(),
790fcf59617SAndrey V. Elsukov  * rip6_input() and sctp_input().
791fcf59617SAndrey V. Elsukov  */
792fcf59617SAndrey V. Elsukov int
793fcf59617SAndrey V. Elsukov ipsec6_in_reject(const struct mbuf *m, struct inpcb *inp)
794fcf59617SAndrey V. Elsukov {
795fcf59617SAndrey V. Elsukov 	struct secpolicy *sp;
796fcf59617SAndrey V. Elsukov 	int result;
797fcf59617SAndrey V. Elsukov 
798*22bbefb2SAndrey V. Elsukov 	sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0);
799fcf59617SAndrey V. Elsukov 	result = ipsec_in_reject(sp, inp, m);
800fcf59617SAndrey V. Elsukov 	key_freesp(&sp);
801fcf59617SAndrey V. Elsukov 	if (result)
802fcf59617SAndrey V. Elsukov 		IPSEC6STAT_INC(ips_in_polvio);
803fcf59617SAndrey V. Elsukov 	return (result);
804fcf59617SAndrey V. Elsukov }
805fcf59617SAndrey V. Elsukov 
806fcf59617SAndrey V. Elsukov /*
807fcf59617SAndrey V. Elsukov  * IPSEC_CAP() method implementation for IPv6.
808fcf59617SAndrey V. Elsukov  */
809fcf59617SAndrey V. Elsukov int
810fcf59617SAndrey V. Elsukov ipsec6_capability(struct mbuf *m, u_int cap)
811fcf59617SAndrey V. Elsukov {
812fcf59617SAndrey V. Elsukov 
813fcf59617SAndrey V. Elsukov 	switch (cap) {
814fcf59617SAndrey V. Elsukov 	case IPSEC_CAP_BYPASS_FILTER:
815fcf59617SAndrey V. Elsukov 		/*
816fcf59617SAndrey V. Elsukov 		 * Bypass packet filtering for packets previously handled
817fcf59617SAndrey V. Elsukov 		 * by IPsec.
818fcf59617SAndrey V. Elsukov 		 */
819fcf59617SAndrey V. Elsukov 		if (!V_ip6_filtertunnel &&
820fcf59617SAndrey V. Elsukov 		    m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL)
821fcf59617SAndrey V. Elsukov 			return (1);
822fcf59617SAndrey V. Elsukov 		return (0);
823fcf59617SAndrey V. Elsukov 	case IPSEC_CAP_OPERABLE:
824fcf59617SAndrey V. Elsukov 		/* Do we have active security policies? */
825fcf59617SAndrey V. Elsukov 		if (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
826fcf59617SAndrey V. Elsukov 		    key_havesp(IPSEC_DIR_OUTBOUND) != 0)
827fcf59617SAndrey V. Elsukov 			return (1);
828fcf59617SAndrey V. Elsukov 		return (0);
829fcf59617SAndrey V. Elsukov 	};
830fcf59617SAndrey V. Elsukov 	return (EOPNOTSUPP);
831fcf59617SAndrey V. Elsukov }
832fcf59617SAndrey V. Elsukov #endif /* INET6 */
83388768458SSam Leffler 
834ef91a976SAndrey V. Elsukov int
835ef91a976SAndrey V. Elsukov ipsec_run_hhooks(struct ipsec_ctx_data *ctx, int type)
836ef91a976SAndrey V. Elsukov {
837ef91a976SAndrey V. Elsukov 	int idx;
838ef91a976SAndrey V. Elsukov 
839ef91a976SAndrey V. Elsukov 	switch (ctx->af) {
840ef91a976SAndrey V. Elsukov #ifdef INET
841ef91a976SAndrey V. Elsukov 	case AF_INET:
842ef91a976SAndrey V. Elsukov 		idx = HHOOK_IPSEC_INET;
843ef91a976SAndrey V. Elsukov 		break;
844ef91a976SAndrey V. Elsukov #endif
845ef91a976SAndrey V. Elsukov #ifdef INET6
846ef91a976SAndrey V. Elsukov 	case AF_INET6:
847ef91a976SAndrey V. Elsukov 		idx = HHOOK_IPSEC_INET6;
848ef91a976SAndrey V. Elsukov 		break;
849ef91a976SAndrey V. Elsukov #endif
850ef91a976SAndrey V. Elsukov 	default:
851ef91a976SAndrey V. Elsukov 		return (EPFNOSUPPORT);
852ef91a976SAndrey V. Elsukov 	}
853ef91a976SAndrey V. Elsukov 	if (type == HHOOK_TYPE_IPSEC_IN)
854ef91a976SAndrey V. Elsukov 		HHOOKS_RUN_IF(V_ipsec_hhh_in[idx], ctx, NULL);
855ef91a976SAndrey V. Elsukov 	else
856ef91a976SAndrey V. Elsukov 		HHOOKS_RUN_IF(V_ipsec_hhh_out[idx], ctx, NULL);
857ef91a976SAndrey V. Elsukov 	if (*ctx->mp == NULL)
858ef91a976SAndrey V. Elsukov 		return (EACCES);
859ef91a976SAndrey V. Elsukov 	return (0);
860ef91a976SAndrey V. Elsukov }
861ef91a976SAndrey V. Elsukov 
86288768458SSam Leffler /*
863de47c390SBjoern A. Zeeb  * Return current level.
86488768458SSam Leffler  * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned.
86588768458SSam Leffler  */
86688768458SSam Leffler u_int
867fcf59617SAndrey V. Elsukov ipsec_get_reqlevel(struct secpolicy *sp, u_int idx)
86888768458SSam Leffler {
869fcf59617SAndrey V. Elsukov 	struct ipsecrequest *isr;
87088768458SSam Leffler 	u_int esp_trans_deflev, esp_net_deflev;
87188768458SSam Leffler 	u_int ah_trans_deflev, ah_net_deflev;
872fcf59617SAndrey V. Elsukov 	u_int level = 0;
87388768458SSam Leffler 
874fcf59617SAndrey V. Elsukov 	IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx));
875de47c390SBjoern A. Zeeb /* XXX Note that we have ipseclog() expanded here - code sync issue. */
87688768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \
877fcf59617SAndrey V. Elsukov 	(((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE &&	\
878fcf59617SAndrey V. Elsukov 	  (lev) != IPSEC_LEVEL_UNIQUE)					\
879fcf59617SAndrey V. Elsukov 		? (V_ipsec_debug  ?					\
880fcf59617SAndrey V. Elsukov 		log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\
881fcf59617SAndrey V. Elsukov 		(lev), IPSEC_LEVEL_REQUIRE) : 0),			\
882fcf59617SAndrey V. Elsukov 		(lev) = IPSEC_LEVEL_REQUIRE, (lev) : (lev))
883fcf59617SAndrey V. Elsukov 
884fcf59617SAndrey V. Elsukov 	/*
885fcf59617SAndrey V. Elsukov 	 * IPsec VTI uses unique security policy with fake spidx filled
886fcf59617SAndrey V. Elsukov 	 * with zeroes. Just return IPSEC_LEVEL_REQUIRE instead of doing
887fcf59617SAndrey V. Elsukov 	 * full level lookup for such policies.
888fcf59617SAndrey V. Elsukov 	 */
889fcf59617SAndrey V. Elsukov 	if (sp->state == IPSEC_SPSTATE_IFNET) {
890fcf59617SAndrey V. Elsukov 		IPSEC_ASSERT(sp->req[idx]->level == IPSEC_LEVEL_UNIQUE,
891fcf59617SAndrey V. Elsukov 		    ("Wrong IPsec request level %d", sp->req[idx]->level));
892fcf59617SAndrey V. Elsukov 		return (IPSEC_LEVEL_REQUIRE);
893fcf59617SAndrey V. Elsukov 	}
89488768458SSam Leffler 
895de47c390SBjoern A. Zeeb 	/* Set default level. */
896fcf59617SAndrey V. Elsukov 	switch (sp->spidx.src.sa.sa_family) {
89788768458SSam Leffler #ifdef INET
89888768458SSam Leffler 	case AF_INET:
899603724d3SBjoern A. Zeeb 		esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev);
900603724d3SBjoern A. Zeeb 		esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev);
901603724d3SBjoern A. Zeeb 		ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev);
902603724d3SBjoern A. Zeeb 		ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev);
90388768458SSam Leffler 		break;
90488768458SSam Leffler #endif
90588768458SSam Leffler #ifdef INET6
90688768458SSam Leffler 	case AF_INET6:
907603724d3SBjoern A. Zeeb 		esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev);
908603724d3SBjoern A. Zeeb 		esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev);
909603724d3SBjoern A. Zeeb 		ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev);
910603724d3SBjoern A. Zeeb 		ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev);
91188768458SSam Leffler 		break;
91288768458SSam Leffler #endif /* INET6 */
91388768458SSam Leffler 	default:
9149ffa9677SSam Leffler 		panic("%s: unknown af %u",
915fcf59617SAndrey V. Elsukov 			__func__, sp->spidx.src.sa.sa_family);
91688768458SSam Leffler 	}
91788768458SSam Leffler 
91888768458SSam Leffler #undef IPSEC_CHECK_DEFAULT
91988768458SSam Leffler 
920fcf59617SAndrey V. Elsukov 	isr = sp->req[idx];
921de47c390SBjoern A. Zeeb 	/* Set level. */
92288768458SSam Leffler 	switch (isr->level) {
92388768458SSam Leffler 	case IPSEC_LEVEL_DEFAULT:
92488768458SSam Leffler 		switch (isr->saidx.proto) {
92588768458SSam Leffler 		case IPPROTO_ESP:
92688768458SSam Leffler 			if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
92788768458SSam Leffler 				level = esp_net_deflev;
92888768458SSam Leffler 			else
92988768458SSam Leffler 				level = esp_trans_deflev;
93088768458SSam Leffler 			break;
93188768458SSam Leffler 		case IPPROTO_AH:
93288768458SSam Leffler 			if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
93388768458SSam Leffler 				level = ah_net_deflev;
93488768458SSam Leffler 			else
93588768458SSam Leffler 				level = ah_trans_deflev;
9368381996eSSam Leffler 			break;
93788768458SSam Leffler 		case IPPROTO_IPCOMP:
93888768458SSam Leffler 			/*
939de47c390SBjoern A. Zeeb 			 * We don't really care, as IPcomp document says that
940de47c390SBjoern A. Zeeb 			 * we shouldn't compress small packets.
94188768458SSam Leffler 			 */
94288768458SSam Leffler 			level = IPSEC_LEVEL_USE;
94388768458SSam Leffler 			break;
94488768458SSam Leffler 		default:
9459ffa9677SSam Leffler 			panic("%s: Illegal protocol defined %u\n", __func__,
94688768458SSam Leffler 				isr->saidx.proto);
94788768458SSam Leffler 		}
94888768458SSam Leffler 		break;
94988768458SSam Leffler 
95088768458SSam Leffler 	case IPSEC_LEVEL_USE:
95188768458SSam Leffler 	case IPSEC_LEVEL_REQUIRE:
95288768458SSam Leffler 		level = isr->level;
95388768458SSam Leffler 		break;
95488768458SSam Leffler 	case IPSEC_LEVEL_UNIQUE:
95588768458SSam Leffler 		level = IPSEC_LEVEL_REQUIRE;
95688768458SSam Leffler 		break;
95788768458SSam Leffler 
95888768458SSam Leffler 	default:
9599ffa9677SSam Leffler 		panic("%s: Illegal IPsec level %u\n", __func__, isr->level);
96088768458SSam Leffler 	}
96188768458SSam Leffler 
962de47c390SBjoern A. Zeeb 	return (level);
96388768458SSam Leffler }
96488768458SSam Leffler 
965fcf59617SAndrey V. Elsukov static int
966fcf59617SAndrey V. Elsukov ipsec_check_history(const struct mbuf *m, struct secpolicy *sp, u_int idx)
967fcf59617SAndrey V. Elsukov {
968fcf59617SAndrey V. Elsukov 	struct xform_history *xh;
969fcf59617SAndrey V. Elsukov 	struct m_tag *mtag;
970fcf59617SAndrey V. Elsukov 
971fcf59617SAndrey V. Elsukov 	mtag = NULL;
972fcf59617SAndrey V. Elsukov 	while ((mtag = m_tag_find(__DECONST(struct mbuf *, m),
973fcf59617SAndrey V. Elsukov 	    PACKET_TAG_IPSEC_IN_DONE, mtag)) != NULL) {
974fcf59617SAndrey V. Elsukov 		xh = (struct xform_history *)(mtag + 1);
975fcf59617SAndrey V. Elsukov 		KEYDBG(IPSEC_DATA,
976fcf59617SAndrey V. Elsukov 		    char buf[IPSEC_ADDRSTRLEN];
977fcf59617SAndrey V. Elsukov 		    printf("%s: mode %s proto %u dst %s\n", __func__,
978fcf59617SAndrey V. Elsukov 			kdebug_secasindex_mode(xh->mode), xh->proto,
979fcf59617SAndrey V. Elsukov 			ipsec_address(&xh->dst, buf, sizeof(buf))));
980fcf59617SAndrey V. Elsukov 		if (xh->proto != sp->req[idx]->saidx.proto)
981fcf59617SAndrey V. Elsukov 			continue;
982fcf59617SAndrey V. Elsukov 		/* If SA had IPSEC_MODE_ANY, consider this as match. */
983fcf59617SAndrey V. Elsukov 		if (xh->mode != sp->req[idx]->saidx.mode &&
984fcf59617SAndrey V. Elsukov 		    xh->mode != IPSEC_MODE_ANY)
985fcf59617SAndrey V. Elsukov 			continue;
986fcf59617SAndrey V. Elsukov 		/*
987fcf59617SAndrey V. Elsukov 		 * For transport mode IPsec request doesn't contain
988fcf59617SAndrey V. Elsukov 		 * addresses. We need to use address from spidx.
989fcf59617SAndrey V. Elsukov 		 */
990fcf59617SAndrey V. Elsukov 		if (sp->req[idx]->saidx.mode == IPSEC_MODE_TRANSPORT) {
991fcf59617SAndrey V. Elsukov 			if (key_sockaddrcmp_withmask(&xh->dst.sa,
992fcf59617SAndrey V. Elsukov 			    &sp->spidx.dst.sa, sp->spidx.prefd) != 0)
993fcf59617SAndrey V. Elsukov 				continue;
994fcf59617SAndrey V. Elsukov 		} else {
995fcf59617SAndrey V. Elsukov 			if (key_sockaddrcmp(&xh->dst.sa,
996fcf59617SAndrey V. Elsukov 			    &sp->req[idx]->saidx.dst.sa, 0) != 0)
997fcf59617SAndrey V. Elsukov 				continue;
998fcf59617SAndrey V. Elsukov 		}
999fcf59617SAndrey V. Elsukov 		return (0); /* matched */
1000fcf59617SAndrey V. Elsukov 	}
1001fcf59617SAndrey V. Elsukov 	return (1);
1002fcf59617SAndrey V. Elsukov }
1003fcf59617SAndrey V. Elsukov 
100488768458SSam Leffler /*
100588768458SSam Leffler  * Check security policy requirements against the actual
100688768458SSam Leffler  * packet contents.  Return one if the packet should be
100788768458SSam Leffler  * reject as "invalid"; otherwiser return zero to have the
100888768458SSam Leffler  * packet treated as "valid".
100988768458SSam Leffler  *
101088768458SSam Leffler  * OUT:
101188768458SSam Leffler  *	0: valid
101288768458SSam Leffler  *	1: invalid
101388768458SSam Leffler  */
1014a9b9f6b6SAndrey V. Elsukov static int
1015fcf59617SAndrey V. Elsukov ipsec_in_reject(struct secpolicy *sp, struct inpcb *inp, const struct mbuf *m)
101688768458SSam Leffler {
1017fcf59617SAndrey V. Elsukov 	int i;
101888768458SSam Leffler 
1019fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_STAMP,
1020fcf59617SAndrey V. Elsukov 	    printf("%s: PCB(%p): using SP(%p)\n", __func__, inp, sp));
1021fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp));
1022fcf59617SAndrey V. Elsukov 
1023fcf59617SAndrey V. Elsukov 	if (inp != NULL && inp->inp_sp != NULL && inp->inp_sp->sp_in == NULL)
1024fcf59617SAndrey V. Elsukov 		ipsec_cachepolicy(inp, sp, IPSEC_DIR_INBOUND);
102588768458SSam Leffler 
1026de47c390SBjoern A. Zeeb 	/* Check policy. */
102788768458SSam Leffler 	switch (sp->policy) {
102888768458SSam Leffler 	case IPSEC_POLICY_DISCARD:
1029de47c390SBjoern A. Zeeb 		return (1);
103088768458SSam Leffler 	case IPSEC_POLICY_BYPASS:
103188768458SSam Leffler 	case IPSEC_POLICY_NONE:
1032de47c390SBjoern A. Zeeb 		return (0);
103388768458SSam Leffler 	}
103488768458SSam Leffler 
10359ffa9677SSam Leffler 	IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC,
10369ffa9677SSam Leffler 		("invalid policy %u", sp->policy));
103788768458SSam Leffler 
1038fcf59617SAndrey V. Elsukov 	/*
1039fcf59617SAndrey V. Elsukov 	 * ipsec[46]_common_input_cb after each transform adds
1040fcf59617SAndrey V. Elsukov 	 * PACKET_TAG_IPSEC_IN_DONE mbuf tag. It contains SPI, proto, mode
1041fcf59617SAndrey V. Elsukov 	 * and destination address from saidx. We can compare info from
1042fcf59617SAndrey V. Elsukov 	 * these tags with requirements in SP.
1043fcf59617SAndrey V. Elsukov 	 */
1044fcf59617SAndrey V. Elsukov 	for (i = 0; i < sp->tcount; i++) {
1045fcf59617SAndrey V. Elsukov 		/*
1046fcf59617SAndrey V. Elsukov 		 * Do not check IPcomp, since IPcomp document
1047fcf59617SAndrey V. Elsukov 		 * says that we shouldn't compress small packets.
1048fcf59617SAndrey V. Elsukov 		 * IPComp policy should always be treated as being
1049fcf59617SAndrey V. Elsukov 		 * in "use" level.
1050fcf59617SAndrey V. Elsukov 		 */
1051fcf59617SAndrey V. Elsukov 		if (sp->req[i]->saidx.proto == IPPROTO_IPCOMP ||
1052fcf59617SAndrey V. Elsukov 		    ipsec_get_reqlevel(sp, i) != IPSEC_LEVEL_REQUIRE)
105388768458SSam Leffler 			continue;
1054fcf59617SAndrey V. Elsukov 		if (V_check_policy_history != 0 &&
1055fcf59617SAndrey V. Elsukov 		    ipsec_check_history(m, sp, i) != 0)
1056fcf59617SAndrey V. Elsukov 			return (1);
1057fcf59617SAndrey V. Elsukov 		else switch (sp->req[i]->saidx.proto) {
105888768458SSam Leffler 		case IPPROTO_ESP:
105988768458SSam Leffler 			if ((m->m_flags & M_DECRYPTED) == 0) {
1060fcf59617SAndrey V. Elsukov 				KEYDBG(IPSEC_DUMP,
10619ffa9677SSam Leffler 				    printf("%s: ESP m_flags:%x\n", __func__,
106288768458SSam Leffler 					    m->m_flags));
1063de47c390SBjoern A. Zeeb 				return (1);
106488768458SSam Leffler 			}
106588768458SSam Leffler 			break;
106688768458SSam Leffler 		case IPPROTO_AH:
106788768458SSam Leffler 			if ((m->m_flags & M_AUTHIPHDR) == 0) {
1068fcf59617SAndrey V. Elsukov 				KEYDBG(IPSEC_DUMP,
10699ffa9677SSam Leffler 				    printf("%s: AH m_flags:%x\n", __func__,
107088768458SSam Leffler 					    m->m_flags));
1071de47c390SBjoern A. Zeeb 				return (1);
107288768458SSam Leffler 			}
107388768458SSam Leffler 			break;
107488768458SSam Leffler 		}
107588768458SSam Leffler 	}
1076de47c390SBjoern A. Zeeb 	return (0);		/* Valid. */
107788768458SSam Leffler }
107888768458SSam Leffler 
1079a91150daSAndrey V. Elsukov /*
1080de47c390SBjoern A. Zeeb  * Compute the byte size to be occupied by IPsec header.
1081de47c390SBjoern A. Zeeb  * In case it is tunnelled, it includes the size of outer IP header.
108288768458SSam Leffler  */
108388768458SSam Leffler static size_t
108497aa4a51SBjoern A. Zeeb ipsec_hdrsiz_internal(struct secpolicy *sp)
108588768458SSam Leffler {
10861f8bd75eSBjoern A. Zeeb 	size_t size;
1087fcf59617SAndrey V. Elsukov 	int i;
108888768458SSam Leffler 
1089fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_STAMP, printf("%s: using SP(%p)\n", __func__, sp));
1090fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp));
109188768458SSam Leffler 
109288768458SSam Leffler 	switch (sp->policy) {
109388768458SSam Leffler 	case IPSEC_POLICY_DISCARD:
109488768458SSam Leffler 	case IPSEC_POLICY_BYPASS:
109588768458SSam Leffler 	case IPSEC_POLICY_NONE:
1096de47c390SBjoern A. Zeeb 		return (0);
109788768458SSam Leffler 	}
109888768458SSam Leffler 
10999ffa9677SSam Leffler 	IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC,
11009ffa9677SSam Leffler 		("invalid policy %u", sp->policy));
110188768458SSam Leffler 
1102fcf59617SAndrey V. Elsukov 	/*
1103fcf59617SAndrey V. Elsukov 	 * XXX: for each transform we need to lookup suitable SA
1104fcf59617SAndrey V. Elsukov 	 * and use info from SA to calculate headers size.
1105fcf59617SAndrey V. Elsukov 	 * XXX: for NAT-T we need to cosider UDP header size.
1106fcf59617SAndrey V. Elsukov 	 */
11071f8bd75eSBjoern A. Zeeb 	size = 0;
1108fcf59617SAndrey V. Elsukov 	for (i = 0; i < sp->tcount; i++) {
1109fcf59617SAndrey V. Elsukov 		switch (sp->req[i]->saidx.proto) {
111088768458SSam Leffler 		case IPPROTO_ESP:
1111fcf59617SAndrey V. Elsukov 			size += esp_hdrsiz(NULL);
111288768458SSam Leffler 			break;
111388768458SSam Leffler 		case IPPROTO_AH:
1114fcf59617SAndrey V. Elsukov 			size += ah_hdrsiz(NULL);
111588768458SSam Leffler 			break;
111688768458SSam Leffler 		case IPPROTO_IPCOMP:
1117fcf59617SAndrey V. Elsukov 			size += sizeof(struct ipcomp);
111888768458SSam Leffler 			break;
111988768458SSam Leffler 		}
112088768458SSam Leffler 
1121fcf59617SAndrey V. Elsukov 		if (sp->req[i]->saidx.mode == IPSEC_MODE_TUNNEL) {
1122fcf59617SAndrey V. Elsukov 			switch (sp->req[i]->saidx.dst.sa.sa_family) {
1123fcf59617SAndrey V. Elsukov #ifdef INET
112488768458SSam Leffler 			case AF_INET:
1125fcf59617SAndrey V. Elsukov 				size += sizeof(struct ip);
112688768458SSam Leffler 				break;
1127fcf59617SAndrey V. Elsukov #endif
112888768458SSam Leffler #ifdef INET6
112988768458SSam Leffler 			case AF_INET6:
1130fcf59617SAndrey V. Elsukov 				size += sizeof(struct ip6_hdr);
113188768458SSam Leffler 				break;
113288768458SSam Leffler #endif
113388768458SSam Leffler 			default:
11349ffa9677SSam Leffler 				ipseclog((LOG_ERR, "%s: unknown AF %d in "
11359ffa9677SSam Leffler 				    "IPsec tunnel SA\n", __func__,
1136fcf59617SAndrey V. Elsukov 				    sp->req[i]->saidx.dst.sa.sa_family));
113788768458SSam Leffler 				break;
113888768458SSam Leffler 			}
113988768458SSam Leffler 		}
114088768458SSam Leffler 	}
11411f8bd75eSBjoern A. Zeeb 	return (size);
114288768458SSam Leffler }
114388768458SSam Leffler 
114497aa4a51SBjoern A. Zeeb /*
1145fcf59617SAndrey V. Elsukov  * Compute ESP/AH header size for protocols with PCB, including
1146fcf59617SAndrey V. Elsukov  * outer IP header. Currently only tcp_output() uses it.
114797aa4a51SBjoern A. Zeeb  */
114888768458SSam Leffler size_t
1149fcf59617SAndrey V. Elsukov ipsec_hdrsiz_inpcb(struct inpcb *inp)
115088768458SSam Leffler {
1151fcf59617SAndrey V. Elsukov 	struct secpolicyindex spidx;
115288768458SSam Leffler 	struct secpolicy *sp;
1153fcf59617SAndrey V. Elsukov 	size_t sz;
115488768458SSam Leffler 
1155fcf59617SAndrey V. Elsukov 	sp = ipsec_getpcbpolicy(inp, IPSEC_DIR_OUTBOUND);
1156fcf59617SAndrey V. Elsukov 	if (sp == NULL && key_havesp(IPSEC_DIR_OUTBOUND)) {
1157fcf59617SAndrey V. Elsukov 		ipsec_setspidx_inpcb(inp, &spidx, IPSEC_DIR_OUTBOUND);
1158fcf59617SAndrey V. Elsukov 		sp = key_allocsp(&spidx, IPSEC_DIR_OUTBOUND);
115988768458SSam Leffler 	}
1160fcf59617SAndrey V. Elsukov 	if (sp == NULL)
1161fcf59617SAndrey V. Elsukov 		sp = key_allocsp_default();
1162fcf59617SAndrey V. Elsukov 	sz = ipsec_hdrsiz_internal(sp);
1163fcf59617SAndrey V. Elsukov 	key_freesp(&sp);
1164fcf59617SAndrey V. Elsukov 	return (sz);
116588768458SSam Leffler }
116688768458SSam Leffler 
116788768458SSam Leffler /*
116888768458SSam Leffler  * Check the variable replay window.
116988768458SSam Leffler  * ipsec_chkreplay() performs replay check before ICV verification.
117088768458SSam Leffler  * ipsec_updatereplay() updates replay bitmap.  This must be called after
117188768458SSam Leffler  * ICV verification (it also performs replay check, which is usually done
117288768458SSam Leffler  * beforehand).
117388768458SSam Leffler  * 0 (zero) is returned if packet disallowed, 1 if packet permitted.
117488768458SSam Leffler  *
1175bf435626SFabien Thomas  * Based on RFC 6479. Blocks are 32 bits unsigned integers
117688768458SSam Leffler  */
1177bf435626SFabien Thomas 
1178bf435626SFabien Thomas #define IPSEC_BITMAP_INDEX_MASK(w)	(w - 1)
1179bf435626SFabien Thomas #define IPSEC_REDUNDANT_BIT_SHIFTS	5
1180bf435626SFabien Thomas #define IPSEC_REDUNDANT_BITS		(1 << IPSEC_REDUNDANT_BIT_SHIFTS)
1181bf435626SFabien Thomas #define IPSEC_BITMAP_LOC_MASK		(IPSEC_REDUNDANT_BITS - 1)
1182bf435626SFabien Thomas 
118388768458SSam Leffler int
1184fcf59617SAndrey V. Elsukov ipsec_chkreplay(uint32_t seq, struct secasvar *sav)
118588768458SSam Leffler {
118688768458SSam Leffler 	const struct secreplay *replay;
1187fcf59617SAndrey V. Elsukov 	uint32_t wsizeb;		/* Constant: window size. */
1188fcf59617SAndrey V. Elsukov 	int index, bit_location;
118988768458SSam Leffler 
11909ffa9677SSam Leffler 	IPSEC_ASSERT(sav != NULL, ("Null SA"));
11919ffa9677SSam Leffler 	IPSEC_ASSERT(sav->replay != NULL, ("Null replay state"));
119288768458SSam Leffler 
119388768458SSam Leffler 	replay = sav->replay;
119488768458SSam Leffler 
1195bf435626SFabien Thomas 	/* No need to check replay if disabled. */
119688768458SSam Leffler 	if (replay->wsize == 0)
1197fcf59617SAndrey V. Elsukov 		return (1);
119888768458SSam Leffler 
1199de47c390SBjoern A. Zeeb 	/* Constant. */
120088768458SSam Leffler 	wsizeb = replay->wsize << 3;
120188768458SSam Leffler 
1202de47c390SBjoern A. Zeeb 	/* Sequence number of 0 is invalid. */
120388768458SSam Leffler 	if (seq == 0)
1204fcf59617SAndrey V. Elsukov 		return (0);
120588768458SSam Leffler 
1206de47c390SBjoern A. Zeeb 	/* First time is always okay. */
120788768458SSam Leffler 	if (replay->count == 0)
1208fcf59617SAndrey V. Elsukov 		return (1);
120988768458SSam Leffler 
1210de47c390SBjoern A. Zeeb 	/* Larger sequences are okay. */
1211bf435626SFabien Thomas 	if (seq > replay->lastseq)
1212fcf59617SAndrey V. Elsukov 		return (1);
121388768458SSam Leffler 
1214de47c390SBjoern A. Zeeb 	/* Over range to check, i.e. too old or wrapped. */
1215bf435626SFabien Thomas 	if (replay->lastseq - seq >= wsizeb)
1216fcf59617SAndrey V. Elsukov 		return (0);
121788768458SSam Leffler 
1218bf435626SFabien Thomas 	/* The sequence is inside the sliding window
1219bf435626SFabien Thomas 	 * now check the bit in the bitmap
1220bf435626SFabien Thomas 	 * bit location only depends on the sequence number
1221bf435626SFabien Thomas 	 */
1222bf435626SFabien Thomas 	bit_location = seq & IPSEC_BITMAP_LOC_MASK;
1223bf435626SFabien Thomas 	index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS)
1224bf435626SFabien Thomas 		& IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size);
122588768458SSam Leffler 
1226de47c390SBjoern A. Zeeb 	/* This packet already seen? */
1227bf435626SFabien Thomas 	if ((replay->bitmap)[index] & (1 << bit_location))
1228fcf59617SAndrey V. Elsukov 		return (0);
1229fcf59617SAndrey V. Elsukov 	return (1);
123088768458SSam Leffler }
123188768458SSam Leffler 
123288768458SSam Leffler /*
1233de47c390SBjoern A. Zeeb  * Check replay counter whether to update or not.
123488768458SSam Leffler  * OUT:	0:	OK
123588768458SSam Leffler  *	1:	NG
123688768458SSam Leffler  */
123788768458SSam Leffler int
1238fcf59617SAndrey V. Elsukov ipsec_updatereplay(uint32_t seq, struct secasvar *sav)
123988768458SSam Leffler {
1240962ac6c7SAndrey V. Elsukov 	char buf[128];
124188768458SSam Leffler 	struct secreplay *replay;
1242fcf59617SAndrey V. Elsukov 	uint32_t wsizeb;		/* Constant: window size. */
1243fcf59617SAndrey V. Elsukov 	int diff, index, bit_location;
124488768458SSam Leffler 
12459ffa9677SSam Leffler 	IPSEC_ASSERT(sav != NULL, ("Null SA"));
12469ffa9677SSam Leffler 	IPSEC_ASSERT(sav->replay != NULL, ("Null replay state"));
124788768458SSam Leffler 
124888768458SSam Leffler 	replay = sav->replay;
124988768458SSam Leffler 
125088768458SSam Leffler 	if (replay->wsize == 0)
1251de47c390SBjoern A. Zeeb 		goto ok;	/* No need to check replay. */
125288768458SSam Leffler 
1253de47c390SBjoern A. Zeeb 	/* Constant. */
125488768458SSam Leffler 	wsizeb = replay->wsize << 3;
125588768458SSam Leffler 
1256de47c390SBjoern A. Zeeb 	/* Sequence number of 0 is invalid. */
125788768458SSam Leffler 	if (seq == 0)
1258fcf59617SAndrey V. Elsukov 		return (1);
125988768458SSam Leffler 
1260bf435626SFabien Thomas 	/* The packet is too old, no need to update */
1261bf435626SFabien Thomas 	if (wsizeb + seq < replay->lastseq)
126288768458SSam Leffler 		goto ok;
126388768458SSam Leffler 
1264bf435626SFabien Thomas 	/* Now update the bit */
1265bf435626SFabien Thomas 	index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS);
1266bf435626SFabien Thomas 
1267bf435626SFabien Thomas 	/* First check if the sequence number is in the range */
126888768458SSam Leffler 	if (seq > replay->lastseq) {
1269bf435626SFabien Thomas 		int id;
1270bf435626SFabien Thomas 		int index_cur = replay->lastseq >> IPSEC_REDUNDANT_BIT_SHIFTS;
127188768458SSam Leffler 
1272bf435626SFabien Thomas 		diff = index - index_cur;
1273bf435626SFabien Thomas 		if (diff > replay->bitmap_size) {
1274bf435626SFabien Thomas 			/* something unusual in this case */
1275bf435626SFabien Thomas 			diff = replay->bitmap_size;
127688768458SSam Leffler 		}
1277bf435626SFabien Thomas 
1278bf435626SFabien Thomas 		for (id = 0; id < diff; ++id) {
1279bf435626SFabien Thomas 			replay->bitmap[(id + index_cur + 1)
1280bf435626SFabien Thomas 			& IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size)] = 0;
1281bf435626SFabien Thomas 		}
1282bf435626SFabien Thomas 
128388768458SSam Leffler 		replay->lastseq = seq;
128488768458SSam Leffler 	}
128588768458SSam Leffler 
1286bf435626SFabien Thomas 	index &= IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size);
1287bf435626SFabien Thomas 	bit_location = seq & IPSEC_BITMAP_LOC_MASK;
1288bf435626SFabien Thomas 
1289bf435626SFabien Thomas 	/* this packet has already been received */
1290bf435626SFabien Thomas 	if (replay->bitmap[index] & (1 << bit_location))
1291fcf59617SAndrey V. Elsukov 		return (1);
1292bf435626SFabien Thomas 
1293bf435626SFabien Thomas 	replay->bitmap[index] |= (1 << bit_location);
1294bf435626SFabien Thomas 
129588768458SSam Leffler ok:
129688768458SSam Leffler 	if (replay->count == ~0) {
129788768458SSam Leffler 
1298de47c390SBjoern A. Zeeb 		/* Set overflow flag. */
129988768458SSam Leffler 		replay->overflow++;
130088768458SSam Leffler 
1301de47c390SBjoern A. Zeeb 		/* Don't increment, no more packets accepted. */
1302fcf59617SAndrey V. Elsukov 		if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
1303fcf59617SAndrey V. Elsukov 			if (sav->sah->saidx.proto == IPPROTO_AH)
1304fcf59617SAndrey V. Elsukov 				AHSTAT_INC(ahs_wrap);
1305fcf59617SAndrey V. Elsukov 			else if (sav->sah->saidx.proto == IPPROTO_ESP)
1306fcf59617SAndrey V. Elsukov 				ESPSTAT_INC(esps_wrap);
1307fcf59617SAndrey V. Elsukov 			return (1);
1308fcf59617SAndrey V. Elsukov 		}
130988768458SSam Leffler 
13109ffa9677SSam Leffler 		ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n",
1311962ac6c7SAndrey V. Elsukov 		    __func__, replay->overflow,
1312fcf59617SAndrey V. Elsukov 		    ipsec_sa2str(sav, buf, sizeof(buf))));
1313fcf59617SAndrey V. Elsukov 	}
1314fcf59617SAndrey V. Elsukov 	return (0);
131588768458SSam Leffler }
131688768458SSam Leffler 
1317fcf59617SAndrey V. Elsukov int
1318fcf59617SAndrey V. Elsukov ipsec_updateid(struct secasvar *sav, uint64_t *new, uint64_t *old)
1319fcf59617SAndrey V. Elsukov {
1320fcf59617SAndrey V. Elsukov 	uint64_t tmp;
132188768458SSam Leffler 
1322fcf59617SAndrey V. Elsukov 	/*
1323fcf59617SAndrey V. Elsukov 	 * tdb_cryptoid is initialized by xform_init().
1324fcf59617SAndrey V. Elsukov 	 * Then it can be changed only when some crypto error occurred or
1325fcf59617SAndrey V. Elsukov 	 * when SA is deleted. We stored used cryptoid in the xform_data
1326fcf59617SAndrey V. Elsukov 	 * structure. In case when crypto error occurred and crypto
1327fcf59617SAndrey V. Elsukov 	 * subsystem has reinited the session, it returns new cryptoid
1328fcf59617SAndrey V. Elsukov 	 * and EAGAIN error code.
1329fcf59617SAndrey V. Elsukov 	 *
1330fcf59617SAndrey V. Elsukov 	 * This function will be called when we got EAGAIN from crypto
1331fcf59617SAndrey V. Elsukov 	 * subsystem.
1332fcf59617SAndrey V. Elsukov 	 * *new is cryptoid that was returned by crypto subsystem in
1333fcf59617SAndrey V. Elsukov 	 * the crp_sid.
1334fcf59617SAndrey V. Elsukov 	 * *old is the original cryptoid that we stored in xform_data.
1335fcf59617SAndrey V. Elsukov 	 *
1336fcf59617SAndrey V. Elsukov 	 * For first failed request *old == sav->tdb_cryptoid, then
1337fcf59617SAndrey V. Elsukov 	 * we update sav->tdb_cryptoid and redo crypto_dispatch().
1338fcf59617SAndrey V. Elsukov 	 * For next failed request *old != sav->tdb_cryptoid, then
1339fcf59617SAndrey V. Elsukov 	 * we store cryptoid from first request into the *new variable
1340fcf59617SAndrey V. Elsukov 	 * and crp_sid from this second session will be returned via
1341fcf59617SAndrey V. Elsukov 	 * *old pointer, so caller can release second session.
1342fcf59617SAndrey V. Elsukov 	 *
1343fcf59617SAndrey V. Elsukov 	 * XXXAE: check this more carefully.
1344fcf59617SAndrey V. Elsukov 	 */
1345fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_STAMP,
1346fcf59617SAndrey V. Elsukov 	    printf("%s: SA(%p) moves cryptoid %jd -> %jd\n",
1347fcf59617SAndrey V. Elsukov 		__func__, sav, (uintmax_t)(*old), (uintmax_t)(*new)));
1348fcf59617SAndrey V. Elsukov 	KEYDBG(IPSEC_DATA, kdebug_secasv(sav));
1349fcf59617SAndrey V. Elsukov 	SECASVAR_LOCK(sav);
1350fcf59617SAndrey V. Elsukov 	if (sav->tdb_cryptoid != *old) {
1351fcf59617SAndrey V. Elsukov 		/* cryptoid was already updated */
1352fcf59617SAndrey V. Elsukov 		tmp = *new;
1353fcf59617SAndrey V. Elsukov 		*new = sav->tdb_cryptoid;
1354fcf59617SAndrey V. Elsukov 		*old = tmp;
1355bf435626SFabien Thomas 		SECASVAR_UNLOCK(sav);
1356fcf59617SAndrey V. Elsukov 		return (1);
1357fcf59617SAndrey V. Elsukov 	}
1358fcf59617SAndrey V. Elsukov 	sav->tdb_cryptoid = *new;
1359fcf59617SAndrey V. Elsukov 	SECASVAR_UNLOCK(sav);
1360fcf59617SAndrey V. Elsukov 	return (0);
136188768458SSam Leffler }
136288768458SSam Leffler 
1363fcf59617SAndrey V. Elsukov int
1364fcf59617SAndrey V. Elsukov ipsec_initialized(void)
136588768458SSam Leffler {
1366de47c390SBjoern A. Zeeb 
1367fcf59617SAndrey V. Elsukov 	return (V_def_policy != NULL);
136888768458SSam Leffler }
136988768458SSam Leffler 
13708381996eSSam Leffler static void
137193201211SAndrey V. Elsukov def_policy_init(const void *unused __unused)
13721ed81b73SMarko Zec {
13731ed81b73SMarko Zec 
1374fcf59617SAndrey V. Elsukov 	V_def_policy = key_newsp();
1375fcf59617SAndrey V. Elsukov 	if (V_def_policy != NULL) {
1376fcf59617SAndrey V. Elsukov 		V_def_policy->policy = IPSEC_POLICY_NONE;
1377fcf59617SAndrey V. Elsukov 		/* Force INPCB SP cache invalidation */
1378fcf59617SAndrey V. Elsukov 		key_bumpspgen();
1379fcf59617SAndrey V. Elsukov 	} else
1380fcf59617SAndrey V. Elsukov 		printf("%s: failed to initialize default policy\n", __func__);
13818381996eSSam Leffler }
1382fcf59617SAndrey V. Elsukov 
1383fcf59617SAndrey V. Elsukov 
1384fcf59617SAndrey V. Elsukov static void
1385fcf59617SAndrey V. Elsukov def_policy_uninit(const void *unused __unused)
1386fcf59617SAndrey V. Elsukov {
1387fcf59617SAndrey V. Elsukov 
1388fcf59617SAndrey V. Elsukov 	if (V_def_policy != NULL) {
1389fcf59617SAndrey V. Elsukov 		key_freesp(&V_def_policy);
1390fcf59617SAndrey V. Elsukov 		key_bumpspgen();
1391fcf59617SAndrey V. Elsukov 	}
1392fcf59617SAndrey V. Elsukov }
1393fcf59617SAndrey V. Elsukov 
139489856f7eSBjoern A. Zeeb VNET_SYSINIT(def_policy_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
139593201211SAndrey V. Elsukov     def_policy_init, NULL);
1396fcf59617SAndrey V. Elsukov VNET_SYSUNINIT(def_policy_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
1397fcf59617SAndrey V. Elsukov     def_policy_uninit, NULL);
1398