1223637Sbz/*	$OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $ */
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
5223637Sbz * Copyright (c) 2002 - 2008 Henning Brauer
6126258Smlaier * All rights reserved.
7126258Smlaier *
8126258Smlaier * Redistribution and use in source and binary forms, with or without
9126258Smlaier * modification, are permitted provided that the following conditions
10126258Smlaier * are met:
11126258Smlaier *
12126258Smlaier *    - Redistributions of source code must retain the above copyright
13126258Smlaier *      notice, this list of conditions and the following disclaimer.
14126258Smlaier *    - Redistributions in binary form must reproduce the above
15126258Smlaier *      copyright notice, this list of conditions and the following
16126258Smlaier *      disclaimer in the documentation and/or other materials provided
17126258Smlaier *      with the distribution.
18126258Smlaier *
19126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
31126258Smlaier *
32126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
33126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
34126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35126258Smlaier *
36126258Smlaier */
37126258Smlaier
38127145Smlaier#ifdef __FreeBSD__
39126261Smlaier#include "opt_inet.h"
40126261Smlaier#include "opt_inet6.h"
41171168Smlaier
42171168Smlaier#include <sys/cdefs.h>
43171168Smlaier__FBSDID("$FreeBSD$");
44126261Smlaier#endif
45126261Smlaier
46127145Smlaier#ifdef __FreeBSD__
47126261Smlaier#include "opt_bpf.h"
48126261Smlaier#include "opt_pf.h"
49153110Sru
50230868Sglebius#define	NPFSYNC		1
51153110Sru
52223637Sbz#ifdef DEV_PFLOW
53223637Sbz#define	NPFLOW		DEV_PFLOW
54153110Sru#else
55223637Sbz#define	NPFLOW		0
56223637Sbz#endif
57223637Sbz
58223637Sbz#else
59126258Smlaier#include "bpfilter.h"
60126258Smlaier#include "pflog.h"
61126258Smlaier#include "pfsync.h"
62223637Sbz#include "pflow.h"
63126261Smlaier#endif
64126258Smlaier
65126258Smlaier#include <sys/param.h>
66126258Smlaier#include <sys/systm.h>
67126258Smlaier#include <sys/mbuf.h>
68126258Smlaier#include <sys/filio.h>
69126258Smlaier#include <sys/socket.h>
70126258Smlaier#include <sys/socketvar.h>
71126258Smlaier#include <sys/kernel.h>
72126258Smlaier#include <sys/time.h>
73127145Smlaier#ifdef __FreeBSD__
74223637Sbz#include <sys/random.h>
75126261Smlaier#include <sys/sysctl.h>
76130613Smlaier#include <sys/endian.h>
77223637Sbz#define	betoh64		be64toh
78126261Smlaier#else
79126258Smlaier#include <sys/pool.h>
80126261Smlaier#endif
81171168Smlaier#include <sys/proc.h>
82171168Smlaier#ifdef __FreeBSD__
83171168Smlaier#include <sys/kthread.h>
84171168Smlaier#include <sys/lock.h>
85171168Smlaier#include <sys/sx.h>
86171168Smlaier#else
87171168Smlaier#include <sys/rwlock.h>
88171168Smlaier#endif
89126258Smlaier
90223637Sbz#ifdef __FreeBSD__
91223637Sbz#include <sys/md5.h>
92223637Sbz#else
93223637Sbz#include <crypto/md5.h>
94223637Sbz#endif
95223637Sbz
96126258Smlaier#include <net/if.h>
97126258Smlaier#include <net/if_types.h>
98126258Smlaier#include <net/bpf.h>
99126258Smlaier#include <net/route.h>
100223637Sbz#ifdef __FreeBSD__
101223637Sbz#ifdef RADIX_MPATH
102171168Smlaier#include <net/radix_mpath.h>
103171168Smlaier#endif
104223637Sbz#else
105223637Sbz#include <net/radix_mpath.h>
106223637Sbz#endif
107126258Smlaier
108126258Smlaier#include <netinet/in.h>
109126258Smlaier#include <netinet/in_var.h>
110126258Smlaier#include <netinet/in_systm.h>
111126258Smlaier#include <netinet/ip.h>
112126258Smlaier#include <netinet/ip_var.h>
113126258Smlaier#include <netinet/tcp.h>
114126258Smlaier#include <netinet/tcp_seq.h>
115126258Smlaier#include <netinet/udp.h>
116126258Smlaier#include <netinet/ip_icmp.h>
117126258Smlaier#include <netinet/in_pcb.h>
118126258Smlaier#include <netinet/tcp_timer.h>
119126258Smlaier#include <netinet/tcp_var.h>
120126258Smlaier#include <netinet/udp_var.h>
121126258Smlaier#include <netinet/icmp_var.h>
122145836Smlaier#include <netinet/if_ether.h>
123223637Sbz#ifdef __FreeBSD__
124223637Sbz#include <netinet/ip_fw.h>
125243401Sglebius#include <netpfil/ipfw/ip_fw_private.h> /* XXX: only for DIR_IN/DIR_OUT */
126223637Sbz#endif
127126258Smlaier
128127145Smlaier#ifndef __FreeBSD__
129126258Smlaier#include <dev/rndvar.h>
130126261Smlaier#endif
131126258Smlaier#include <net/pfvar.h>
132126258Smlaier#include <net/if_pflog.h>
133223637Sbz#include <net/if_pflow.h>
134126258Smlaier#include <net/if_pfsync.h>
135126258Smlaier
136126258Smlaier#ifdef INET6
137126258Smlaier#include <netinet/ip6.h>
138126258Smlaier#include <netinet/in_pcb.h>
139126258Smlaier#include <netinet/icmp6.h>
140126258Smlaier#include <netinet6/nd6.h>
141127145Smlaier#ifdef __FreeBSD__
142126261Smlaier#include <netinet6/ip6_var.h>
143126261Smlaier#include <netinet6/in6_pcb.h>
144126261Smlaier#endif
145126258Smlaier#endif /* INET6 */
146126258Smlaier
147127145Smlaier#ifdef __FreeBSD__
148126261Smlaier#include <machine/in_cksum.h>
149126261Smlaier#include <sys/limits.h>
150126261Smlaier#include <sys/ucred.h>
151163606Srwatson#include <security/mac/mac_framework.h>
152126258Smlaier
153126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
154126261Smlaier#endif
155126261Smlaier
156223637Sbz#ifdef __FreeBSD__
157223637Sbz#define	DPFPRINTF(n, x)	if (V_pf_status.debug >= (n)) printf x
158223637Sbz#else
159223637Sbz#define	DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
160223637Sbz#endif
161126258Smlaier
162126258Smlaier/*
163126258Smlaier * Global variables
164126258Smlaier */
165126258Smlaier
166223637Sbz/* state tables */
167223637Sbz#ifdef __FreeBSD__
168223637SbzVNET_DEFINE(struct pf_state_tree,	 pf_statetbl);
169223637Sbz
170223637SbzVNET_DEFINE(struct pf_altqqueue,	 pf_altqs[2]);
171223637SbzVNET_DEFINE(struct pf_palist,		 pf_pabuf);
172223637SbzVNET_DEFINE(struct pf_altqqueue *,	 pf_altqs_active);
173223637SbzVNET_DEFINE(struct pf_altqqueue *,	 pf_altqs_inactive);
174223637SbzVNET_DEFINE(struct pf_status,		 pf_status);
175223637Sbz
176223637SbzVNET_DEFINE(u_int32_t,			 ticket_altqs_active);
177223637SbzVNET_DEFINE(u_int32_t,			 ticket_altqs_inactive);
178223637SbzVNET_DEFINE(int,			 altqs_inactive_open);
179223637SbzVNET_DEFINE(u_int32_t,			 ticket_pabuf);
180223637Sbz
181223637SbzVNET_DEFINE(MD5_CTX,			 pf_tcp_secret_ctx);
182223637Sbz#define	V_pf_tcp_secret_ctx		 VNET(pf_tcp_secret_ctx)
183223637SbzVNET_DEFINE(u_char,			 pf_tcp_secret[16]);
184223637Sbz#define	V_pf_tcp_secret			 VNET(pf_tcp_secret)
185223637SbzVNET_DEFINE(int,			 pf_tcp_secret_init);
186223637Sbz#define	V_pf_tcp_secret_init		 VNET(pf_tcp_secret_init)
187223637SbzVNET_DEFINE(int,			 pf_tcp_iss_off);
188223637Sbz#define	V_pf_tcp_iss_off		 VNET(pf_tcp_iss_off)
189223637Sbz
190223637Sbzstruct pf_anchor_stackframe {
191223637Sbz	struct pf_ruleset		*rs;
192223637Sbz	struct pf_rule			*r;
193223637Sbz	struct pf_anchor_node		*parent;
194223637Sbz	struct pf_anchor		*child;
195223637Sbz};
196223637SbzVNET_DEFINE(struct pf_anchor_stackframe, pf_anchor_stack[64]);
197223637Sbz#define	V_pf_anchor_stack		 VNET(pf_anchor_stack)
198223637Sbz
199223637SbzVNET_DEFINE(uma_zone_t,	 pf_src_tree_pl);
200223637SbzVNET_DEFINE(uma_zone_t,	 pf_rule_pl);
201223637SbzVNET_DEFINE(uma_zone_t,	 pf_pooladdr_pl);
202223637SbzVNET_DEFINE(uma_zone_t,	 pf_state_pl);
203223637SbzVNET_DEFINE(uma_zone_t,	 pf_state_key_pl);
204223637SbzVNET_DEFINE(uma_zone_t,	 pf_state_item_pl);
205223637SbzVNET_DEFINE(uma_zone_t,	 pf_altq_pl);
206223637Sbz#else
207223637Sbzstruct pf_state_tree	 pf_statetbl;
208223637Sbz
209126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
210126258Smlaierstruct pf_palist	 pf_pabuf;
211126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
212126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
213126258Smlaierstruct pf_status	 pf_status;
214126258Smlaier
215126258Smlaieru_int32_t		 ticket_altqs_active;
216126258Smlaieru_int32_t		 ticket_altqs_inactive;
217130613Smlaierint			 altqs_inactive_open;
218126258Smlaieru_int32_t		 ticket_pabuf;
219126258Smlaier
220223637SbzMD5_CTX			 pf_tcp_secret_ctx;
221223637Sbzu_char			 pf_tcp_secret[16];
222223637Sbzint			 pf_tcp_secret_init;
223223637Sbzint			 pf_tcp_iss_off;
224223637Sbz
225145836Smlaierstruct pf_anchor_stackframe {
226145836Smlaier	struct pf_ruleset			*rs;
227145836Smlaier	struct pf_rule				*r;
228145836Smlaier	struct pf_anchor_node			*parent;
229145836Smlaier	struct pf_anchor			*child;
230145836Smlaier} pf_anchor_stack[64];
231126261Smlaier
232223637Sbzstruct pool		 pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl;
233223637Sbzstruct pool		 pf_state_pl, pf_state_key_pl, pf_state_item_pl;
234223637Sbzstruct pool		 pf_altq_pl;
235126261Smlaier#endif
236126258Smlaier
237145836Smlaiervoid			 pf_init_threshold(struct pf_threshold *, u_int32_t,
238145836Smlaier			    u_int32_t);
239145836Smlaiervoid			 pf_add_threshold(struct pf_threshold *);
240145836Smlaierint			 pf_check_threshold(struct pf_threshold *);
241145836Smlaier
242293896Sglebiusvoid			 pf_change_ap(struct mbuf *, struct pf_addr *, u_int16_t *,
243126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
244126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
245171168Smlaierint			 pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
246171168Smlaier			    struct tcphdr *, struct pf_state_peer *);
247126258Smlaier#ifdef INET6
248126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
249126258Smlaier			    struct pf_addr *, u_int8_t);
250126258Smlaier#endif /* INET6 */
251126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
252126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
253126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
254126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
255162238Scsjp#ifdef __FreeBSD__
256162238Scsjpvoid			 pf_send_tcp(struct mbuf *,
257162238Scsjp			    const struct pf_rule *, sa_family_t,
258162238Scsjp#else
259126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
260162238Scsjp#endif
261126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
262126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
263145836Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
264171168Smlaier			    u_int16_t, struct ether_header *, struct ifnet *);
265223637Sbzstatic void		 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
266126258Smlaier			    sa_family_t, struct pf_rule *);
267223637Sbzvoid			 pf_detach_state(struct pf_state *);
268223637Sbzvoid			 pf_state_key_detach(struct pf_state *, int);
269223637Sbzu_int32_t		 pf_tcp_iss(struct pf_pdesc *);
270223637Sbzint			 pf_test_rule(struct pf_rule **, struct pf_state **,
271130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
272126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
273135920Smlaier#ifdef __FreeBSD__
274145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
275145836Smlaier			    struct inpcb *);
276135920Smlaier#else
277145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
278135920Smlaier#endif
279223637Sbzstatic __inline int	 pf_create_state(struct pf_rule *, struct pf_rule *,
280223637Sbz			    struct pf_rule *, struct pf_pdesc *,
281223637Sbz			    struct pf_src_node *, struct pf_state_key *,
282223637Sbz			    struct pf_state_key *, struct pf_state_key *,
283223637Sbz			    struct pf_state_key *, struct mbuf *, int,
284223637Sbz			    u_int16_t, u_int16_t, int *, struct pfi_kif *,
285223637Sbz			    struct pf_state **, int, u_int16_t, u_int16_t,
286223637Sbz			    int);
287126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
288130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
289126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
290126258Smlaier			    struct pf_ruleset **);
291200930Sdelphijint			 pf_tcp_track_full(struct pf_state_peer *,
292200930Sdelphij			    struct pf_state_peer *, struct pf_state **,
293200930Sdelphij			    struct pfi_kif *, struct mbuf *, int,
294200930Sdelphij			    struct pf_pdesc *, u_short *, int *);
295223637Sbzint			pf_tcp_track_sloppy(struct pf_state_peer *,
296200930Sdelphij			    struct pf_state_peer *, struct pf_state **,
297200930Sdelphij			    struct pf_pdesc *, u_short *);
298126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
299130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
300126258Smlaier			    void *, struct pf_pdesc *, u_short *);
301126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
302130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
303126258Smlaier			    void *, struct pf_pdesc *);
304126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
305130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
306145836Smlaier			    void *, struct pf_pdesc *, u_short *);
307126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
308223637Sbz			    struct pfi_kif *, struct mbuf *, struct pf_pdesc *);
309126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
310171168Smlaier			    struct ifnet *, struct pf_state *,
311171168Smlaier			    struct pf_pdesc *);
312126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
313171168Smlaier			    struct ifnet *, struct pf_state *,
314171168Smlaier			    struct pf_pdesc *);
315223637Sbz#ifndef __FreeBSD__
316171168Smlaierint			 pf_socket_lookup(int, struct pf_pdesc *);
317135920Smlaier#endif
318126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
319126258Smlaier			    sa_family_t);
320126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
321126258Smlaier			    sa_family_t);
322126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
323232292Sbz				int, u_int16_t);
324126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
325126258Smlaier			    struct pf_addr *);
326126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
327126258Smlaier			    u_int8_t, sa_family_t);
328223637Sbz#ifndef __FreeBSD__
329223637Sbzstruct pf_divert	*pf_get_divert(struct mbuf *);
330223637Sbz#endif
331223637Sbzvoid			 pf_print_state_parts(struct pf_state *,
332223637Sbz			    struct pf_state_key *, struct pf_state_key *);
333126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
334126258Smlaier			    struct pf_addr_wrap *);
335223637Sbzint			 pf_compare_state_keys(struct pf_state_key *,
336223637Sbz			    struct pf_state_key *, struct pfi_kif *, u_int);
337223637Sbz#ifdef __FreeBSD__
338223637Sbzstruct pf_state		*pf_find_state(struct pfi_kif *,
339223637Sbz			    struct pf_state_key_cmp *, u_int, struct mbuf *,
340223637Sbz			    struct pf_mtag *);
341223637Sbz#else
342223637Sbzstruct pf_state		*pf_find_state(struct pfi_kif *,
343223637Sbz			    struct pf_state_key_cmp *, u_int, struct mbuf *);
344223637Sbz#endif
345145836Smlaierint			 pf_src_connlimit(struct pf_state **);
346145836Smlaierint			 pf_check_congestion(struct ifqueue *);
347126258Smlaier
348127145Smlaier#ifdef __FreeBSD__
349126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
350126258Smlaier
351223637SbzVNET_DECLARE(int, pf_end_threads);
352171168Smlaier
353223637SbzVNET_DEFINE(struct pf_pool_limit, pf_pool_limits[PF_LIMIT_MAX]);
354171168Smlaier#else
355171168Smlaierextern struct pool pfr_ktable_pl;
356171168Smlaierextern struct pool pfr_kentry_pl;
357145836Smlaier
358130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
359130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
360130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
361171168Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT },
362171168Smlaier	{ &pfr_ktable_pl, PFR_KTABLE_HIWAT },
363171168Smlaier	{ &pfr_kentry_pl, PFR_KENTRY_HIWAT }
364130613Smlaier};
365126261Smlaier#endif
366126258Smlaier
367223637Sbz#ifdef __FreeBSD__
368223637Sbz#define	PPACKET_LOOPED()						\
369223637Sbz	(pd->pf_mtag->flags & PF_PACKET_LOOPED)
370223637Sbz
371223637Sbz#define	PACKET_LOOPED()							\
372223637Sbz	(pd.pf_mtag->flags & PF_PACKET_LOOPED)
373223637Sbz
374223637Sbz#define	STATE_LOOKUP(i, k, d, s, m, pt)					\
375126258Smlaier	do {								\
376223637Sbz		s = pf_find_state(i, k, d, m, pt);			\
377223637Sbz		if (s == NULL || (s)->timeout == PFTM_PURGE)		\
378126258Smlaier			return (PF_DROP);				\
379223637Sbz		if (PPACKET_LOOPED())					\
380126258Smlaier			return (PF_PASS);				\
381223637Sbz		if (d == PF_OUT &&					\
382223637Sbz		    (((s)->rule.ptr->rt == PF_ROUTETO &&		\
383223637Sbz		    (s)->rule.ptr->direction == PF_OUT) ||		\
384223637Sbz		    ((s)->rule.ptr->rt == PF_REPLYTO &&			\
385223637Sbz		    (s)->rule.ptr->direction == PF_IN)) &&		\
386223637Sbz		    (s)->rt_kif != NULL &&				\
387223637Sbz		    (s)->rt_kif != i)					\
388223637Sbz			return (PF_PASS);				\
389126258Smlaier	} while (0)
390223637Sbz#else
391223637Sbz#define	STATE_LOOKUP(i, k, d, s, m)					\
392223637Sbz	do {								\
393223637Sbz		s = pf_find_state(i, k, d, m);				\
394223637Sbz		if (s == NULL || (s)->timeout == PFTM_PURGE)		\
395223637Sbz			return (PF_DROP);				\
396223637Sbz		if (d == PF_OUT &&					\
397223637Sbz		    (((s)->rule.ptr->rt == PF_ROUTETO &&		\
398223637Sbz		    (s)->rule.ptr->direction == PF_OUT) ||		\
399223637Sbz		    ((s)->rule.ptr->rt == PF_REPLYTO &&			\
400223637Sbz		    (s)->rule.ptr->direction == PF_IN)) &&		\
401223637Sbz		    (s)->rt_kif != NULL &&				\
402223637Sbz		    (s)->rt_kif != i)					\
403223637Sbz			return (PF_PASS);				\
404223637Sbz	} while (0)
405223637Sbz#endif
406126258Smlaier
407223637Sbz#ifdef __FreeBSD__
408223637Sbz#define	BOUND_IFACE(r, k) \
409223637Sbz	((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all
410223637Sbz#else
411223637Sbz#define	BOUND_IFACE(r, k) \
412171168Smlaier	((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
413223637Sbz#endif
414126258Smlaier
415223637Sbz#define	STATE_INC_COUNTERS(s)				\
416145836Smlaier	do {						\
417223637Sbz		s->rule.ptr->states_cur++;		\
418223637Sbz		s->rule.ptr->states_tot++;		\
419223637Sbz		if (s->anchor.ptr != NULL) {		\
420223637Sbz			s->anchor.ptr->states_cur++;	\
421223637Sbz			s->anchor.ptr->states_tot++;	\
422223637Sbz		}					\
423223637Sbz		if (s->nat_rule.ptr != NULL) {		\
424223637Sbz			s->nat_rule.ptr->states_cur++;	\
425223637Sbz			s->nat_rule.ptr->states_tot++;	\
426223637Sbz		}					\
427145836Smlaier	} while (0)
428145836Smlaier
429223637Sbz#define	STATE_DEC_COUNTERS(s)				\
430145836Smlaier	do {						\
431145836Smlaier		if (s->nat_rule.ptr != NULL)		\
432223637Sbz			s->nat_rule.ptr->states_cur--;	\
433145836Smlaier		if (s->anchor.ptr != NULL)		\
434223637Sbz			s->anchor.ptr->states_cur--;	\
435223637Sbz		s->rule.ptr->states_cur--;		\
436145836Smlaier	} while (0)
437145836Smlaier
438223637Sbzstatic __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
439223637Sbzstatic __inline int pf_state_compare_key(struct pf_state_key *,
440223637Sbz	struct pf_state_key *);
441223637Sbzstatic __inline int pf_state_compare_id(struct pf_state *,
442223637Sbz	struct pf_state *);
443223637Sbz
444223637Sbz#ifdef __FreeBSD__
445223637SbzVNET_DEFINE(struct pf_src_tree,	 	 tree_src_tracking);
446223637Sbz
447223637SbzVNET_DEFINE(struct pf_state_tree_id,	 tree_id);
448223637SbzVNET_DEFINE(struct pf_state_queue,	 state_list);
449223637Sbz#else
450130613Smlaierstruct pf_src_tree tree_src_tracking;
451130613Smlaier
452130613Smlaierstruct pf_state_tree_id tree_id;
453171168Smlaierstruct pf_state_queue state_list;
454171168Smlaier#endif
455171168Smlaier
456130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
457223637SbzRB_GENERATE(pf_state_tree, pf_state_key, entry, pf_state_compare_key);
458130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
459223637Sbz    entry_id, pf_state_compare_id);
460130613Smlaier
461126258Smlaierstatic __inline int
462130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
463126258Smlaier{
464126258Smlaier	int	diff;
465126258Smlaier
466130613Smlaier	if (a->rule.ptr > b->rule.ptr)
467130613Smlaier		return (1);
468130613Smlaier	if (a->rule.ptr < b->rule.ptr)
469130613Smlaier		return (-1);
470130613Smlaier	if ((diff = a->af - b->af) != 0)
471130613Smlaier		return (diff);
472130613Smlaier	switch (a->af) {
473130613Smlaier#ifdef INET
474130613Smlaier	case AF_INET:
475130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
476130613Smlaier			return (1);
477130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
478130613Smlaier			return (-1);
479130613Smlaier		break;
480130613Smlaier#endif /* INET */
481130613Smlaier#ifdef INET6
482130613Smlaier	case AF_INET6:
483130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
484130613Smlaier			return (1);
485130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
486130613Smlaier			return (-1);
487130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
488130613Smlaier			return (1);
489130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
490130613Smlaier			return (-1);
491130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
492130613Smlaier			return (1);
493130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
494130613Smlaier			return (-1);
495130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
496130613Smlaier			return (1);
497130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
498130613Smlaier			return (-1);
499130613Smlaier		break;
500130613Smlaier#endif /* INET6 */
501130613Smlaier	}
502130613Smlaier	return (0);
503130613Smlaier}
504130613Smlaier
505126258Smlaier#ifdef INET6
506126258Smlaiervoid
507126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
508126258Smlaier{
509126258Smlaier	switch (af) {
510126258Smlaier#ifdef INET
511126258Smlaier	case AF_INET:
512126258Smlaier		dst->addr32[0] = src->addr32[0];
513126258Smlaier		break;
514126258Smlaier#endif /* INET */
515126258Smlaier	case AF_INET6:
516126258Smlaier		dst->addr32[0] = src->addr32[0];
517126258Smlaier		dst->addr32[1] = src->addr32[1];
518126258Smlaier		dst->addr32[2] = src->addr32[2];
519126258Smlaier		dst->addr32[3] = src->addr32[3];
520126258Smlaier		break;
521126258Smlaier	}
522126258Smlaier}
523145836Smlaier#endif /* INET6 */
524126258Smlaier
525145836Smlaiervoid
526145836Smlaierpf_init_threshold(struct pf_threshold *threshold,
527145836Smlaier    u_int32_t limit, u_int32_t seconds)
528145836Smlaier{
529145836Smlaier	threshold->limit = limit * PF_THRESHOLD_MULT;
530145836Smlaier	threshold->seconds = seconds;
531145836Smlaier	threshold->count = 0;
532145836Smlaier	threshold->last = time_second;
533145836Smlaier}
534145836Smlaier
535145836Smlaiervoid
536145836Smlaierpf_add_threshold(struct pf_threshold *threshold)
537145836Smlaier{
538145836Smlaier	u_int32_t t = time_second, diff = t - threshold->last;
539145836Smlaier
540145836Smlaier	if (diff >= threshold->seconds)
541145836Smlaier		threshold->count = 0;
542145836Smlaier	else
543145836Smlaier		threshold->count -= threshold->count * diff /
544145836Smlaier		    threshold->seconds;
545145836Smlaier	threshold->count += PF_THRESHOLD_MULT;
546145836Smlaier	threshold->last = t;
547145836Smlaier}
548145836Smlaier
549126258Smlaierint
550145836Smlaierpf_check_threshold(struct pf_threshold *threshold)
551145836Smlaier{
552145836Smlaier	return (threshold->count > threshold->limit);
553145836Smlaier}
554145836Smlaier
555145836Smlaierint
556145836Smlaierpf_src_connlimit(struct pf_state **state)
557145836Smlaier{
558145836Smlaier	int bad = 0;
559145836Smlaier
560145836Smlaier	(*state)->src_node->conn++;
561171168Smlaier	(*state)->src.tcp_est = 1;
562145836Smlaier	pf_add_threshold(&(*state)->src_node->conn_rate);
563145836Smlaier
564145836Smlaier	if ((*state)->rule.ptr->max_src_conn &&
565145836Smlaier	    (*state)->rule.ptr->max_src_conn <
566145836Smlaier	    (*state)->src_node->conn) {
567223637Sbz#ifdef __FreeBSD__
568223637Sbz		V_pf_status.lcounters[LCNT_SRCCONN]++;
569223637Sbz#else
570145836Smlaier		pf_status.lcounters[LCNT_SRCCONN]++;
571223637Sbz#endif
572145836Smlaier		bad++;
573145836Smlaier	}
574145836Smlaier
575145836Smlaier	if ((*state)->rule.ptr->max_src_conn_rate.limit &&
576145836Smlaier	    pf_check_threshold(&(*state)->src_node->conn_rate)) {
577223637Sbz#ifdef __FreeBSD__
578223637Sbz		V_pf_status.lcounters[LCNT_SRCCONNRATE]++;
579223637Sbz#else
580145836Smlaier		pf_status.lcounters[LCNT_SRCCONNRATE]++;
581223637Sbz#endif
582145836Smlaier		bad++;
583145836Smlaier	}
584145836Smlaier
585145836Smlaier	if (!bad)
586145836Smlaier		return (0);
587145836Smlaier
588145836Smlaier	if ((*state)->rule.ptr->overload_tbl) {
589145836Smlaier		struct pfr_addr p;
590145836Smlaier		u_int32_t	killed = 0;
591145836Smlaier
592223637Sbz#ifdef __FreeBSD__
593223637Sbz		V_pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
594223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC) {
595223637Sbz#else
596145836Smlaier		pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
597145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
598223637Sbz#endif
599145836Smlaier			printf("pf_src_connlimit: blocking address ");
600145836Smlaier			pf_print_host(&(*state)->src_node->addr, 0,
601223637Sbz			    (*state)->key[PF_SK_WIRE]->af);
602145836Smlaier		}
603145836Smlaier
604145836Smlaier		bzero(&p, sizeof(p));
605223637Sbz		p.pfra_af = (*state)->key[PF_SK_WIRE]->af;
606223637Sbz		switch ((*state)->key[PF_SK_WIRE]->af) {
607145836Smlaier#ifdef INET
608145836Smlaier		case AF_INET:
609145836Smlaier			p.pfra_net = 32;
610145836Smlaier			p.pfra_ip4addr = (*state)->src_node->addr.v4;
611145836Smlaier			break;
612145836Smlaier#endif /* INET */
613145836Smlaier#ifdef INET6
614145836Smlaier		case AF_INET6:
615145836Smlaier			p.pfra_net = 128;
616145836Smlaier			p.pfra_ip6addr = (*state)->src_node->addr.v6;
617145836Smlaier			break;
618145836Smlaier#endif /* INET6 */
619145836Smlaier		}
620145836Smlaier
621145836Smlaier		pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
622145836Smlaier		    &p, time_second);
623145836Smlaier
624145836Smlaier		/* kill existing states if that's required. */
625145836Smlaier		if ((*state)->rule.ptr->flush) {
626223637Sbz			struct pf_state_key *sk;
627223637Sbz			struct pf_state *st;
628223637Sbz
629223637Sbz#ifdef __FreeBSD__
630223637Sbz			V_pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
631223637Sbz			RB_FOREACH(st, pf_state_tree_id, &V_tree_id) {
632223637Sbz#else
633145836Smlaier			pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
634223637Sbz			RB_FOREACH(st, pf_state_tree_id, &tree_id) {
635223637Sbz#endif
636223637Sbz				sk = st->key[PF_SK_WIRE];
637145836Smlaier				/*
638145836Smlaier				 * Kill states from this source.  (Only those
639145836Smlaier				 * from the same rule if PF_FLUSH_GLOBAL is not
640145836Smlaier				 * set)
641145836Smlaier				 */
642223637Sbz				if (sk->af ==
643223637Sbz				    (*state)->key[PF_SK_WIRE]->af &&
644145836Smlaier				    (((*state)->direction == PF_OUT &&
645145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
646237053Sglebius					&sk->addr[1], sk->af)) ||
647145836Smlaier				    ((*state)->direction == PF_IN &&
648145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
649237053Sglebius					&sk->addr[0], sk->af))) &&
650145836Smlaier				    ((*state)->rule.ptr->flush &
651145836Smlaier				    PF_FLUSH_GLOBAL ||
652223637Sbz				    (*state)->rule.ptr == st->rule.ptr)) {
653223637Sbz					st->timeout = PFTM_PURGE;
654223637Sbz					st->src.state = st->dst.state =
655145836Smlaier					    TCPS_CLOSED;
656145836Smlaier					killed++;
657145836Smlaier				}
658145836Smlaier			}
659223637Sbz#ifdef __FreeBSD__
660223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC)
661223637Sbz#else
662145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
663223637Sbz#endif
664145836Smlaier				printf(", %u states killed", killed);
665145836Smlaier		}
666223637Sbz#ifdef __FreeBSD__
667223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC)
668223637Sbz#else
669145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
670223637Sbz#endif
671145836Smlaier			printf("\n");
672145836Smlaier	}
673145836Smlaier
674145836Smlaier	/* kill this state */
675145836Smlaier	(*state)->timeout = PFTM_PURGE;
676145836Smlaier	(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
677145836Smlaier	return (1);
678145836Smlaier}
679145836Smlaier
680145836Smlaierint
681130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
682130613Smlaier    struct pf_addr *src, sa_family_t af)
683126258Smlaier{
684130613Smlaier	struct pf_src_node	k;
685126258Smlaier
686130613Smlaier	if (*sn == NULL) {
687130613Smlaier		k.af = af;
688130613Smlaier		PF_ACPY(&k.addr, src, af);
689130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
690130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
691130613Smlaier			k.rule.ptr = rule;
692130613Smlaier		else
693130613Smlaier			k.rule.ptr = NULL;
694223637Sbz#ifdef __FreeBSD__
695223637Sbz		V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
696223637Sbz		*sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k);
697223637Sbz#else
698130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
699130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
700223637Sbz#endif
701130613Smlaier	}
702130613Smlaier	if (*sn == NULL) {
703130613Smlaier		if (!rule->max_src_nodes ||
704130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
705223637Sbz#ifdef __FreeBSD__
706223637Sbz			(*sn) = pool_get(&V_pf_src_tree_pl, PR_NOWAIT | PR_ZERO);
707223637Sbz#else
708223637Sbz			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT | PR_ZERO);
709223637Sbz#endif
710145836Smlaier		else
711223637Sbz#ifdef __FreeBSD__
712223637Sbz			V_pf_status.lcounters[LCNT_SRCNODES]++;
713223637Sbz#else
714145836Smlaier			pf_status.lcounters[LCNT_SRCNODES]++;
715223637Sbz#endif
716130613Smlaier		if ((*sn) == NULL)
717130613Smlaier			return (-1);
718145836Smlaier
719145836Smlaier		pf_init_threshold(&(*sn)->conn_rate,
720145836Smlaier		    rule->max_src_conn_rate.limit,
721145836Smlaier		    rule->max_src_conn_rate.seconds);
722145836Smlaier
723130613Smlaier		(*sn)->af = af;
724130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
725130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
726130613Smlaier			(*sn)->rule.ptr = rule;
727130613Smlaier		else
728130613Smlaier			(*sn)->rule.ptr = NULL;
729130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
730130613Smlaier		if (RB_INSERT(pf_src_tree,
731223637Sbz#ifdef __FreeBSD__
732223637Sbz		    &V_tree_src_tracking, *sn) != NULL) {
733223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
734223637Sbz#else
735130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
736130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
737223637Sbz#endif
738130613Smlaier				printf("pf: src_tree insert failed: ");
739130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
740130613Smlaier				printf("\n");
741130613Smlaier			}
742223637Sbz#ifdef __FreeBSD__
743223637Sbz			pool_put(&V_pf_src_tree_pl, *sn);
744223637Sbz#else
745130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
746223637Sbz#endif
747130613Smlaier			return (-1);
748130613Smlaier		}
749130613Smlaier		(*sn)->creation = time_second;
750130613Smlaier		(*sn)->ruletype = rule->action;
751130613Smlaier		if ((*sn)->rule.ptr != NULL)
752130613Smlaier			(*sn)->rule.ptr->src_nodes++;
753223637Sbz#ifdef __FreeBSD__
754223637Sbz		V_pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
755223637Sbz		V_pf_status.src_nodes++;
756223637Sbz#else
757130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
758130613Smlaier		pf_status.src_nodes++;
759223637Sbz#endif
760130613Smlaier	} else {
761130613Smlaier		if (rule->max_src_states &&
762145836Smlaier		    (*sn)->states >= rule->max_src_states) {
763223637Sbz#ifdef __FreeBSD__
764223637Sbz			V_pf_status.lcounters[LCNT_SRCSTATES]++;
765223637Sbz#else
766145836Smlaier			pf_status.lcounters[LCNT_SRCSTATES]++;
767223637Sbz#endif
768130613Smlaier			return (-1);
769145836Smlaier		}
770130613Smlaier	}
771130613Smlaier	return (0);
772130613Smlaier}
773126258Smlaier
774223637Sbz/* state table stuff */
775223637Sbz
776223637Sbzstatic __inline int
777223637Sbzpf_state_compare_key(struct pf_state_key *a, struct pf_state_key *b)
778223637Sbz{
779223637Sbz	int	diff;
780223637Sbz
781223637Sbz	if ((diff = a->proto - b->proto) != 0)
782223637Sbz		return (diff);
783223637Sbz	if ((diff = a->af - b->af) != 0)
784223637Sbz		return (diff);
785223637Sbz	switch (a->af) {
786223637Sbz#ifdef INET
787223637Sbz	case AF_INET:
788223637Sbz		if (a->addr[0].addr32[0] > b->addr[0].addr32[0])
789223637Sbz			return (1);
790223637Sbz		if (a->addr[0].addr32[0] < b->addr[0].addr32[0])
791223637Sbz			return (-1);
792223637Sbz		if (a->addr[1].addr32[0] > b->addr[1].addr32[0])
793223637Sbz			return (1);
794223637Sbz		if (a->addr[1].addr32[0] < b->addr[1].addr32[0])
795223637Sbz			return (-1);
796223637Sbz		break;
797223637Sbz#endif /* INET */
798223637Sbz#ifdef INET6
799223637Sbz	case AF_INET6:
800223637Sbz		if (a->addr[0].addr32[3] > b->addr[0].addr32[3])
801223637Sbz			return (1);
802223637Sbz		if (a->addr[0].addr32[3] < b->addr[0].addr32[3])
803223637Sbz			return (-1);
804223637Sbz		if (a->addr[1].addr32[3] > b->addr[1].addr32[3])
805223637Sbz			return (1);
806223637Sbz		if (a->addr[1].addr32[3] < b->addr[1].addr32[3])
807223637Sbz			return (-1);
808223637Sbz		if (a->addr[0].addr32[2] > b->addr[0].addr32[2])
809223637Sbz			return (1);
810223637Sbz		if (a->addr[0].addr32[2] < b->addr[0].addr32[2])
811223637Sbz			return (-1);
812223637Sbz		if (a->addr[1].addr32[2] > b->addr[1].addr32[2])
813223637Sbz			return (1);
814223637Sbz		if (a->addr[1].addr32[2] < b->addr[1].addr32[2])
815223637Sbz			return (-1);
816223637Sbz		if (a->addr[0].addr32[1] > b->addr[0].addr32[1])
817223637Sbz			return (1);
818223637Sbz		if (a->addr[0].addr32[1] < b->addr[0].addr32[1])
819223637Sbz			return (-1);
820223637Sbz		if (a->addr[1].addr32[1] > b->addr[1].addr32[1])
821223637Sbz			return (1);
822223637Sbz		if (a->addr[1].addr32[1] < b->addr[1].addr32[1])
823223637Sbz			return (-1);
824223637Sbz		if (a->addr[0].addr32[0] > b->addr[0].addr32[0])
825223637Sbz			return (1);
826223637Sbz		if (a->addr[0].addr32[0] < b->addr[0].addr32[0])
827223637Sbz			return (-1);
828223637Sbz		if (a->addr[1].addr32[0] > b->addr[1].addr32[0])
829223637Sbz			return (1);
830223637Sbz		if (a->addr[1].addr32[0] < b->addr[1].addr32[0])
831223637Sbz			return (-1);
832223637Sbz		break;
833223637Sbz#endif /* INET6 */
834223637Sbz	}
835223637Sbz
836223637Sbz	if ((diff = a->port[0] - b->port[0]) != 0)
837223637Sbz		return (diff);
838223637Sbz	if ((diff = a->port[1] - b->port[1]) != 0)
839223637Sbz		return (diff);
840223637Sbz
841223637Sbz	return (0);
842223637Sbz}
843223637Sbz
844223637Sbzstatic __inline int
845223637Sbzpf_state_compare_id(struct pf_state *a, struct pf_state *b)
846223637Sbz{
847223637Sbz	if (a->id > b->id)
848223637Sbz		return (1);
849223637Sbz	if (a->id < b->id)
850223637Sbz		return (-1);
851223637Sbz	if (a->creatorid > b->creatorid)
852223637Sbz		return (1);
853223637Sbz	if (a->creatorid < b->creatorid)
854223637Sbz		return (-1);
855223637Sbz
856223637Sbz	return (0);
857223637Sbz}
858223637Sbz
859130613Smlaierint
860223637Sbzpf_state_key_attach(struct pf_state_key *sk, struct pf_state *s, int idx)
861130613Smlaier{
862223637Sbz	struct pf_state_item	*si;
863223637Sbz	struct pf_state_key	*cur;
864223637Sbz	struct pf_state		*olds = NULL;
865223637Sbz
866223637Sbz#ifdef __FreeBSD__
867223637Sbz	KASSERT(s->key[idx] == NULL, ("%s: key is null!", __FUNCTION__));
868223637Sbz#else
869223637Sbz	KASSERT(s->key[idx] == NULL);	/* XXX handle this? */
870223637Sbz#endif
871223637Sbz
872223637Sbz#ifdef __FreeBSD__
873223637Sbz	if ((cur = RB_INSERT(pf_state_tree, &V_pf_statetbl, sk)) != NULL) {
874223637Sbz#else
875223637Sbz	if ((cur = RB_INSERT(pf_state_tree, &pf_statetbl, sk)) != NULL) {
876223637Sbz#endif
877223637Sbz		/* key exists. check for same kif, if none, add to key */
878223637Sbz		TAILQ_FOREACH(si, &cur->states, entry)
879223637Sbz			if (si->s->kif == s->kif &&
880223637Sbz			    si->s->direction == s->direction) {
881223637Sbz				if (sk->proto == IPPROTO_TCP &&
882223637Sbz				    si->s->src.state >= TCPS_FIN_WAIT_2 &&
883223637Sbz				    si->s->dst.state >= TCPS_FIN_WAIT_2) {
884223637Sbz					si->s->src.state = si->s->dst.state =
885223637Sbz					    TCPS_CLOSED;
886223637Sbz					/* unlink late or sks can go away */
887223637Sbz					olds = si->s;
888223637Sbz				} else {
889223637Sbz#ifdef __FreeBSD__
890223637Sbz					if (V_pf_status.debug >= PF_DEBUG_MISC) {
891223637Sbz#else
892223637Sbz					if (pf_status.debug >= PF_DEBUG_MISC) {
893223637Sbz#endif
894223637Sbz						printf("pf: %s key attach "
895223637Sbz						    "failed on %s: ",
896223637Sbz						    (idx == PF_SK_WIRE) ?
897223637Sbz						    "wire" : "stack",
898223637Sbz						    s->kif->pfik_name);
899223637Sbz						pf_print_state_parts(s,
900223637Sbz						    (idx == PF_SK_WIRE) ?
901223637Sbz						    sk : NULL,
902223637Sbz						    (idx == PF_SK_STACK) ?
903223637Sbz						    sk : NULL);
904223637Sbz						printf(", existing: ");
905223637Sbz						pf_print_state_parts(si->s,
906223637Sbz						    (idx == PF_SK_WIRE) ?
907223637Sbz						    sk : NULL,
908223637Sbz						    (idx == PF_SK_STACK) ?
909223637Sbz						    sk : NULL);
910223637Sbz						printf("\n");
911223637Sbz					}
912223637Sbz#ifdef __FreeBSD__
913223637Sbz					pool_put(&V_pf_state_key_pl, sk);
914223637Sbz#else
915223637Sbz					pool_put(&pf_state_key_pl, sk);
916223637Sbz#endif
917223637Sbz					return (-1);	/* collision! */
918223637Sbz				}
919223637Sbz			}
920223637Sbz#ifdef __FreeBSD__
921223637Sbz		pool_put(&V_pf_state_key_pl, sk);
922223637Sbz#else
923223637Sbz		pool_put(&pf_state_key_pl, sk);
924223637Sbz#endif
925223637Sbz		s->key[idx] = cur;
926223637Sbz	} else
927223637Sbz		s->key[idx] = sk;
928223637Sbz
929223637Sbz#ifdef __FreeBSD__
930223637Sbz	if ((si = pool_get(&V_pf_state_item_pl, PR_NOWAIT)) == NULL) {
931223637Sbz#else
932223637Sbz	if ((si = pool_get(&pf_state_item_pl, PR_NOWAIT)) == NULL) {
933223637Sbz#endif
934223637Sbz		pf_state_key_detach(s, idx);
935126258Smlaier		return (-1);
936126258Smlaier	}
937223637Sbz	si->s = s;
938126258Smlaier
939223637Sbz	/* list is sorted, if-bound states before floating */
940223637Sbz#ifdef __FreeBSD__
941223637Sbz	if (s->kif == V_pfi_all)
942223637Sbz#else
943223637Sbz	if (s->kif == pfi_all)
944223637Sbz#endif
945223637Sbz		TAILQ_INSERT_TAIL(&s->key[idx]->states, si, entry);
946223637Sbz	else
947223637Sbz		TAILQ_INSERT_HEAD(&s->key[idx]->states, si, entry);
948223637Sbz
949223637Sbz	if (olds)
950223637Sbz		pf_unlink_state(olds);
951223637Sbz
952223637Sbz	return (0);
953223637Sbz}
954223637Sbz
955223637Sbzvoid
956223637Sbzpf_detach_state(struct pf_state *s)
957223637Sbz{
958223637Sbz	if (s->key[PF_SK_WIRE] == s->key[PF_SK_STACK])
959223637Sbz		s->key[PF_SK_WIRE] = NULL;
960223637Sbz
961223637Sbz	if (s->key[PF_SK_STACK] != NULL)
962223637Sbz		pf_state_key_detach(s, PF_SK_STACK);
963223637Sbz
964223637Sbz	if (s->key[PF_SK_WIRE] != NULL)
965223637Sbz		pf_state_key_detach(s, PF_SK_WIRE);
966223637Sbz}
967223637Sbz
968223637Sbzvoid
969223637Sbzpf_state_key_detach(struct pf_state *s, int idx)
970223637Sbz{
971223637Sbz	struct pf_state_item	*si;
972223637Sbz
973223637Sbz	si = TAILQ_FIRST(&s->key[idx]->states);
974223637Sbz	while (si && si->s != s)
975223637Sbz	    si = TAILQ_NEXT(si, entry);
976223637Sbz
977223637Sbz	if (si) {
978223637Sbz		TAILQ_REMOVE(&s->key[idx]->states, si, entry);
979223637Sbz#ifdef __FreeBSD__
980223637Sbz		pool_put(&V_pf_state_item_pl, si);
981223637Sbz#else
982223637Sbz		pool_put(&pf_state_item_pl, si);
983223637Sbz#endif
984223637Sbz	}
985223637Sbz
986223637Sbz	if (TAILQ_EMPTY(&s->key[idx]->states)) {
987223637Sbz#ifdef __FreeBSD__
988223637Sbz		RB_REMOVE(pf_state_tree, &V_pf_statetbl, s->key[idx]);
989223637Sbz#else
990223637Sbz		RB_REMOVE(pf_state_tree, &pf_statetbl, s->key[idx]);
991223637Sbz#endif
992223637Sbz		if (s->key[idx]->reverse)
993223637Sbz			s->key[idx]->reverse->reverse = NULL;
994223637Sbz#ifdef __FreeBSD__
995223637Sbz	/* XXX: implement this */
996223637Sbz#else
997223637Sbz		if (s->key[idx]->inp)
998223637Sbz			s->key[idx]->inp->inp_pf_sk = NULL;
999223637Sbz#endif
1000223637Sbz#ifdef __FreeBSD__
1001223637Sbz		pool_put(&V_pf_state_key_pl, s->key[idx]);
1002223637Sbz#else
1003223637Sbz		pool_put(&pf_state_key_pl, s->key[idx]);
1004223637Sbz#endif
1005223637Sbz	}
1006223637Sbz	s->key[idx] = NULL;
1007223637Sbz}
1008223637Sbz
1009223637Sbzstruct pf_state_key *
1010223637Sbzpf_alloc_state_key(int pool_flags)
1011223637Sbz{
1012223637Sbz	struct pf_state_key	*sk;
1013223637Sbz
1014223637Sbz#ifdef __FreeBSD__
1015223637Sbz	if ((sk = pool_get(&V_pf_state_key_pl, pool_flags)) == NULL)
1016223637Sbz#else
1017223637Sbz	if ((sk = pool_get(&pf_state_key_pl, pool_flags)) == NULL)
1018223637Sbz#endif
1019223637Sbz		return (NULL);
1020223637Sbz	TAILQ_INIT(&sk->states);
1021223637Sbz
1022223637Sbz	return (sk);
1023223637Sbz}
1024223637Sbz
1025223637Sbzint
1026223637Sbzpf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr,
1027223637Sbz	struct pf_state_key **skw, struct pf_state_key **sks,
1028223637Sbz	struct pf_state_key **skp, struct pf_state_key **nkp,
1029223637Sbz	struct pf_addr *saddr, struct pf_addr *daddr,
1030223637Sbz	u_int16_t sport, u_int16_t dport)
1031223637Sbz{
1032223637Sbz#ifdef __FreeBSD__
1033223637Sbz	KASSERT((*skp == NULL && *nkp == NULL),
1034223637Sbz		("%s: skp == NULL && nkp == NULL", __FUNCTION__));
1035223637Sbz#else
1036223637Sbz	KASSERT((*skp == NULL && *nkp == NULL));
1037223637Sbz#endif
1038223637Sbz
1039223637Sbz	if ((*skp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL)
1040223637Sbz		return (ENOMEM);
1041223637Sbz
1042223637Sbz	PF_ACPY(&(*skp)->addr[pd->sidx], saddr, pd->af);
1043223637Sbz	PF_ACPY(&(*skp)->addr[pd->didx], daddr, pd->af);
1044223637Sbz	(*skp)->port[pd->sidx] = sport;
1045223637Sbz	(*skp)->port[pd->didx] = dport;
1046223637Sbz	(*skp)->proto = pd->proto;
1047223637Sbz	(*skp)->af = pd->af;
1048223637Sbz
1049223637Sbz	if (nr != NULL) {
1050223637Sbz		if ((*nkp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL)
1051223637Sbz			return (ENOMEM); /* caller must handle cleanup */
1052223637Sbz
1053223637Sbz		/* XXX maybe just bcopy and TAILQ_INIT(&(*nkp)->states) */
1054223637Sbz		PF_ACPY(&(*nkp)->addr[0], &(*skp)->addr[0], pd->af);
1055223637Sbz		PF_ACPY(&(*nkp)->addr[1], &(*skp)->addr[1], pd->af);
1056223637Sbz		(*nkp)->port[0] = (*skp)->port[0];
1057223637Sbz		(*nkp)->port[1] = (*skp)->port[1];
1058223637Sbz		(*nkp)->proto = pd->proto;
1059223637Sbz		(*nkp)->af = pd->af;
1060223637Sbz	} else
1061223637Sbz		*nkp = *skp;
1062223637Sbz
1063223637Sbz	if (pd->dir == PF_IN) {
1064223637Sbz		*skw = *skp;
1065223637Sbz		*sks = *nkp;
1066223637Sbz	} else {
1067223637Sbz		*sks = *skp;
1068223637Sbz		*skw = *nkp;
1069223637Sbz	}
1070223637Sbz	return (0);
1071223637Sbz}
1072223637Sbz
1073223637Sbz
1074223637Sbzint
1075223637Sbzpf_state_insert(struct pfi_kif *kif, struct pf_state_key *skw,
1076223637Sbz    struct pf_state_key *sks, struct pf_state *s)
1077223637Sbz{
1078223637Sbz#ifndef __FreeBSD__
1079223637Sbz	splassert(IPL_SOFTNET);
1080223637Sbz#endif
1081223637Sbz
1082223637Sbz	s->kif = kif;
1083223637Sbz
1084223637Sbz	if (skw == sks) {
1085223637Sbz		if (pf_state_key_attach(skw, s, PF_SK_WIRE))
1086223637Sbz			return (-1);
1087223637Sbz		s->key[PF_SK_STACK] = s->key[PF_SK_WIRE];
1088223637Sbz	} else {
1089223637Sbz		if (pf_state_key_attach(skw, s, PF_SK_WIRE)) {
1090223637Sbz#ifdef __FreeBSD__
1091223637Sbz			pool_put(&V_pf_state_key_pl, sks);
1092223637Sbz#else
1093223637Sbz			pool_put(&pf_state_key_pl, sks);
1094223637Sbz#endif
1095223637Sbz			return (-1);
1096126258Smlaier		}
1097223637Sbz		if (pf_state_key_attach(sks, s, PF_SK_STACK)) {
1098223637Sbz			pf_state_key_detach(s, PF_SK_WIRE);
1099223637Sbz			return (-1);
1100223637Sbz		}
1101126258Smlaier	}
1102126258Smlaier
1103223637Sbz	if (s->id == 0 && s->creatorid == 0) {
1104223637Sbz#ifdef __FreeBSD__
1105223637Sbz		s->id = htobe64(V_pf_status.stateid++);
1106223637Sbz		s->creatorid = V_pf_status.hostid;
1107223637Sbz#else
1108223637Sbz		s->id = htobe64(pf_status.stateid++);
1109223637Sbz		s->creatorid = pf_status.hostid;
1110223637Sbz#endif
1111130613Smlaier	}
1112223637Sbz#ifdef __FreeBSD__
1113223637Sbz	if (RB_INSERT(pf_state_tree_id, &V_tree_id, s) != NULL) {
1114223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC) {
1115223637Sbz#else
1116223637Sbz	if (RB_INSERT(pf_state_tree_id, &tree_id, s) != NULL) {
1117130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
1118223637Sbz#endif
1119130613Smlaier			printf("pf: state insert failed: "
1120130613Smlaier			    "id: %016llx creatorid: %08x",
1121223637Sbz#ifdef __FreeBSD__
1122223637Sbz			    (unsigned long long)betoh64(s->id), ntohl(s->creatorid));
1123130613Smlaier#else
1124223637Sbz			    betoh64(s->id), ntohl(s->creatorid));
1125130613Smlaier#endif
1126130613Smlaier			printf("\n");
1127130613Smlaier		}
1128223637Sbz		pf_detach_state(s);
1129130613Smlaier		return (-1);
1130130613Smlaier	}
1131223637Sbz#ifdef __FreeBSD__
1132223637Sbz	TAILQ_INSERT_TAIL(&V_state_list, s, entry_list);
1133223637Sbz	V_pf_status.fcounters[FCNT_STATE_INSERT]++;
1134223637Sbz	V_pf_status.states++;
1135223637Sbz#else
1136223637Sbz	TAILQ_INSERT_TAIL(&state_list, s, entry_list);
1137126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
1138126258Smlaier	pf_status.states++;
1139223637Sbz#endif
1140171168Smlaier	pfi_kif_ref(kif, PFI_KIF_REF_STATE);
1141223637Sbz#if NPFSYNC > 0
1142223637Sbz#ifdef __FreeBSD__
1143223637Sbz	if (pfsync_insert_state_ptr != NULL)
1144223637Sbz		pfsync_insert_state_ptr(s);
1145223637Sbz#else
1146223637Sbz	pfsync_insert_state(s);
1147126258Smlaier#endif
1148223637Sbz#endif
1149126258Smlaier	return (0);
1150126258Smlaier}
1151126258Smlaier
1152223637Sbzstruct pf_state *
1153223637Sbzpf_find_state_byid(struct pf_state_cmp *key)
1154223637Sbz{
1155223637Sbz#ifdef __FreeBSD__
1156223637Sbz	V_pf_status.fcounters[FCNT_STATE_SEARCH]++;
1157223637Sbz
1158223637Sbz	return (RB_FIND(pf_state_tree_id, &V_tree_id, (struct pf_state *)key));
1159223637Sbz#else
1160223637Sbz	pf_status.fcounters[FCNT_STATE_SEARCH]++;
1161223637Sbz
1162223637Sbz	return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
1163223637Sbz#endif
1164223637Sbz}
1165223637Sbz
1166223637Sbz/* XXX debug function, intended to be removed one day */
1167223637Sbzint
1168223637Sbzpf_compare_state_keys(struct pf_state_key *a, struct pf_state_key *b,
1169223637Sbz    struct pfi_kif *kif, u_int dir)
1170223637Sbz{
1171223637Sbz	/* a (from hdr) and b (new) must be exact opposites of each other */
1172223637Sbz	if (a->af == b->af && a->proto == b->proto &&
1173223637Sbz	    PF_AEQ(&a->addr[0], &b->addr[1], a->af) &&
1174223637Sbz	    PF_AEQ(&a->addr[1], &b->addr[0], a->af) &&
1175223637Sbz	    a->port[0] == b->port[1] &&
1176223637Sbz	    a->port[1] == b->port[0])
1177223637Sbz		return (0);
1178223637Sbz	else {
1179223637Sbz		/* mismatch. must not happen. */
1180223637Sbz		printf("pf: state key linking mismatch! dir=%s, "
1181223637Sbz		    "if=%s, stored af=%u, a0: ",
1182223637Sbz		    dir == PF_OUT ? "OUT" : "IN", kif->pfik_name, a->af);
1183223637Sbz		pf_print_host(&a->addr[0], a->port[0], a->af);
1184223637Sbz		printf(", a1: ");
1185223637Sbz		pf_print_host(&a->addr[1], a->port[1], a->af);
1186223637Sbz		printf(", proto=%u", a->proto);
1187223637Sbz		printf(", found af=%u, a0: ", b->af);
1188223637Sbz		pf_print_host(&b->addr[0], b->port[0], b->af);
1189223637Sbz		printf(", a1: ");
1190223637Sbz		pf_print_host(&b->addr[1], b->port[1], b->af);
1191223637Sbz		printf(", proto=%u", b->proto);
1192223637Sbz		printf(".\n");
1193223637Sbz		return (-1);
1194223637Sbz	}
1195223637Sbz}
1196223637Sbz
1197223637Sbzstruct pf_state *
1198223637Sbz#ifdef __FreeBSD__
1199223637Sbzpf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir,
1200223637Sbz    struct mbuf *m, struct pf_mtag *pftag)
1201223637Sbz#else
1202223637Sbzpf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir,
1203223637Sbz    struct mbuf *m)
1204223637Sbz#endif
1205223637Sbz{
1206223637Sbz	struct pf_state_key	*sk;
1207223637Sbz	struct pf_state_item	*si;
1208223637Sbz
1209223637Sbz#ifdef __FreeBSD__
1210223637Sbz	V_pf_status.fcounters[FCNT_STATE_SEARCH]++;
1211223637Sbz#else
1212223637Sbz	pf_status.fcounters[FCNT_STATE_SEARCH]++;
1213223637Sbz#endif
1214223637Sbz
1215223637Sbz#ifdef __FreeBSD__
1216223637Sbz	if (dir == PF_OUT && pftag->statekey &&
1217223637Sbz	    ((struct pf_state_key *)pftag->statekey)->reverse)
1218223637Sbz		sk = ((struct pf_state_key *)pftag->statekey)->reverse;
1219223637Sbz	else {
1220223637Sbz#ifdef __FreeBSD__
1221223637Sbz		if ((sk = RB_FIND(pf_state_tree, &V_pf_statetbl,
1222223637Sbz#else
1223223637Sbz		if ((sk = RB_FIND(pf_state_tree, &pf_statetbl,
1224223637Sbz#endif
1225223637Sbz		    (struct pf_state_key *)key)) == NULL)
1226223637Sbz			return (NULL);
1227223637Sbz		if (dir == PF_OUT && pftag->statekey &&
1228223637Sbz		    pf_compare_state_keys(pftag->statekey, sk,
1229223637Sbz		    kif, dir) == 0) {
1230223637Sbz			((struct pf_state_key *)
1231223637Sbz			    pftag->statekey)->reverse = sk;
1232223637Sbz			sk->reverse = pftag->statekey;
1233223637Sbz		}
1234223637Sbz	}
1235223637Sbz#else
1236223637Sbz	if (dir == PF_OUT && m->m_pkthdr.pf.statekey &&
1237223637Sbz	    ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse)
1238223637Sbz		sk = ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse;
1239223637Sbz	else {
1240223637Sbz#ifdef __FreeBSD__
1241223637Sbz		if ((sk = RB_FIND(pf_state_tree, &V_pf_statetbl,
1242223637Sbz#else
1243223637Sbz		if ((sk = RB_FIND(pf_state_tree, &pf_statetbl,
1244223637Sbz#endif
1245223637Sbz		    (struct pf_state_key *)key)) == NULL)
1246223637Sbz			return (NULL);
1247223637Sbz		if (dir == PF_OUT && m->m_pkthdr.pf.statekey &&
1248223637Sbz		    pf_compare_state_keys(m->m_pkthdr.pf.statekey, sk,
1249223637Sbz		    kif, dir) == 0) {
1250223637Sbz			((struct pf_state_key *)
1251223637Sbz			    m->m_pkthdr.pf.statekey)->reverse = sk;
1252223637Sbz			sk->reverse = m->m_pkthdr.pf.statekey;
1253223637Sbz		}
1254223637Sbz	}
1255223637Sbz#endif
1256223637Sbz
1257223637Sbz	if (dir == PF_OUT)
1258223637Sbz#ifdef __FreeBSD__
1259223637Sbz		pftag->statekey = NULL;
1260223637Sbz#else
1261223637Sbz		m->m_pkthdr.pf.statekey = NULL;
1262223637Sbz#endif
1263223637Sbz
1264223637Sbz	/* list is sorted, if-bound states before floating ones */
1265223637Sbz	TAILQ_FOREACH(si, &sk->states, entry)
1266223637Sbz#ifdef __FreeBSD__
1267223637Sbz		if ((si->s->kif == V_pfi_all || si->s->kif == kif) &&
1268223637Sbz#else
1269223637Sbz		if ((si->s->kif == pfi_all || si->s->kif == kif) &&
1270223637Sbz#endif
1271223637Sbz		    sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] :
1272223637Sbz		    si->s->key[PF_SK_STACK]))
1273223637Sbz			return (si->s);
1274223637Sbz
1275223637Sbz	return (NULL);
1276223637Sbz}
1277223637Sbz
1278223637Sbzstruct pf_state *
1279223637Sbzpf_find_state_all(struct pf_state_key_cmp *key, u_int dir, int *more)
1280223637Sbz{
1281223637Sbz	struct pf_state_key	*sk;
1282223637Sbz	struct pf_state_item	*si, *ret = NULL;
1283223637Sbz
1284223637Sbz#ifdef __FreeBSD__
1285223637Sbz	V_pf_status.fcounters[FCNT_STATE_SEARCH]++;
1286223637Sbz#else
1287223637Sbz	pf_status.fcounters[FCNT_STATE_SEARCH]++;
1288223637Sbz#endif
1289223637Sbz
1290223637Sbz#ifdef __FreeBSD__
1291223637Sbz	sk = RB_FIND(pf_state_tree, &V_pf_statetbl, (struct pf_state_key *)key);
1292223637Sbz#else
1293223637Sbz	sk = RB_FIND(pf_state_tree, &pf_statetbl, (struct pf_state_key *)key);
1294223637Sbz#endif
1295223637Sbz	if (sk != NULL) {
1296223637Sbz		TAILQ_FOREACH(si, &sk->states, entry)
1297223637Sbz			if (dir == PF_INOUT ||
1298223637Sbz			    (sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] :
1299223637Sbz			    si->s->key[PF_SK_STACK]))) {
1300223637Sbz				if (more == NULL)
1301223637Sbz					return (si->s);
1302223637Sbz
1303223637Sbz				if (ret)
1304223637Sbz					(*more)++;
1305223637Sbz				else
1306223637Sbz					ret = si;
1307223637Sbz			}
1308223637Sbz	}
1309223637Sbz	return (ret ? ret->s : NULL);
1310223637Sbz}
1311223637Sbz
1312223637Sbz/* END state table stuff */
1313223637Sbz
1314223637Sbz
1315126258Smlaiervoid
1316171168Smlaierpf_purge_thread(void *v)
1317126258Smlaier{
1318171168Smlaier	int nloops = 0, s;
1319196372Smlaier#ifdef __FreeBSD__
1320196372Smlaier	int locked;
1321196372Smlaier#endif
1322171168Smlaier
1323223637Sbz	CURVNET_SET((struct vnet *)v);
1324223637Sbz
1325171168Smlaier	for (;;) {
1326171168Smlaier		tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
1327171168Smlaier
1328127145Smlaier#ifdef __FreeBSD__
1329226796Sbz		sx_slock(&V_pf_consistency_lock);
1330171168Smlaier		PF_LOCK();
1331226796Sbz		locked = 0;
1332126258Smlaier
1333226796Sbz		if (V_pf_end_threads) {
1334226796Sbz			PF_UNLOCK();
1335226796Sbz			sx_sunlock(&V_pf_consistency_lock);
1336226796Sbz			sx_xlock(&V_pf_consistency_lock);
1337226796Sbz			PF_LOCK();
1338171168Smlaier
1339226796Sbz			pf_purge_expired_states(V_pf_status.states, 1);
1340226796Sbz			pf_purge_expired_fragments();
1341226796Sbz			pf_purge_expired_src_nodes(1);
1342226796Sbz			V_pf_end_threads++;
1343226796Sbz
1344226796Sbz			sx_xunlock(&V_pf_consistency_lock);
1345226796Sbz			PF_UNLOCK();
1346226796Sbz			wakeup(pf_purge_thread);
1347226796Sbz			kproc_exit(0);
1348226796Sbz		}
1349126261Smlaier#endif
1350171168Smlaier		s = splsoftnet();
1351126258Smlaier
1352171168Smlaier		/* process a fraction of the state table every second */
1353196372Smlaier#ifdef __FreeBSD__
1354226796Sbz		if (!pf_purge_expired_states(1 + (V_pf_status.states /
1355226796Sbz		    V_pf_default_rule.timeout[PFTM_INTERVAL]), 0)) {
1356226796Sbz			PF_UNLOCK();
1357226796Sbz			sx_sunlock(&V_pf_consistency_lock);
1358226796Sbz			sx_xlock(&V_pf_consistency_lock);
1359226796Sbz			PF_LOCK();
1360226796Sbz			locked = 1;
1361196372Smlaier
1362226796Sbz			pf_purge_expired_states(1 + (V_pf_status.states /
1363226796Sbz			    V_pf_default_rule.timeout[PFTM_INTERVAL]), 1);
1364226796Sbz		}
1365196372Smlaier#else
1366171168Smlaier		pf_purge_expired_states(1 + (pf_status.states
1367171168Smlaier		    / pf_default_rule.timeout[PFTM_INTERVAL]));
1368196372Smlaier#endif
1369171168Smlaier
1370171168Smlaier		/* purge other expired types every PFTM_INTERVAL seconds */
1371223637Sbz#ifdef __FreeBSD__
1372223637Sbz		if (++nloops >= V_pf_default_rule.timeout[PFTM_INTERVAL]) {
1373223637Sbz#else
1374171168Smlaier		if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
1375223637Sbz#endif
1376171168Smlaier			pf_purge_expired_fragments();
1377223637Sbz			pf_purge_expired_src_nodes(0);
1378171168Smlaier			nloops = 0;
1379171168Smlaier		}
1380171168Smlaier
1381171168Smlaier		splx(s);
1382127145Smlaier#ifdef __FreeBSD__
1383171168Smlaier		PF_UNLOCK();
1384196372Smlaier		if (locked)
1385223637Sbz			sx_xunlock(&V_pf_consistency_lock);
1386196372Smlaier		else
1387223637Sbz			sx_sunlock(&V_pf_consistency_lock);
1388126261Smlaier#endif
1389171168Smlaier	}
1390223637Sbz	CURVNET_RESTORE();
1391126258Smlaier}
1392126258Smlaier
1393126258Smlaieru_int32_t
1394126258Smlaierpf_state_expires(const struct pf_state *state)
1395126258Smlaier{
1396126258Smlaier	u_int32_t	timeout;
1397126258Smlaier	u_int32_t	start;
1398126258Smlaier	u_int32_t	end;
1399126258Smlaier	u_int32_t	states;
1400126258Smlaier
1401126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
1402126258Smlaier	if (state->timeout == PFTM_PURGE)
1403126261Smlaier		return (time_second);
1404126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1405126258Smlaier		return (0);
1406223637Sbz#ifdef __FreeBSD__
1407171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED,
1408171168Smlaier	    ("pf_state_expires: timeout == PFTM_UNLINKED"));
1409126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1410126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1411126261Smlaier#else
1412171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED);
1413126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1414126261Smlaier#endif
1415126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1416126258Smlaier	if (!timeout)
1417223637Sbz#ifdef __FreeBSD__
1418223637Sbz		timeout = V_pf_default_rule.timeout[state->timeout];
1419223637Sbz#else
1420126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1421223637Sbz#endif
1422126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1423126258Smlaier	if (start) {
1424126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1425223637Sbz		states = state->rule.ptr->states_cur;
1426126258Smlaier	} else {
1427223637Sbz#ifdef __FreeBSD__
1428223637Sbz		start = V_pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1429223637Sbz		end = V_pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1430223637Sbz		states = V_pf_status.states;
1431223637Sbz#else
1432126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1433126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1434126258Smlaier		states = pf_status.states;
1435223637Sbz#endif
1436126258Smlaier	}
1437126258Smlaier	if (end && states > start && start < end) {
1438126258Smlaier		if (states < end)
1439126258Smlaier			return (state->expire + timeout * (end - states) /
1440126258Smlaier			    (end - start));
1441126258Smlaier		else
1442126261Smlaier			return (time_second);
1443126258Smlaier	}
1444126258Smlaier	return (state->expire + timeout);
1445126258Smlaier}
1446126258Smlaier
1447196372Smlaier#ifdef __FreeBSD__
1448196372Smlaierint
1449196372Smlaierpf_purge_expired_src_nodes(int waslocked)
1450196372Smlaier#else
1451126258Smlaiervoid
1452171168Smlaierpf_purge_expired_src_nodes(int waslocked)
1453196372Smlaier#endif
1454126258Smlaier{
1455223637Sbz	struct pf_src_node		*cur, *next;
1456223637Sbz	int				 locked = waslocked;
1457126258Smlaier
1458171168Smlaier#ifdef __FreeBSD__
1459223637Sbz	for (cur = RB_MIN(pf_src_tree, &V_tree_src_tracking); cur; cur = next) {
1460223637Sbz	next = RB_NEXT(pf_src_tree, &V_tree_src_tracking, cur);
1461171168Smlaier#else
1462223637Sbz	for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1463223637Sbz	next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1464171168Smlaier#endif
1465171168Smlaier
1466223637Sbz		if (cur->states <= 0 && cur->expire <= time_second) {
1467223637Sbz			if (! locked) {
1468171168Smlaier#ifdef __FreeBSD__
1469223637Sbz				if (!sx_try_upgrade(&V_pf_consistency_lock))
1470223637Sbz					return (0);
1471171168Smlaier#else
1472223637Sbz				rw_enter_write(&pf_consistency_lock);
1473171168Smlaier#endif
1474223637Sbz				next = RB_NEXT(pf_src_tree,
1475223637Sbz#ifdef __FreeBSD__
1476223637Sbz				    &V_tree_src_tracking, cur);
1477223637Sbz#else
1478223637Sbz				    &tree_src_tracking, cur);
1479223637Sbz#endif
1480223637Sbz				locked = 1;
1481223637Sbz			}
1482223637Sbz			if (cur->rule.ptr != NULL) {
1483223637Sbz				cur->rule.ptr->src_nodes--;
1484223637Sbz				if (cur->rule.ptr->states_cur <= 0 &&
1485223637Sbz				    cur->rule.ptr->max_src_nodes <= 0)
1486223637Sbz					pf_rm_rule(NULL, cur->rule.ptr);
1487223637Sbz			}
1488223637Sbz#ifdef __FreeBSD__
1489223637Sbz			RB_REMOVE(pf_src_tree, &V_tree_src_tracking, cur);
1490223637Sbz			V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1491223637Sbz			V_pf_status.src_nodes--;
1492223637Sbz			pool_put(&V_pf_src_tree_pl, cur);
1493223637Sbz#else
1494223637Sbz			RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1495223637Sbz			pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1496223637Sbz			pf_status.src_nodes--;
1497223637Sbz			pool_put(&pf_src_tree_pl, cur);
1498223637Sbz#endif
1499223637Sbz		}
1500223637Sbz	}
1501196372Smlaier
1502223637Sbz	if (locked && !waslocked)
1503196372Smlaier#ifdef __FreeBSD__
1504223637Sbz	{
1505223637Sbz		sx_downgrade(&V_pf_consistency_lock);
1506223637Sbz	}
1507196372Smlaier	return (1);
1508223637Sbz#else
1509223637Sbz		rw_exit_write(&pf_consistency_lock);
1510196372Smlaier#endif
1511130613Smlaier}
1512126258Smlaier
1513130613Smlaiervoid
1514130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1515130613Smlaier{
1516130613Smlaier	u_int32_t timeout;
1517126258Smlaier
1518130613Smlaier	if (s->src_node != NULL) {
1519223637Sbz		if (s->src.tcp_est)
1520223637Sbz			--s->src_node->conn;
1521130613Smlaier		if (--s->src_node->states <= 0) {
1522130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1523130613Smlaier			if (!timeout)
1524130613Smlaier				timeout =
1525223637Sbz#ifdef __FreeBSD__
1526223637Sbz				    V_pf_default_rule.timeout[PFTM_SRC_NODE];
1527223637Sbz#else
1528130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1529223637Sbz#endif
1530130613Smlaier			s->src_node->expire = time_second + timeout;
1531130613Smlaier		}
1532130613Smlaier	}
1533130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1534130613Smlaier		if (--s->nat_src_node->states <= 0) {
1535130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1536130613Smlaier			if (!timeout)
1537130613Smlaier				timeout =
1538223637Sbz#ifdef __FreeBSD__
1539223637Sbz				    V_pf_default_rule.timeout[PFTM_SRC_NODE];
1540223637Sbz#else
1541130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1542223637Sbz#endif
1543130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1544130613Smlaier		}
1545130613Smlaier	}
1546130613Smlaier	s->src_node = s->nat_src_node = NULL;
1547130613Smlaier}
1548126258Smlaier
1549171168Smlaier/* callers should be at splsoftnet */
1550130613Smlaiervoid
1551171168Smlaierpf_unlink_state(struct pf_state *cur)
1552145836Smlaier{
1553148196Smlaier#ifdef __FreeBSD__
1554153545Smlaier	if (cur->local_flags & PFSTATE_EXPIRING)
1555148196Smlaier		return;
1556153545Smlaier	cur->local_flags |= PFSTATE_EXPIRING;
1557223637Sbz#else
1558223637Sbz	splassert(IPL_SOFTNET);
1559148196Smlaier#endif
1560223637Sbz
1561171168Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST) {
1562223637Sbz		/* XXX wire key the right one? */
1563162238Scsjp#ifdef __FreeBSD__
1564223637Sbz		pf_send_tcp(NULL, cur->rule.ptr, cur->key[PF_SK_WIRE]->af,
1565162238Scsjp#else
1566223637Sbz		pf_send_tcp(cur->rule.ptr, cur->key[PF_SK_WIRE]->af,
1567162238Scsjp#endif
1568223637Sbz		    &cur->key[PF_SK_WIRE]->addr[1],
1569223637Sbz		    &cur->key[PF_SK_WIRE]->addr[0],
1570223637Sbz		    cur->key[PF_SK_WIRE]->port[1],
1571223637Sbz		    cur->key[PF_SK_WIRE]->port[0],
1572145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1573171168Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
1574171168Smlaier	}
1575223637Sbz#ifdef __FreeBSD__
1576223637Sbz	RB_REMOVE(pf_state_tree_id, &V_tree_id, cur);
1577223637Sbz#else
1578145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1579145836Smlaier#endif
1580223637Sbz#if NPFLOW > 0
1581223637Sbz	if (cur->state_flags & PFSTATE_PFLOW)
1582223637Sbz#ifdef __FreeBSD__
1583223637Sbz		if (export_pflow_ptr != NULL)
1584223637Sbz			export_pflow_ptr(cur);
1585223637Sbz#else
1586223637Sbz		export_pflow(cur);
1587223637Sbz#endif
1588223637Sbz#endif
1589223637Sbz#if NPFSYNC > 0
1590223637Sbz#ifdef __FreeBSD__
1591223637Sbz	if (pfsync_delete_state_ptr != NULL)
1592223637Sbz		pfsync_delete_state_ptr(cur);
1593223637Sbz#else
1594223637Sbz	pfsync_delete_state(cur);
1595223637Sbz#endif
1596223637Sbz#endif
1597171168Smlaier	cur->timeout = PFTM_UNLINKED;
1598145836Smlaier	pf_src_tree_remove_state(cur);
1599223637Sbz	pf_detach_state(cur);
1600171168Smlaier}
1601171168Smlaier
1602171168Smlaier/* callers should be at splsoftnet and hold the
1603171168Smlaier * write_lock on pf_consistency_lock */
1604171168Smlaiervoid
1605171168Smlaierpf_free_state(struct pf_state *cur)
1606171168Smlaier{
1607223637Sbz#ifndef __FreeBSD__
1608223637Sbz	splassert(IPL_SOFTNET);
1609223637Sbz#endif
1610223637Sbz
1611223637Sbz#if NPFSYNC > 0
1612223637Sbz#ifdef __FreeBSD__
1613226796Sbz	if (pfsync_state_in_use_ptr != NULL &&
1614226796Sbz		pfsync_state_in_use_ptr(cur))
1615223637Sbz#else
1616223637Sbz	if (pfsync_state_in_use(cur))
1617223637Sbz#endif
1618171168Smlaier		return;
1619171168Smlaier#endif
1620171168Smlaier#ifdef __FreeBSD__
1621171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED,
1622171168Smlaier	    ("pf_free_state: cur->timeout != PFTM_UNLINKED"));
1623171168Smlaier#else
1624171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED);
1625171168Smlaier#endif
1626223637Sbz	if (--cur->rule.ptr->states_cur <= 0 &&
1627145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1628145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1629145836Smlaier	if (cur->nat_rule.ptr != NULL)
1630223637Sbz		if (--cur->nat_rule.ptr->states_cur <= 0 &&
1631145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1632145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1633145836Smlaier	if (cur->anchor.ptr != NULL)
1634223637Sbz		if (--cur->anchor.ptr->states_cur <= 0)
1635145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1636145836Smlaier	pf_normalize_tcp_cleanup(cur);
1637223637Sbz	pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
1638223637Sbz#ifdef __FreeBSD__
1639223637Sbz	TAILQ_REMOVE(&V_state_list, cur, entry_list);
1640223637Sbz#else
1641223637Sbz	TAILQ_REMOVE(&state_list, cur, entry_list);
1642223637Sbz#endif
1643145836Smlaier	if (cur->tag)
1644145836Smlaier		pf_tag_unref(cur->tag);
1645223637Sbz#ifdef __FreeBSD__
1646223637Sbz	pool_put(&V_pf_state_pl, cur);
1647223637Sbz	V_pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1648223637Sbz	V_pf_status.states--;
1649223637Sbz#else
1650145836Smlaier	pool_put(&pf_state_pl, cur);
1651145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1652145836Smlaier	pf_status.states--;
1653223637Sbz#endif
1654145836Smlaier}
1655145836Smlaier
1656196372Smlaier#ifdef __FreeBSD__
1657196372Smlaierint
1658196372Smlaierpf_purge_expired_states(u_int32_t maxcheck, int waslocked)
1659196372Smlaier#else
1660145836Smlaiervoid
1661171168Smlaierpf_purge_expired_states(u_int32_t maxcheck)
1662196372Smlaier#endif
1663130613Smlaier{
1664171168Smlaier	static struct pf_state	*cur = NULL;
1665171168Smlaier	struct pf_state		*next;
1666196372Smlaier#ifdef __FreeBSD__
1667223637Sbz	int			 locked = waslocked;
1668196372Smlaier#else
1669223637Sbz	int			 locked = 0;
1670196372Smlaier#endif
1671130613Smlaier
1672171168Smlaier	while (maxcheck--) {
1673171168Smlaier		/* wrap to start of list when we hit the end */
1674171168Smlaier		if (cur == NULL) {
1675223637Sbz#ifdef __FreeBSD__
1676223637Sbz			cur = TAILQ_FIRST(&V_state_list);
1677223637Sbz#else
1678171168Smlaier			cur = TAILQ_FIRST(&state_list);
1679223637Sbz#endif
1680171168Smlaier			if (cur == NULL)
1681171168Smlaier				break;	/* list empty */
1682171168Smlaier		}
1683171168Smlaier
1684171168Smlaier		/* get next state, as cur may get deleted */
1685223637Sbz		next = TAILQ_NEXT(cur, entry_list);
1686171168Smlaier
1687171168Smlaier		if (cur->timeout == PFTM_UNLINKED) {
1688171168Smlaier			/* free unlinked state */
1689171168Smlaier			if (! locked) {
1690171168Smlaier#ifdef __FreeBSD__
1691223637Sbz				if (!sx_try_upgrade(&V_pf_consistency_lock))
1692223637Sbz					return (0);
1693171168Smlaier#else
1694171168Smlaier				rw_enter_write(&pf_consistency_lock);
1695171168Smlaier#endif
1696171168Smlaier				locked = 1;
1697171168Smlaier			}
1698171168Smlaier			pf_free_state(cur);
1699171168Smlaier		} else if (pf_state_expires(cur) <= time_second) {
1700171168Smlaier			/* unlink and free expired state */
1701171168Smlaier			pf_unlink_state(cur);
1702171168Smlaier			if (! locked) {
1703171168Smlaier#ifdef __FreeBSD__
1704223637Sbz				if (!sx_try_upgrade(&V_pf_consistency_lock))
1705223637Sbz					return (0);
1706171168Smlaier#else
1707171168Smlaier				rw_enter_write(&pf_consistency_lock);
1708171168Smlaier#endif
1709171168Smlaier				locked = 1;
1710171168Smlaier			}
1711171168Smlaier			pf_free_state(cur);
1712171168Smlaier		}
1713171168Smlaier		cur = next;
1714126258Smlaier	}
1715171168Smlaier
1716171168Smlaier#ifdef __FreeBSD__
1717196372Smlaier	if (!waslocked && locked)
1718223637Sbz		sx_downgrade(&V_pf_consistency_lock);
1719196372Smlaier
1720196372Smlaier	return (1);
1721171168Smlaier#else
1722196372Smlaier	if (locked)
1723171168Smlaier		rw_exit_write(&pf_consistency_lock);
1724171168Smlaier#endif
1725126258Smlaier}
1726126258Smlaier
1727126258Smlaierint
1728126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1729126258Smlaier{
1730126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1731126258Smlaier		return (0);
1732223637Sbz	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname, 1)) == NULL)
1733126258Smlaier		return (1);
1734126258Smlaier	return (0);
1735126258Smlaier}
1736126258Smlaier
1737126258Smlaiervoid
1738126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1739126258Smlaier{
1740126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1741126258Smlaier		return;
1742126258Smlaier	pfr_detach_table(aw->p.tbl);
1743126258Smlaier	aw->p.tbl = NULL;
1744126258Smlaier}
1745126258Smlaier
1746126258Smlaiervoid
1747126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1748126258Smlaier{
1749126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1750126258Smlaier
1751126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1752126258Smlaier		return;
1753126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1754126258Smlaier		kt = kt->pfrkt_root;
1755126258Smlaier	aw->p.tbl = NULL;
1756126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1757126258Smlaier		kt->pfrkt_cnt : -1;
1758126258Smlaier}
1759126258Smlaier
1760126258Smlaiervoid
1761126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1762126258Smlaier{
1763126258Smlaier	switch (af) {
1764126258Smlaier#ifdef INET
1765126258Smlaier	case AF_INET: {
1766126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1767126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1768126258Smlaier		    (a>>8)&255, a&255);
1769126258Smlaier		if (p) {
1770126258Smlaier			p = ntohs(p);
1771126258Smlaier			printf(":%u", p);
1772126258Smlaier		}
1773126258Smlaier		break;
1774126258Smlaier	}
1775126258Smlaier#endif /* INET */
1776126258Smlaier#ifdef INET6
1777126258Smlaier	case AF_INET6: {
1778126258Smlaier		u_int16_t b;
1779223637Sbz		u_int8_t i, curstart, curend, maxstart, maxend;
1780223637Sbz		curstart = curend = maxstart = maxend = 255;
1781126258Smlaier		for (i = 0; i < 8; i++) {
1782126258Smlaier			if (!addr->addr16[i]) {
1783126258Smlaier				if (curstart == 255)
1784126258Smlaier					curstart = i;
1785223637Sbz				curend = i;
1786126258Smlaier			} else {
1787223637Sbz				if ((curend - curstart) >
1788223637Sbz				    (maxend - maxstart)) {
1789223637Sbz					maxstart = curstart;
1790223637Sbz					maxend = curend;
1791126258Smlaier				}
1792223637Sbz				curstart = curend = 255;
1793126258Smlaier			}
1794126258Smlaier		}
1795223637Sbz		if ((curend - curstart) >
1796223637Sbz		    (maxend - maxstart)) {
1797223637Sbz			maxstart = curstart;
1798223637Sbz			maxend = curend;
1799223637Sbz		}
1800126258Smlaier		for (i = 0; i < 8; i++) {
1801126258Smlaier			if (i >= maxstart && i <= maxend) {
1802223637Sbz				if (i == 0)
1803223637Sbz					printf(":");
1804223637Sbz				if (i == maxend)
1805223637Sbz					printf(":");
1806126258Smlaier			} else {
1807126258Smlaier				b = ntohs(addr->addr16[i]);
1808126258Smlaier				printf("%x", b);
1809126258Smlaier				if (i < 7)
1810126258Smlaier					printf(":");
1811126258Smlaier			}
1812126258Smlaier		}
1813126258Smlaier		if (p) {
1814126258Smlaier			p = ntohs(p);
1815126258Smlaier			printf("[%u]", p);
1816126258Smlaier		}
1817126258Smlaier		break;
1818126258Smlaier	}
1819126258Smlaier#endif /* INET6 */
1820126258Smlaier	}
1821126258Smlaier}
1822126258Smlaier
1823126258Smlaiervoid
1824126258Smlaierpf_print_state(struct pf_state *s)
1825126258Smlaier{
1826223637Sbz	pf_print_state_parts(s, NULL, NULL);
1827223637Sbz}
1828223637Sbz
1829223637Sbzvoid
1830223637Sbzpf_print_state_parts(struct pf_state *s,
1831223637Sbz    struct pf_state_key *skwp, struct pf_state_key *sksp)
1832223637Sbz{
1833223637Sbz	struct pf_state_key *skw, *sks;
1834223637Sbz	u_int8_t proto, dir;
1835223637Sbz
1836223637Sbz	/* Do our best to fill these, but they're skipped if NULL */
1837223637Sbz	skw = skwp ? skwp : (s ? s->key[PF_SK_WIRE] : NULL);
1838223637Sbz	sks = sksp ? sksp : (s ? s->key[PF_SK_STACK] : NULL);
1839223637Sbz	proto = skw ? skw->proto : (sks ? sks->proto : 0);
1840223637Sbz	dir = s ? s->direction : 0;
1841223637Sbz
1842223637Sbz	switch (proto) {
1843223637Sbz	case IPPROTO_IPV4:
1844223637Sbz		printf("IPv4");
1845223637Sbz		break;
1846223637Sbz	case IPPROTO_IPV6:
1847223637Sbz		printf("IPv6");
1848223637Sbz		break;
1849126258Smlaier	case IPPROTO_TCP:
1850223637Sbz		printf("TCP");
1851126258Smlaier		break;
1852126258Smlaier	case IPPROTO_UDP:
1853223637Sbz		printf("UDP");
1854126258Smlaier		break;
1855126258Smlaier	case IPPROTO_ICMP:
1856223637Sbz		printf("ICMP");
1857126258Smlaier		break;
1858126258Smlaier	case IPPROTO_ICMPV6:
1859223637Sbz		printf("ICMPv6");
1860126258Smlaier		break;
1861126258Smlaier	default:
1862223637Sbz		printf("%u", skw->proto);
1863126258Smlaier		break;
1864126258Smlaier	}
1865223637Sbz	switch (dir) {
1866223637Sbz	case PF_IN:
1867223637Sbz		printf(" in");
1868223637Sbz		break;
1869223637Sbz	case PF_OUT:
1870223637Sbz		printf(" out");
1871223637Sbz		break;
1872223637Sbz	}
1873223637Sbz	if (skw) {
1874223637Sbz		printf(" wire: ");
1875223637Sbz		pf_print_host(&skw->addr[0], skw->port[0], skw->af);
1876223637Sbz		printf(" ");
1877223637Sbz		pf_print_host(&skw->addr[1], skw->port[1], skw->af);
1878223637Sbz	}
1879223637Sbz	if (sks) {
1880223637Sbz		printf(" stack: ");
1881223637Sbz		if (sks != skw) {
1882223637Sbz			pf_print_host(&sks->addr[0], sks->port[0], sks->af);
1883223637Sbz			printf(" ");
1884223637Sbz			pf_print_host(&sks->addr[1], sks->port[1], sks->af);
1885223637Sbz		} else
1886223637Sbz			printf("-");
1887223637Sbz	}
1888223637Sbz	if (s) {
1889223637Sbz		if (proto == IPPROTO_TCP) {
1890223637Sbz			printf(" [lo=%u high=%u win=%u modulator=%u",
1891223637Sbz			    s->src.seqlo, s->src.seqhi,
1892223637Sbz			    s->src.max_win, s->src.seqdiff);
1893223637Sbz			if (s->src.wscale && s->dst.wscale)
1894223637Sbz				printf(" wscale=%u",
1895223637Sbz				    s->src.wscale & PF_WSCALE_MASK);
1896223637Sbz			printf("]");
1897223637Sbz			printf(" [lo=%u high=%u win=%u modulator=%u",
1898223637Sbz			    s->dst.seqlo, s->dst.seqhi,
1899223637Sbz			    s->dst.max_win, s->dst.seqdiff);
1900223637Sbz			if (s->src.wscale && s->dst.wscale)
1901223637Sbz				printf(" wscale=%u",
1902223637Sbz				s->dst.wscale & PF_WSCALE_MASK);
1903223637Sbz			printf("]");
1904223637Sbz		}
1905223637Sbz		printf(" %u:%u", s->src.state, s->dst.state);
1906223637Sbz	}
1907126258Smlaier}
1908126258Smlaier
1909126258Smlaiervoid
1910126258Smlaierpf_print_flags(u_int8_t f)
1911126258Smlaier{
1912126258Smlaier	if (f)
1913126258Smlaier		printf(" ");
1914126258Smlaier	if (f & TH_FIN)
1915126258Smlaier		printf("F");
1916126258Smlaier	if (f & TH_SYN)
1917126258Smlaier		printf("S");
1918126258Smlaier	if (f & TH_RST)
1919126258Smlaier		printf("R");
1920126258Smlaier	if (f & TH_PUSH)
1921126258Smlaier		printf("P");
1922126258Smlaier	if (f & TH_ACK)
1923126258Smlaier		printf("A");
1924126258Smlaier	if (f & TH_URG)
1925126258Smlaier		printf("U");
1926126258Smlaier	if (f & TH_ECE)
1927126258Smlaier		printf("E");
1928126258Smlaier	if (f & TH_CWR)
1929126258Smlaier		printf("W");
1930126258Smlaier}
1931126258Smlaier
1932126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1933126258Smlaier	do {							\
1934126258Smlaier		while (head[i] != cur) {			\
1935126258Smlaier			head[i]->skip[i].ptr = cur;		\
1936126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1937126258Smlaier		}						\
1938126258Smlaier	} while (0)
1939126258Smlaier
1940126258Smlaiervoid
1941126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1942126258Smlaier{
1943126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1944126258Smlaier	int i;
1945126258Smlaier
1946126258Smlaier	cur = TAILQ_FIRST(rules);
1947126258Smlaier	prev = cur;
1948126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1949126258Smlaier		head[i] = cur;
1950126258Smlaier	while (cur != NULL) {
1951126258Smlaier
1952130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1953126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1954126258Smlaier		if (cur->direction != prev->direction)
1955126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1956126258Smlaier		if (cur->af != prev->af)
1957126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1958126258Smlaier		if (cur->proto != prev->proto)
1959126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1960145836Smlaier		if (cur->src.neg != prev->src.neg ||
1961126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1962126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1963126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1964126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1965126258Smlaier		    cur->src.port_op != prev->src.port_op)
1966126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1967145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1968126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1969126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1970126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1971126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1972126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1973126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1974126258Smlaier
1975126258Smlaier		prev = cur;
1976126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1977126258Smlaier	}
1978126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1979126258Smlaier		PF_SET_SKIP_STEPS(i);
1980126258Smlaier}
1981126258Smlaier
1982126258Smlaierint
1983126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1984126258Smlaier{
1985126258Smlaier	if (aw1->type != aw2->type)
1986126258Smlaier		return (1);
1987126258Smlaier	switch (aw1->type) {
1988126258Smlaier	case PF_ADDR_ADDRMASK:
1989223637Sbz	case PF_ADDR_RANGE:
1990126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1991126258Smlaier			return (1);
1992126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1993126258Smlaier			return (1);
1994126258Smlaier		return (0);
1995126258Smlaier	case PF_ADDR_DYNIFTL:
1996130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1997126258Smlaier	case PF_ADDR_NOROUTE:
1998171168Smlaier	case PF_ADDR_URPFFAILED:
1999126258Smlaier		return (0);
2000126258Smlaier	case PF_ADDR_TABLE:
2001126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
2002171168Smlaier	case PF_ADDR_RTLABEL:
2003171168Smlaier		return (aw1->v.rtlabel != aw2->v.rtlabel);
2004126258Smlaier	default:
2005126258Smlaier		printf("invalid address type: %d\n", aw1->type);
2006126258Smlaier		return (1);
2007126258Smlaier	}
2008126258Smlaier}
2009126258Smlaier
2010293896Sglebius/**
2011293896Sglebius * Checksum updates are a little complicated because the checksum in the TCP/UDP
2012293896Sglebius * header isn't always a full checksum. In some cases (i.e. output) it's a
2013293896Sglebius * pseudo-header checksum, which is a partial checksum over src/dst IP
2014293896Sglebius * addresses, protocol number and length.
2015293896Sglebius *
2016293896Sglebius * That means we have the following cases:
2017293896Sglebius *  * Input or forwarding: we don't have TSO, the checksum fields are full
2018293896Sglebius *  	checksums, we need to update the checksum whenever we change anything.
2019293896Sglebius *  * Output (i.e. the checksum is a pseudo-header checksum):
2020293896Sglebius *  	x The field being updated is src/dst address or affects the length of
2021293896Sglebius *  	the packet. We need to update the pseudo-header checksum (note that this
2022293896Sglebius *  	checksum is not ones' complement).
2023293896Sglebius *  	x Some other field is being modified (e.g. src/dst port numbers): We
2024293896Sglebius *  	don't have to update anything.
2025293896Sglebius **/
2026126258Smlaieru_int16_t
2027126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
2028126258Smlaier{
2029126258Smlaier	u_int32_t	l;
2030126258Smlaier
2031126258Smlaier	if (udp && !cksum)
2032126258Smlaier		return (0x0000);
2033126258Smlaier	l = cksum + old - new;
2034126258Smlaier	l = (l >> 16) + (l & 65535);
2035126258Smlaier	l = l & 65535;
2036126258Smlaier	if (udp && !l)
2037126258Smlaier		return (0xFFFF);
2038126258Smlaier	return (l);
2039126258Smlaier}
2040126258Smlaier
2041293896Sglebiusu_int16_t
2042293896Sglebiuspf_proto_cksum_fixup(struct mbuf *m, u_int16_t cksum, u_int16_t old,
2043293896Sglebius        u_int16_t new, u_int8_t udp)
2044293896Sglebius{
2045293896Sglebius	if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6))
2046293896Sglebius		return (cksum);
2047293896Sglebius
2048293896Sglebius	return (pf_cksum_fixup(cksum, old, new, udp));
2049293896Sglebius}
2050293896Sglebius
2051126258Smlaiervoid
2052293896Sglebiuspf_change_ap(struct mbuf *m, struct pf_addr *a, u_int16_t *p, u_int16_t *ic,
2053293896Sglebius        u_int16_t *pc, struct pf_addr *an, u_int16_t pn, u_int8_t u,
2054293896Sglebius        sa_family_t af)
2055126258Smlaier{
2056126258Smlaier	struct pf_addr	ao;
2057126258Smlaier	u_int16_t	po = *p;
2058126258Smlaier
2059126258Smlaier	PF_ACPY(&ao, a, af);
2060126258Smlaier	PF_ACPY(a, an, af);
2061126258Smlaier
2062293896Sglebius	if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6))
2063293896Sglebius		*pc = ~*pc;
2064293896Sglebius
2065126258Smlaier	*p = pn;
2066126258Smlaier
2067126258Smlaier	switch (af) {
2068126258Smlaier#ifdef INET
2069126258Smlaier	case AF_INET:
2070126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
2071126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
2072126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
2073126258Smlaier		*p = pn;
2074293896Sglebius
2075293896Sglebius		*pc = pf_cksum_fixup(pf_cksum_fixup(*pc,
2076126258Smlaier		    ao.addr16[0], an->addr16[0], u),
2077293896Sglebius		    ao.addr16[1], an->addr16[1], u);
2078293896Sglebius
2079293896Sglebius		*pc = pf_proto_cksum_fixup(m, *pc, po, pn, u);
2080126258Smlaier		break;
2081126258Smlaier#endif /* INET */
2082126258Smlaier#ifdef INET6
2083126258Smlaier	case AF_INET6:
2084126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2085126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2086293896Sglebius		    pf_cksum_fixup(pf_cksum_fixup(*pc,
2087126258Smlaier		    ao.addr16[0], an->addr16[0], u),
2088126258Smlaier		    ao.addr16[1], an->addr16[1], u),
2089126258Smlaier		    ao.addr16[2], an->addr16[2], u),
2090126258Smlaier		    ao.addr16[3], an->addr16[3], u),
2091126258Smlaier		    ao.addr16[4], an->addr16[4], u),
2092126258Smlaier		    ao.addr16[5], an->addr16[5], u),
2093126258Smlaier		    ao.addr16[6], an->addr16[6], u),
2094293896Sglebius		    ao.addr16[7], an->addr16[7], u);
2095293896Sglebius
2096293896Sglebius		*pc = pf_proto_cksum_fixup(m, *pc, po, pn, u);
2097126258Smlaier		break;
2098126258Smlaier#endif /* INET6 */
2099126258Smlaier	}
2100293896Sglebius
2101293896Sglebius	if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA |
2102293896Sglebius	    CSUM_DELAY_DATA_IPV6)) {
2103293896Sglebius		*pc = ~*pc;
2104293896Sglebius		if (! *pc)
2105293896Sglebius			*pc = 0xffff;
2106293896Sglebius	}
2107126258Smlaier}
2108126258Smlaier
2109126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
2110126258Smlaiervoid
2111126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
2112126258Smlaier{
2113126258Smlaier	u_int32_t	ao;
2114126258Smlaier
2115126258Smlaier	memcpy(&ao, a, sizeof(ao));
2116126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
2117126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
2118126258Smlaier	    ao % 65536, an % 65536, u);
2119126258Smlaier}
2120126258Smlaier
2121293896Sglebiusvoid
2122293896Sglebiuspf_change_proto_a(struct mbuf *m, void *a, u_int16_t *c, u_int32_t an, u_int8_t udp)
2123293896Sglebius{
2124293896Sglebius	u_int32_t	ao;
2125293896Sglebius
2126293896Sglebius	memcpy(&ao, a, sizeof(ao));
2127293896Sglebius	memcpy(a, &an, sizeof(u_int32_t));
2128293896Sglebius
2129293896Sglebius	*c = pf_proto_cksum_fixup(m,
2130293896Sglebius	    pf_proto_cksum_fixup(m, *c, ao / 65536, an / 65536, udp),
2131293896Sglebius	    ao % 65536, an % 65536, udp);
2132293896Sglebius}
2133293896Sglebius
2134126258Smlaier#ifdef INET6
2135126258Smlaiervoid
2136126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
2137126258Smlaier{
2138126258Smlaier	struct pf_addr	ao;
2139126258Smlaier
2140126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
2141126258Smlaier	PF_ACPY(a, an, AF_INET6);
2142126258Smlaier
2143126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2144126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2145126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
2146126258Smlaier	    ao.addr16[0], an->addr16[0], u),
2147126258Smlaier	    ao.addr16[1], an->addr16[1], u),
2148126258Smlaier	    ao.addr16[2], an->addr16[2], u),
2149126258Smlaier	    ao.addr16[3], an->addr16[3], u),
2150126258Smlaier	    ao.addr16[4], an->addr16[4], u),
2151126258Smlaier	    ao.addr16[5], an->addr16[5], u),
2152126258Smlaier	    ao.addr16[6], an->addr16[6], u),
2153126258Smlaier	    ao.addr16[7], an->addr16[7], u);
2154126258Smlaier}
2155126258Smlaier#endif /* INET6 */
2156126258Smlaier
2157126258Smlaiervoid
2158126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
2159126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
2160126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
2161126258Smlaier{
2162126258Smlaier	struct pf_addr	oia, ooa;
2163126258Smlaier
2164126258Smlaier	PF_ACPY(&oia, ia, af);
2165223637Sbz	if (oa)
2166223637Sbz		PF_ACPY(&ooa, oa, af);
2167126258Smlaier
2168126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
2169126258Smlaier	if (ip != NULL) {
2170126258Smlaier		u_int16_t	oip = *ip;
2171223637Sbz		u_int32_t	opc;
2172126258Smlaier
2173126258Smlaier		if (pc != NULL)
2174126258Smlaier			opc = *pc;
2175126258Smlaier		*ip = np;
2176126258Smlaier		if (pc != NULL)
2177126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
2178126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
2179126258Smlaier		if (pc != NULL)
2180126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
2181126258Smlaier	}
2182126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
2183126258Smlaier	PF_ACPY(ia, na, af);
2184126258Smlaier	switch (af) {
2185126258Smlaier#ifdef INET
2186126258Smlaier	case AF_INET: {
2187126258Smlaier		u_int32_t	 oh2c = *h2c;
2188126258Smlaier
2189126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
2190126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
2191126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
2192126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
2193126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
2194126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
2195126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
2196126258Smlaier		break;
2197126258Smlaier	}
2198126258Smlaier#endif /* INET */
2199126258Smlaier#ifdef INET6
2200126258Smlaier	case AF_INET6:
2201126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2202126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2203126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
2204126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
2205126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
2206126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
2207126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
2208126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
2209126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
2210126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
2211126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
2212126258Smlaier		break;
2213126258Smlaier#endif /* INET6 */
2214126258Smlaier	}
2215223637Sbz	/* Outer ip address, fix outer ip or icmpv6 checksum, if necessary. */
2216223637Sbz	if (oa) {
2217223637Sbz		PF_ACPY(oa, na, af);
2218223637Sbz		switch (af) {
2219126258Smlaier#ifdef INET
2220223637Sbz		case AF_INET:
2221223637Sbz			*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
2222223637Sbz			    ooa.addr16[0], oa->addr16[0], 0),
2223223637Sbz			    ooa.addr16[1], oa->addr16[1], 0);
2224223637Sbz			break;
2225126258Smlaier#endif /* INET */
2226126258Smlaier#ifdef INET6
2227223637Sbz		case AF_INET6:
2228223637Sbz			*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2229223637Sbz			    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
2230223637Sbz			    pf_cksum_fixup(pf_cksum_fixup(*ic,
2231223637Sbz			    ooa.addr16[0], oa->addr16[0], u),
2232223637Sbz			    ooa.addr16[1], oa->addr16[1], u),
2233223637Sbz			    ooa.addr16[2], oa->addr16[2], u),
2234223637Sbz			    ooa.addr16[3], oa->addr16[3], u),
2235223637Sbz			    ooa.addr16[4], oa->addr16[4], u),
2236223637Sbz			    ooa.addr16[5], oa->addr16[5], u),
2237223637Sbz			    ooa.addr16[6], oa->addr16[6], u),
2238223637Sbz			    ooa.addr16[7], oa->addr16[7], u);
2239223637Sbz			break;
2240126258Smlaier#endif /* INET6 */
2241223637Sbz		}
2242126258Smlaier	}
2243126258Smlaier}
2244126258Smlaier
2245171168Smlaier
2246171168Smlaier/*
2247171168Smlaier * Need to modulate the sequence numbers in the TCP SACK option
2248171168Smlaier * (credits to Krzysztof Pfaff for report and patch)
2249171168Smlaier */
2250171168Smlaierint
2251171168Smlaierpf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
2252171168Smlaier    struct tcphdr *th, struct pf_state_peer *dst)
2253171168Smlaier{
2254171168Smlaier	int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
2255171168Smlaier#ifdef __FreeBSD__
2256171168Smlaier	u_int8_t opts[TCP_MAXOLEN], *opt = opts;
2257171168Smlaier#else
2258171168Smlaier	u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
2259171168Smlaier#endif
2260171168Smlaier	int copyback = 0, i, olen;
2261171168Smlaier	struct sackblk sack;
2262171168Smlaier
2263223637Sbz#define	TCPOLEN_SACKLEN	(TCPOLEN_SACK + 2)
2264171168Smlaier	if (hlen < TCPOLEN_SACKLEN ||
2265171168Smlaier	    !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
2266171168Smlaier		return 0;
2267171168Smlaier
2268171168Smlaier	while (hlen >= TCPOLEN_SACKLEN) {
2269171168Smlaier		olen = opt[1];
2270171168Smlaier		switch (*opt) {
2271171168Smlaier		case TCPOPT_EOL:	/* FALLTHROUGH */
2272171168Smlaier		case TCPOPT_NOP:
2273171168Smlaier			opt++;
2274171168Smlaier			hlen--;
2275171168Smlaier			break;
2276171168Smlaier		case TCPOPT_SACK:
2277171168Smlaier			if (olen > hlen)
2278171168Smlaier				olen = hlen;
2279171168Smlaier			if (olen >= TCPOLEN_SACKLEN) {
2280171168Smlaier				for (i = 2; i + TCPOLEN_SACK <= olen;
2281171168Smlaier				    i += TCPOLEN_SACK) {
2282171168Smlaier					memcpy(&sack, &opt[i], sizeof(sack));
2283293896Sglebius					pf_change_proto_a(m, &sack.start, &th->th_sum,
2284293896Sglebius					    htonl(ntohl(sack.start) - dst->seqdiff), 0);
2285293896Sglebius					pf_change_proto_a(m, &sack.end, &th->th_sum,
2286293896Sglebius					    htonl(ntohl(sack.end) - dst->seqdiff), 0);
2287171168Smlaier					memcpy(&opt[i], &sack, sizeof(sack));
2288171168Smlaier				}
2289171168Smlaier				copyback = 1;
2290171168Smlaier			}
2291171168Smlaier			/* FALLTHROUGH */
2292171168Smlaier		default:
2293171168Smlaier			if (olen < 2)
2294171168Smlaier				olen = 2;
2295171168Smlaier			hlen -= olen;
2296171168Smlaier			opt += olen;
2297171168Smlaier		}
2298171168Smlaier	}
2299171168Smlaier
2300171168Smlaier	if (copyback)
2301171168Smlaier#ifdef __FreeBSD__
2302171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts);
2303171168Smlaier#else
2304171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, opts);
2305171168Smlaier#endif
2306171168Smlaier	return (copyback);
2307171168Smlaier}
2308171168Smlaier
2309126258Smlaiervoid
2310162238Scsjp#ifdef __FreeBSD__
2311162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
2312162238Scsjp#else
2313126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
2314162238Scsjp#endif
2315126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
2316126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
2317145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
2318171168Smlaier    u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
2319126258Smlaier{
2320126258Smlaier	struct mbuf	*m;
2321171168Smlaier	int		 len, tlen;
2322126258Smlaier#ifdef INET
2323171168Smlaier	struct ip	*h;
2324126258Smlaier#endif /* INET */
2325126258Smlaier#ifdef INET6
2326171168Smlaier	struct ip6_hdr	*h6;
2327126258Smlaier#endif /* INET6 */
2328171168Smlaier	struct tcphdr	*th;
2329171168Smlaier	char		*opt;
2330223637Sbz#ifdef __FreeBSD__
2331223637Sbz	struct pf_mtag  *pf_mtag;
2332126258Smlaier
2333171168Smlaier	KASSERT(
2334171168Smlaier#ifdef INET
2335171168Smlaier	    af == AF_INET
2336171168Smlaier#else
2337171168Smlaier	    0
2338171168Smlaier#endif
2339171168Smlaier	    ||
2340171168Smlaier#ifdef INET6
2341171168Smlaier	    af == AF_INET6
2342171168Smlaier#else
2343171168Smlaier	    0
2344171168Smlaier#endif
2345171168Smlaier	    , ("Unsupported AF %d", af));
2346171168Smlaier	len = 0;
2347171168Smlaier	th = NULL;
2348171168Smlaier#ifdef INET
2349171168Smlaier	h = NULL;
2350171168Smlaier#endif
2351171168Smlaier#ifdef INET6
2352171168Smlaier	h6 = NULL;
2353171168Smlaier#endif
2354223637Sbz#endif /* __FreeBSD__ */
2355171168Smlaier
2356126258Smlaier	/* maximum segment size tcp option */
2357126258Smlaier	tlen = sizeof(struct tcphdr);
2358126258Smlaier	if (mss)
2359126258Smlaier		tlen += 4;
2360126258Smlaier
2361126258Smlaier	switch (af) {
2362126258Smlaier#ifdef INET
2363126258Smlaier	case AF_INET:
2364126258Smlaier		len = sizeof(struct ip) + tlen;
2365126258Smlaier		break;
2366126258Smlaier#endif /* INET */
2367126258Smlaier#ifdef INET6
2368126258Smlaier	case AF_INET6:
2369126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
2370126258Smlaier		break;
2371126258Smlaier#endif /* INET6 */
2372126258Smlaier	}
2373126258Smlaier
2374126258Smlaier	/* create outgoing mbuf */
2375132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
2376132280Smlaier	if (m == NULL)
2377132280Smlaier		return;
2378162238Scsjp#ifdef __FreeBSD__
2379162238Scsjp#ifdef MAC
2380223637Sbz	mac_netinet_firewall_send(m);
2381162238Scsjp#endif
2382171168Smlaier	if ((pf_mtag = pf_get_mtag(m)) == NULL) {
2383171168Smlaier		m_freem(m);
2384171168Smlaier		return;
2385171168Smlaier	}
2386223637Sbz#endif
2387171168Smlaier	if (tag)
2388145836Smlaier#ifdef __FreeBSD__
2389145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
2390223637Sbz	pf_mtag->tag = rtag;
2391132280Smlaier#else
2392223637Sbz		m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
2393223637Sbz	m->m_pkthdr.pf.tag = rtag;
2394171168Smlaier#endif
2395145836Smlaier
2396171168Smlaier	if (r != NULL && r->rtableid >= 0)
2397178888Sjulian#ifdef __FreeBSD__
2398178888Sjulian	{
2399178888Sjulian		M_SETFIB(m, r->rtableid);
2400223637Sbz		pf_mtag->rtableid = r->rtableid;
2401223637Sbz#else
2402223637Sbz		m->m_pkthdr.pf.rtableid = r->rtableid;
2403178888Sjulian#endif
2404178888Sjulian#ifdef __FreeBSD__
2405178888Sjulian	}
2406178888Sjulian#endif
2407223637Sbz
2408126258Smlaier#ifdef ALTQ
2409126258Smlaier	if (r != NULL && r->qid) {
2410223637Sbz#ifdef __FreeBSD__
2411171168Smlaier		pf_mtag->qid = r->qid;
2412223637Sbz
2413171168Smlaier		/* add hints for ecn */
2414171168Smlaier		pf_mtag->hdr = mtod(m, struct ip *);
2415223637Sbz#else
2416223637Sbz		m->m_pkthdr.pf.qid = r->qid;
2417223637Sbz		/* add hints for ecn */
2418223637Sbz		m->m_pkthdr.pf.hdr = mtod(m, struct ip *);
2419223637Sbz#endif
2420126258Smlaier	}
2421145836Smlaier#endif /* ALTQ */
2422126258Smlaier	m->m_data += max_linkhdr;
2423126258Smlaier	m->m_pkthdr.len = m->m_len = len;
2424126258Smlaier	m->m_pkthdr.rcvif = NULL;
2425126258Smlaier	bzero(m->m_data, len);
2426126258Smlaier	switch (af) {
2427126258Smlaier#ifdef INET
2428126258Smlaier	case AF_INET:
2429126258Smlaier		h = mtod(m, struct ip *);
2430126258Smlaier
2431126258Smlaier		/* IP header fields included in the TCP checksum */
2432126258Smlaier		h->ip_p = IPPROTO_TCP;
2433126258Smlaier		h->ip_len = htons(tlen);
2434126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
2435126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
2436126258Smlaier
2437126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
2438126258Smlaier		break;
2439126258Smlaier#endif /* INET */
2440126258Smlaier#ifdef INET6
2441126258Smlaier	case AF_INET6:
2442126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
2443126258Smlaier
2444126258Smlaier		/* IP header fields included in the TCP checksum */
2445126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
2446126258Smlaier		h6->ip6_plen = htons(tlen);
2447126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
2448126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
2449126258Smlaier
2450126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
2451126258Smlaier		break;
2452126258Smlaier#endif /* INET6 */
2453126258Smlaier	}
2454126258Smlaier
2455126258Smlaier	/* TCP header */
2456126258Smlaier	th->th_sport = sport;
2457126258Smlaier	th->th_dport = dport;
2458126258Smlaier	th->th_seq = htonl(seq);
2459126258Smlaier	th->th_ack = htonl(ack);
2460126258Smlaier	th->th_off = tlen >> 2;
2461126258Smlaier	th->th_flags = flags;
2462126258Smlaier	th->th_win = htons(win);
2463126258Smlaier
2464126258Smlaier	if (mss) {
2465126258Smlaier		opt = (char *)(th + 1);
2466126258Smlaier		opt[0] = TCPOPT_MAXSEG;
2467126258Smlaier		opt[1] = 4;
2468126258Smlaier		HTONS(mss);
2469126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
2470126258Smlaier	}
2471126258Smlaier
2472126258Smlaier	switch (af) {
2473126258Smlaier#ifdef INET
2474126258Smlaier	case AF_INET:
2475126258Smlaier		/* TCP checksum */
2476126258Smlaier		th->th_sum = in_cksum(m, len);
2477126258Smlaier
2478126258Smlaier		/* Finish the IP header */
2479126258Smlaier		h->ip_v = 4;
2480126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
2481126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
2482127145Smlaier#ifdef __FreeBSD__
2483181803Sbz		h->ip_off = V_path_mtu_discovery ? IP_DF : 0;
2484130613Smlaier		h->ip_len = len;
2485223637Sbz		h->ip_ttl = ttl ? ttl : V_ip_defttl;
2486126261Smlaier#else
2487223637Sbz		h->ip_len = htons(len);
2488126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
2489223637Sbz		h->ip_ttl = ttl ? ttl : ip_defttl;
2490126261Smlaier#endif
2491126258Smlaier		h->ip_sum = 0;
2492145836Smlaier		if (eh == NULL) {
2493127145Smlaier#ifdef __FreeBSD__
2494223637Sbz		PF_UNLOCK();
2495223637Sbz		ip_output(m, (void *)NULL, (void *)NULL, 0,
2496223637Sbz		    (void *)NULL, (void *)NULL);
2497223637Sbz		PF_LOCK();
2498126261Smlaier#else /* ! __FreeBSD__ */
2499145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
2500145836Smlaier			    (void *)NULL, (void *)NULL);
2501126261Smlaier#endif
2502145836Smlaier		} else {
2503145836Smlaier			struct route		 ro;
2504145836Smlaier			struct rtentry		 rt;
2505145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
2506145836Smlaier
2507145836Smlaier			if (ifp == NULL) {
2508145836Smlaier				m_freem(m);
2509145836Smlaier				return;
2510145836Smlaier			}
2511145836Smlaier			rt.rt_ifp = ifp;
2512145836Smlaier			ro.ro_rt = &rt;
2513145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
2514145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
2515145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
2516145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
2517145836Smlaier			e->ether_type = eh->ether_type;
2518145836Smlaier#ifdef __FreeBSD__
2519145836Smlaier			PF_UNLOCK();
2520145836Smlaier			/* XXX_IMPORT: later */
2521145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
2522145836Smlaier			    (void *)NULL, (void *)NULL);
2523145836Smlaier			PF_LOCK();
2524145836Smlaier#else /* ! __FreeBSD__ */
2525145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
2526145836Smlaier			    (void *)NULL, (void *)NULL);
2527145836Smlaier#endif
2528145836Smlaier		}
2529126258Smlaier		break;
2530126258Smlaier#endif /* INET */
2531126258Smlaier#ifdef INET6
2532126258Smlaier	case AF_INET6:
2533126258Smlaier		/* TCP checksum */
2534126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
2535126258Smlaier		    sizeof(struct ip6_hdr), tlen);
2536126258Smlaier
2537126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
2538126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
2539126258Smlaier
2540127145Smlaier#ifdef __FreeBSD__
2541126261Smlaier		PF_UNLOCK();
2542126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
2543126261Smlaier		PF_LOCK();
2544126261Smlaier#else
2545223637Sbz		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
2546126261Smlaier#endif
2547126258Smlaier		break;
2548126258Smlaier#endif /* INET6 */
2549126258Smlaier	}
2550126258Smlaier}
2551126258Smlaier
2552223637Sbzstatic void
2553126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
2554126258Smlaier    struct pf_rule *r)
2555126258Smlaier{
2556126258Smlaier	struct mbuf	*m0;
2557127145Smlaier#ifdef __FreeBSD__
2558221132Sbz#ifdef INET
2559126261Smlaier	struct ip *ip;
2560126261Smlaier#endif
2561223637Sbz	struct pf_mtag *pf_mtag;
2562221132Sbz#endif
2563126258Smlaier
2564132280Smlaier#ifdef __FreeBSD__
2565132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
2566132280Smlaier	if (m0 == NULL)
2567132280Smlaier		return;
2568132280Smlaier#else
2569223637Sbz	if ((m0 = m_copy(m, 0, M_COPYALL)) == NULL)
2570223637Sbz		return;
2571171168Smlaier#endif
2572223637Sbz
2573223637Sbz#ifdef __FreeBSD__
2574171168Smlaier	if ((pf_mtag = pf_get_mtag(m0)) == NULL)
2575126258Smlaier		return;
2576171168Smlaier	/* XXX: revisit */
2577171168Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
2578171168Smlaier#else
2579223637Sbz	m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
2580132280Smlaier#endif
2581126258Smlaier
2582171168Smlaier	if (r->rtableid >= 0)
2583178888Sjulian#ifdef __FreeBSD__
2584178888Sjulian	{
2585178888Sjulian		M_SETFIB(m0, r->rtableid);
2586223637Sbz		pf_mtag->rtableid = r->rtableid;
2587223637Sbz#else
2588223637Sbz		m0->m_pkthdr.pf.rtableid = r->rtableid;
2589178888Sjulian#endif
2590178888Sjulian#ifdef __FreeBSD__
2591178888Sjulian	}
2592178888Sjulian#endif
2593171168Smlaier
2594126258Smlaier#ifdef ALTQ
2595126258Smlaier	if (r->qid) {
2596223637Sbz#ifdef __FreeBSD__
2597171168Smlaier		pf_mtag->qid = r->qid;
2598171168Smlaier		/* add hints for ecn */
2599171168Smlaier		pf_mtag->hdr = mtod(m0, struct ip *);
2600223637Sbz#else
2601223637Sbz		m0->m_pkthdr.pf.qid = r->qid;
2602223637Sbz		/* add hints for ecn */
2603223637Sbz		m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *);
2604223637Sbz#endif
2605126258Smlaier	}
2606145836Smlaier#endif /* ALTQ */
2607126258Smlaier
2608126258Smlaier	switch (af) {
2609126258Smlaier#ifdef INET
2610126258Smlaier	case AF_INET:
2611127145Smlaier#ifdef __FreeBSD__
2612126261Smlaier		/* icmp_error() expects host byte ordering */
2613126261Smlaier		ip = mtod(m0, struct ip *);
2614126261Smlaier		NTOHS(ip->ip_len);
2615126261Smlaier		NTOHS(ip->ip_off);
2616126261Smlaier		PF_UNLOCK();
2617145863Sandre		icmp_error(m0, type, code, 0, 0);
2618126261Smlaier		PF_LOCK();
2619145874Smlaier#else
2620171168Smlaier		icmp_error(m0, type, code, 0, 0);
2621126261Smlaier#endif
2622126258Smlaier		break;
2623126258Smlaier#endif /* INET */
2624126258Smlaier#ifdef INET6
2625126258Smlaier	case AF_INET6:
2626127145Smlaier#ifdef __FreeBSD__
2627126261Smlaier		PF_UNLOCK();
2628126261Smlaier#endif
2629126258Smlaier		icmp6_error(m0, type, code, 0);
2630127145Smlaier#ifdef __FreeBSD__
2631126261Smlaier		PF_LOCK();
2632126261Smlaier#endif
2633126258Smlaier		break;
2634126258Smlaier#endif /* INET6 */
2635126258Smlaier	}
2636126258Smlaier}
2637126258Smlaier
2638126258Smlaier/*
2639126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
2640126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
2641126258Smlaier * are different.
2642126258Smlaier */
2643126258Smlaierint
2644126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
2645126258Smlaier    struct pf_addr *b, sa_family_t af)
2646126258Smlaier{
2647126258Smlaier	int	match = 0;
2648126258Smlaier
2649126258Smlaier	switch (af) {
2650126258Smlaier#ifdef INET
2651126258Smlaier	case AF_INET:
2652126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
2653126258Smlaier		    (b->addr32[0] & m->addr32[0]))
2654126258Smlaier			match++;
2655126258Smlaier		break;
2656126258Smlaier#endif /* INET */
2657126258Smlaier#ifdef INET6
2658126258Smlaier	case AF_INET6:
2659126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
2660126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
2661126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
2662126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
2663126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
2664126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
2665126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
2666126258Smlaier		     (b->addr32[3] & m->addr32[3])))
2667126258Smlaier			match++;
2668126258Smlaier		break;
2669126258Smlaier#endif /* INET6 */
2670126258Smlaier	}
2671126258Smlaier	if (match) {
2672126258Smlaier		if (n)
2673126258Smlaier			return (0);
2674126258Smlaier		else
2675126258Smlaier			return (1);
2676126258Smlaier	} else {
2677126258Smlaier		if (n)
2678126258Smlaier			return (1);
2679126258Smlaier		else
2680126258Smlaier			return (0);
2681126258Smlaier	}
2682126258Smlaier}
2683126258Smlaier
2684223637Sbz/*
2685223637Sbz * Return 1 if b <= a <= e, otherwise return 0.
2686223637Sbz */
2687126258Smlaierint
2688223637Sbzpf_match_addr_range(struct pf_addr *b, struct pf_addr *e,
2689223637Sbz    struct pf_addr *a, sa_family_t af)
2690223637Sbz{
2691223637Sbz	switch (af) {
2692223637Sbz#ifdef INET
2693223637Sbz	case AF_INET:
2694223637Sbz		if ((a->addr32[0] < b->addr32[0]) ||
2695223637Sbz		    (a->addr32[0] > e->addr32[0]))
2696223637Sbz			return (0);
2697223637Sbz		break;
2698223637Sbz#endif /* INET */
2699223637Sbz#ifdef INET6
2700223637Sbz	case AF_INET6: {
2701223637Sbz		int	i;
2702223637Sbz
2703223637Sbz		/* check a >= b */
2704223637Sbz		for (i = 0; i < 4; ++i)
2705223637Sbz			if (a->addr32[i] > b->addr32[i])
2706223637Sbz				break;
2707223637Sbz			else if (a->addr32[i] < b->addr32[i])
2708223637Sbz				return (0);
2709223637Sbz		/* check a <= e */
2710223637Sbz		for (i = 0; i < 4; ++i)
2711223637Sbz			if (a->addr32[i] < e->addr32[i])
2712223637Sbz				break;
2713223637Sbz			else if (a->addr32[i] > e->addr32[i])
2714223637Sbz				return (0);
2715223637Sbz		break;
2716223637Sbz	}
2717223637Sbz#endif /* INET6 */
2718223637Sbz	}
2719223637Sbz	return (1);
2720223637Sbz}
2721223637Sbz
2722223637Sbzint
2723126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
2724126258Smlaier{
2725126258Smlaier	switch (op) {
2726126258Smlaier	case PF_OP_IRG:
2727126258Smlaier		return ((p > a1) && (p < a2));
2728126258Smlaier	case PF_OP_XRG:
2729126258Smlaier		return ((p < a1) || (p > a2));
2730126258Smlaier	case PF_OP_RRG:
2731126258Smlaier		return ((p >= a1) && (p <= a2));
2732126258Smlaier	case PF_OP_EQ:
2733126258Smlaier		return (p == a1);
2734126258Smlaier	case PF_OP_NE:
2735126258Smlaier		return (p != a1);
2736126258Smlaier	case PF_OP_LT:
2737126258Smlaier		return (p < a1);
2738126258Smlaier	case PF_OP_LE:
2739126258Smlaier		return (p <= a1);
2740126258Smlaier	case PF_OP_GT:
2741126258Smlaier		return (p > a1);
2742126258Smlaier	case PF_OP_GE:
2743126258Smlaier		return (p >= a1);
2744126258Smlaier	}
2745126258Smlaier	return (0); /* never reached */
2746126258Smlaier}
2747126258Smlaier
2748126258Smlaierint
2749126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
2750126258Smlaier{
2751126258Smlaier	NTOHS(a1);
2752126258Smlaier	NTOHS(a2);
2753126258Smlaier	NTOHS(p);
2754126258Smlaier	return (pf_match(op, a1, a2, p));
2755126258Smlaier}
2756126258Smlaier
2757126258Smlaierint
2758126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
2759126258Smlaier{
2760126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2761126258Smlaier		return (0);
2762126258Smlaier	return (pf_match(op, a1, a2, u));
2763126258Smlaier}
2764126258Smlaier
2765126258Smlaierint
2766126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
2767126258Smlaier{
2768126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2769126258Smlaier		return (0);
2770126258Smlaier	return (pf_match(op, a1, a2, g));
2771126258Smlaier}
2772126258Smlaier
2773223637Sbzint
2774223637Sbz#ifdef __FreeBSD__
2775223637Sbzpf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag,
2776223637Sbz    struct pf_mtag *pf_mtag)
2777223637Sbz#else
2778223637Sbzpf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag)
2779171168Smlaier#endif
2780171168Smlaier{
2781171168Smlaier	if (*tag == -1)
2782223637Sbz#ifdef __FreeBSD__
2783171168Smlaier		*tag = pf_mtag->tag;
2784223637Sbz#else
2785223637Sbz		*tag = m->m_pkthdr.pf.tag;
2786223637Sbz#endif
2787171168Smlaier
2788126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
2789126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
2790126258Smlaier}
2791126258Smlaier
2792126258Smlaierint
2793223637Sbz#ifdef __FreeBSD__
2794223637Sbzpf_tag_packet(struct mbuf *m, int tag, int rtableid,
2795223637Sbz    struct pf_mtag *pf_mtag)
2796223637Sbz#else
2797223637Sbzpf_tag_packet(struct mbuf *m, int tag, int rtableid)
2798223637Sbz#endif
2799126258Smlaier{
2800171168Smlaier	if (tag <= 0 && rtableid < 0)
2801126258Smlaier		return (0);
2802126258Smlaier
2803171168Smlaier	if (tag > 0)
2804223637Sbz#ifdef __FreeBSD__
2805171168Smlaier		pf_mtag->tag = tag;
2806223637Sbz#else
2807223637Sbz		m->m_pkthdr.pf.tag = tag;
2808223637Sbz#endif
2809171168Smlaier	if (rtableid >= 0)
2810178888Sjulian#ifdef __FreeBSD__
2811178888Sjulian	{
2812178888Sjulian		M_SETFIB(m, rtableid);
2813178888Sjulian	}
2814223637Sbz#else
2815223637Sbz		m->m_pkthdr.pf.rtableid = rtableid;
2816178888Sjulian#endif
2817126258Smlaier
2818126258Smlaier	return (0);
2819126258Smlaier}
2820126258Smlaier
2821223637Sbzvoid
2822145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
2823223637Sbz    struct pf_rule **r, struct pf_rule **a, int *match)
2824145836Smlaier{
2825145836Smlaier	struct pf_anchor_stackframe	*f;
2826126258Smlaier
2827171168Smlaier	(*r)->anchor->match = 0;
2828171168Smlaier	if (match)
2829171168Smlaier		*match = 0;
2830223637Sbz#ifdef __FreeBSD__
2831223637Sbz	if (*depth >= sizeof(V_pf_anchor_stack) /
2832223637Sbz	    sizeof(V_pf_anchor_stack[0])) {
2833223637Sbz#else
2834145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
2835145836Smlaier	    sizeof(pf_anchor_stack[0])) {
2836223637Sbz#endif
2837145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
2838145836Smlaier		*r = TAILQ_NEXT(*r, entries);
2839145836Smlaier		return;
2840145836Smlaier	} else if (*depth == 0 && a != NULL)
2841145836Smlaier		*a = *r;
2842223637Sbz#ifdef __FreeBSD__
2843223637Sbz	f = V_pf_anchor_stack + (*depth)++;
2844223637Sbz#else
2845145836Smlaier	f = pf_anchor_stack + (*depth)++;
2846223637Sbz#endif
2847145836Smlaier	f->rs = *rs;
2848145836Smlaier	f->r = *r;
2849145836Smlaier	if ((*r)->anchor_wildcard) {
2850145836Smlaier		f->parent = &(*r)->anchor->children;
2851145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
2852145836Smlaier		    NULL) {
2853145836Smlaier			*r = NULL;
2854145836Smlaier			return;
2855145836Smlaier		}
2856145836Smlaier		*rs = &f->child->ruleset;
2857145836Smlaier	} else {
2858145836Smlaier		f->parent = NULL;
2859145836Smlaier		f->child = NULL;
2860145836Smlaier		*rs = &(*r)->anchor->ruleset;
2861145836Smlaier	}
2862145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2863145836Smlaier}
2864126258Smlaier
2865171168Smlaierint
2866145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
2867171168Smlaier    struct pf_rule **r, struct pf_rule **a, int *match)
2868145836Smlaier{
2869145836Smlaier	struct pf_anchor_stackframe	*f;
2870171168Smlaier	int quick = 0;
2871145836Smlaier
2872145836Smlaier	do {
2873145836Smlaier		if (*depth <= 0)
2874145836Smlaier			break;
2875223637Sbz#ifdef __FreeBSD__
2876223637Sbz		f = V_pf_anchor_stack + *depth - 1;
2877223637Sbz#else
2878145836Smlaier		f = pf_anchor_stack + *depth - 1;
2879223637Sbz#endif
2880145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2881171168Smlaier			if (f->child->match ||
2882171168Smlaier			    (match != NULL && *match)) {
2883171168Smlaier				f->r->anchor->match = 1;
2884171168Smlaier				*match = 0;
2885171168Smlaier			}
2886145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2887145836Smlaier			if (f->child != NULL) {
2888145836Smlaier				*rs = &f->child->ruleset;
2889145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2890145836Smlaier				if (*r == NULL)
2891145836Smlaier					continue;
2892145836Smlaier				else
2893145836Smlaier					break;
2894145836Smlaier			}
2895145836Smlaier		}
2896145836Smlaier		(*depth)--;
2897145836Smlaier		if (*depth == 0 && a != NULL)
2898145836Smlaier			*a = NULL;
2899145836Smlaier		*rs = f->rs;
2900223637Sbz		if (f->r->anchor->match || (match != NULL && *match))
2901171168Smlaier			quick = f->r->quick;
2902145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2903145836Smlaier	} while (*r == NULL);
2904171168Smlaier
2905171168Smlaier	return (quick);
2906145836Smlaier}
2907145836Smlaier
2908126258Smlaier#ifdef INET6
2909126258Smlaiervoid
2910126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2911126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2912126258Smlaier{
2913126258Smlaier	switch (af) {
2914126258Smlaier#ifdef INET
2915126258Smlaier	case AF_INET:
2916126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2917126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2918126258Smlaier		break;
2919126258Smlaier#endif /* INET */
2920126258Smlaier	case AF_INET6:
2921126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2922126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2923126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2924126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2925126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2926126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2927126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2928126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2929126258Smlaier		break;
2930126258Smlaier	}
2931126258Smlaier}
2932126258Smlaier
2933126258Smlaiervoid
2934130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2935126258Smlaier{
2936126258Smlaier	switch (af) {
2937126258Smlaier#ifdef INET
2938126258Smlaier	case AF_INET:
2939126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2940126258Smlaier		break;
2941126258Smlaier#endif /* INET */
2942126258Smlaier	case AF_INET6:
2943126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2944126258Smlaier			addr->addr32[3] = 0;
2945126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2946126258Smlaier				addr->addr32[2] = 0;
2947126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2948126258Smlaier					addr->addr32[1] = 0;
2949126258Smlaier					addr->addr32[0] =
2950126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2951126258Smlaier				} else
2952126258Smlaier					addr->addr32[1] =
2953126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2954126258Smlaier			} else
2955126258Smlaier				addr->addr32[2] =
2956126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2957126258Smlaier		} else
2958126258Smlaier			addr->addr32[3] =
2959126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2960126258Smlaier		break;
2961126258Smlaier	}
2962126258Smlaier}
2963126258Smlaier#endif /* INET6 */
2964126258Smlaier
2965126258Smlaierint
2966135920Smlaier#ifdef __FreeBSD__
2967171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
2968135920Smlaier#else
2969171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd)
2970135920Smlaier#endif
2971126258Smlaier{
2972126258Smlaier	struct pf_addr		*saddr, *daddr;
2973126258Smlaier	u_int16_t		 sport, dport;
2974127145Smlaier#ifdef __FreeBSD__
2975126261Smlaier	struct inpcbinfo	*pi;
2976126261Smlaier#else
2977126258Smlaier	struct inpcbtable	*tb;
2978126261Smlaier#endif
2979126258Smlaier	struct inpcb		*inp;
2980126258Smlaier
2981171168Smlaier	if (pd == NULL)
2982171168Smlaier		return (-1);
2983171168Smlaier	pd->lookup.uid = UID_MAX;
2984171168Smlaier	pd->lookup.gid = GID_MAX;
2985223637Sbz	pd->lookup.pid = NO_PID;
2986223637Sbz
2987135920Smlaier#ifdef __FreeBSD__
2988135920Smlaier	if (inp_arg != NULL) {
2989178325Srwatson		INP_LOCK_ASSERT(inp_arg);
2990183606Sbz		pd->lookup.uid = inp_arg->inp_cred->cr_uid;
2991183606Sbz		pd->lookup.gid = inp_arg->inp_cred->cr_groups[0];
2992183606Sbz		return (1);
2993135920Smlaier	}
2994135920Smlaier#endif
2995223637Sbz
2996130613Smlaier	switch (pd->proto) {
2997126258Smlaier	case IPPROTO_TCP:
2998171168Smlaier		if (pd->hdr.tcp == NULL)
2999171168Smlaier			return (-1);
3000126258Smlaier		sport = pd->hdr.tcp->th_sport;
3001126258Smlaier		dport = pd->hdr.tcp->th_dport;
3002127145Smlaier#ifdef __FreeBSD__
3003181803Sbz		pi = &V_tcbinfo;
3004126261Smlaier#else
3005126258Smlaier		tb = &tcbtable;
3006126261Smlaier#endif
3007126258Smlaier		break;
3008126258Smlaier	case IPPROTO_UDP:
3009171168Smlaier		if (pd->hdr.udp == NULL)
3010171168Smlaier			return (-1);
3011126258Smlaier		sport = pd->hdr.udp->uh_sport;
3012126258Smlaier		dport = pd->hdr.udp->uh_dport;
3013127145Smlaier#ifdef __FreeBSD__
3014181803Sbz		pi = &V_udbinfo;
3015126261Smlaier#else
3016126258Smlaier		tb = &udbtable;
3017126261Smlaier#endif
3018126258Smlaier		break;
3019126258Smlaier	default:
3020171168Smlaier		return (-1);
3021126258Smlaier	}
3022126258Smlaier	if (direction == PF_IN) {
3023126258Smlaier		saddr = pd->src;
3024126258Smlaier		daddr = pd->dst;
3025126258Smlaier	} else {
3026126258Smlaier		u_int16_t	p;
3027126258Smlaier
3028126258Smlaier		p = sport;
3029126258Smlaier		sport = dport;
3030126258Smlaier		dport = p;
3031126258Smlaier		saddr = pd->dst;
3032126258Smlaier		daddr = pd->src;
3033126258Smlaier	}
3034130613Smlaier	switch (pd->af) {
3035145836Smlaier#ifdef INET
3036126258Smlaier	case AF_INET:
3037127145Smlaier#ifdef __FreeBSD__
3038222691Srwatson		/*
3039222691Srwatson		 * XXXRW: would be nice if we had an mbuf here so that we
3040222691Srwatson		 * could use in_pcblookup_mbuf().
3041222691Srwatson		 */
3042222488Srwatson		inp = in_pcblookup(pi, saddr->v4, sport, daddr->v4,
3043222488Srwatson			dport, INPLOOKUP_RLOCKPCB, NULL);
3044126261Smlaier		if (inp == NULL) {
3045222488Srwatson			inp = in_pcblookup(pi, saddr->v4, sport,
3046222488Srwatson			   daddr->v4, dport, INPLOOKUP_WILDCARD |
3047222488Srwatson			   INPLOOKUP_RLOCKPCB, NULL);
3048222488Srwatson			if (inp == NULL)
3049171168Smlaier				return (-1);
3050126261Smlaier		}
3051126261Smlaier#else
3052126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
3053126258Smlaier		if (inp == NULL) {
3054223637Sbz			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0,
3055223637Sbz			    NULL);
3056126258Smlaier			if (inp == NULL)
3057171168Smlaier				return (-1);
3058126258Smlaier		}
3059126261Smlaier#endif
3060126258Smlaier		break;
3061145836Smlaier#endif /* INET */
3062126258Smlaier#ifdef INET6
3063126258Smlaier	case AF_INET6:
3064127145Smlaier#ifdef __FreeBSD__
3065222691Srwatson		/*
3066222691Srwatson		 * XXXRW: would be nice if we had an mbuf here so that we
3067222691Srwatson		 * could use in6_pcblookup_mbuf().
3068222691Srwatson		 */
3069222488Srwatson		inp = in6_pcblookup(pi, &saddr->v6, sport,
3070222488Srwatson			&daddr->v6, dport, INPLOOKUP_RLOCKPCB, NULL);
3071126261Smlaier		if (inp == NULL) {
3072222488Srwatson			inp = in6_pcblookup(pi, &saddr->v6, sport,
3073222488Srwatson			    &daddr->v6, dport, INPLOOKUP_WILDCARD |
3074222488Srwatson			    INPLOOKUP_RLOCKPCB, NULL);
3075222488Srwatson			if (inp == NULL)
3076171168Smlaier				return (-1);
3077126261Smlaier		}
3078126261Smlaier#else
3079126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
3080126258Smlaier		    dport);
3081126258Smlaier		if (inp == NULL) {
3082223637Sbz			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0,
3083223637Sbz			    NULL);
3084126258Smlaier			if (inp == NULL)
3085171168Smlaier				return (-1);
3086126258Smlaier		}
3087126261Smlaier#endif
3088126258Smlaier		break;
3089126258Smlaier#endif /* INET6 */
3090126258Smlaier
3091126258Smlaier	default:
3092171168Smlaier		return (-1);
3093126258Smlaier	}
3094127145Smlaier#ifdef __FreeBSD__
3095222488Srwatson	INP_RLOCK_ASSERT(inp);
3096183606Sbz	pd->lookup.uid = inp->inp_cred->cr_uid;
3097183606Sbz	pd->lookup.gid = inp->inp_cred->cr_groups[0];
3098222488Srwatson	INP_RUNLOCK(inp);
3099126261Smlaier#else
3100171168Smlaier	pd->lookup.uid = inp->inp_socket->so_euid;
3101171168Smlaier	pd->lookup.gid = inp->inp_socket->so_egid;
3102171168Smlaier	pd->lookup.pid = inp->inp_socket->so_cpid;
3103126261Smlaier#endif
3104126258Smlaier	return (1);
3105126258Smlaier}
3106126258Smlaier
3107126258Smlaieru_int8_t
3108126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3109126258Smlaier{
3110126258Smlaier	int		 hlen;
3111126258Smlaier	u_int8_t	 hdr[60];
3112126258Smlaier	u_int8_t	*opt, optlen;
3113126258Smlaier	u_int8_t	 wscale = 0;
3114126258Smlaier
3115126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
3116126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3117126258Smlaier		return (0);
3118126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3119126258Smlaier		return (0);
3120126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3121126258Smlaier	hlen -= sizeof(struct tcphdr);
3122126258Smlaier	while (hlen >= 3) {
3123126258Smlaier		switch (*opt) {
3124126258Smlaier		case TCPOPT_EOL:
3125126258Smlaier		case TCPOPT_NOP:
3126126258Smlaier			++opt;
3127126258Smlaier			--hlen;
3128126258Smlaier			break;
3129126258Smlaier		case TCPOPT_WINDOW:
3130126258Smlaier			wscale = opt[2];
3131126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
3132126258Smlaier				wscale = TCP_MAX_WINSHIFT;
3133126258Smlaier			wscale |= PF_WSCALE_FLAG;
3134130613Smlaier			/* FALLTHROUGH */
3135126258Smlaier		default:
3136126258Smlaier			optlen = opt[1];
3137126258Smlaier			if (optlen < 2)
3138126258Smlaier				optlen = 2;
3139126258Smlaier			hlen -= optlen;
3140126258Smlaier			opt += optlen;
3141130613Smlaier			break;
3142126258Smlaier		}
3143126258Smlaier	}
3144126258Smlaier	return (wscale);
3145126258Smlaier}
3146126258Smlaier
3147126258Smlaieru_int16_t
3148126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3149126258Smlaier{
3150126258Smlaier	int		 hlen;
3151126258Smlaier	u_int8_t	 hdr[60];
3152126258Smlaier	u_int8_t	*opt, optlen;
3153223637Sbz#ifdef __FreeBSD__
3154181803Sbz	u_int16_t	 mss = V_tcp_mssdflt;
3155223637Sbz#else
3156223637Sbz	u_int16_t	 mss = tcp_mssdflt;
3157223637Sbz#endif
3158126258Smlaier
3159126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
3160126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3161126258Smlaier		return (0);
3162126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3163126258Smlaier		return (0);
3164126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3165126258Smlaier	hlen -= sizeof(struct tcphdr);
3166126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
3167126258Smlaier		switch (*opt) {
3168126258Smlaier		case TCPOPT_EOL:
3169126258Smlaier		case TCPOPT_NOP:
3170126258Smlaier			++opt;
3171126258Smlaier			--hlen;
3172126258Smlaier			break;
3173126258Smlaier		case TCPOPT_MAXSEG:
3174126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
3175145030Sglebius			NTOHS(mss);
3176130613Smlaier			/* FALLTHROUGH */
3177126258Smlaier		default:
3178126258Smlaier			optlen = opt[1];
3179126258Smlaier			if (optlen < 2)
3180126258Smlaier				optlen = 2;
3181126258Smlaier			hlen -= optlen;
3182126258Smlaier			opt += optlen;
3183130613Smlaier			break;
3184126258Smlaier		}
3185126258Smlaier	}
3186126258Smlaier	return (mss);
3187126258Smlaier}
3188126258Smlaier
3189126258Smlaieru_int16_t
3190232292Sbzpf_calc_mss(struct pf_addr *addr, sa_family_t af, int rtableid, u_int16_t offer)
3191126258Smlaier{
3192126258Smlaier#ifdef INET
3193126258Smlaier	struct sockaddr_in	*dst;
3194126258Smlaier	struct route		 ro;
3195126258Smlaier#endif /* INET */
3196126258Smlaier#ifdef INET6
3197126258Smlaier	struct sockaddr_in6	*dst6;
3198126258Smlaier	struct route_in6	 ro6;
3199126258Smlaier#endif /* INET6 */
3200126258Smlaier	struct rtentry		*rt = NULL;
3201223637Sbz#ifdef __FreeBSD__
3202223637Sbz	int			 hlen = 0;
3203181803Sbz	u_int16_t		 mss = V_tcp_mssdflt;
3204223637Sbz#else
3205223637Sbz	int			 hlen;
3206223637Sbz	u_int16_t		 mss = tcp_mssdflt;
3207223637Sbz#endif
3208126258Smlaier
3209126258Smlaier	switch (af) {
3210126258Smlaier#ifdef INET
3211126258Smlaier	case AF_INET:
3212126258Smlaier		hlen = sizeof(struct ip);
3213126258Smlaier		bzero(&ro, sizeof(ro));
3214126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
3215126258Smlaier		dst->sin_family = AF_INET;
3216126258Smlaier		dst->sin_len = sizeof(*dst);
3217126258Smlaier		dst->sin_addr = addr->v4;
3218127145Smlaier#ifdef __FreeBSD__
3219232292Sbz		in_rtalloc_ign(&ro, 0, rtableid);
3220126261Smlaier#else /* ! __FreeBSD__ */
3221126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
3222126261Smlaier#endif
3223126258Smlaier		rt = ro.ro_rt;
3224126258Smlaier		break;
3225126258Smlaier#endif /* INET */
3226126258Smlaier#ifdef INET6
3227126258Smlaier	case AF_INET6:
3228126258Smlaier		hlen = sizeof(struct ip6_hdr);
3229126258Smlaier		bzero(&ro6, sizeof(ro6));
3230126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
3231126258Smlaier		dst6->sin6_family = AF_INET6;
3232126258Smlaier		dst6->sin6_len = sizeof(*dst6);
3233126258Smlaier		dst6->sin6_addr = addr->v6;
3234127145Smlaier#ifdef __FreeBSD__
3235232292Sbz		in6_rtalloc_ign(&ro6, 0, rtableid);
3236126261Smlaier#else /* ! __FreeBSD__ */
3237126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
3238126261Smlaier#endif
3239126258Smlaier		rt = ro6.ro_rt;
3240126258Smlaier		break;
3241126258Smlaier#endif /* INET6 */
3242126258Smlaier	}
3243126258Smlaier
3244126258Smlaier	if (rt && rt->rt_ifp) {
3245126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
3246223637Sbz#ifdef __FreeBSD__
3247181803Sbz		mss = max(V_tcp_mssdflt, mss);
3248223637Sbz#else
3249223637Sbz		mss = max(tcp_mssdflt, mss);
3250223637Sbz#endif
3251126258Smlaier		RTFREE(rt);
3252126258Smlaier	}
3253126258Smlaier	mss = min(mss, offer);
3254126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
3255126258Smlaier	return (mss);
3256126258Smlaier}
3257126258Smlaier
3258126258Smlaiervoid
3259126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
3260126258Smlaier{
3261126258Smlaier	struct pf_rule *r = s->rule.ptr;
3262223637Sbz	struct pf_src_node *sn = NULL;
3263126258Smlaier
3264130613Smlaier	s->rt_kif = NULL;
3265126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
3266126258Smlaier		return;
3267223637Sbz	switch (s->key[PF_SK_WIRE]->af) {
3268126258Smlaier#ifdef INET
3269126258Smlaier	case AF_INET:
3270223637Sbz		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn);
3271130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3272126258Smlaier		break;
3273126258Smlaier#endif /* INET */
3274126258Smlaier#ifdef INET6
3275126258Smlaier	case AF_INET6:
3276223637Sbz		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn);
3277130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3278126258Smlaier		break;
3279126258Smlaier#endif /* INET6 */
3280126258Smlaier	}
3281126258Smlaier}
3282126258Smlaier
3283223637Sbzu_int32_t
3284223637Sbzpf_tcp_iss(struct pf_pdesc *pd)
3285223637Sbz{
3286223637Sbz	MD5_CTX ctx;
3287223637Sbz	u_int32_t digest[4];
3288223637Sbz
3289223637Sbz#ifdef __FreeBSD__
3290223637Sbz	if (V_pf_tcp_secret_init == 0) {
3291223637Sbz		read_random(&V_pf_tcp_secret, sizeof(V_pf_tcp_secret));
3292223637Sbz		MD5Init(&V_pf_tcp_secret_ctx);
3293223637Sbz		MD5Update(&V_pf_tcp_secret_ctx, V_pf_tcp_secret,
3294223637Sbz		    sizeof(V_pf_tcp_secret));
3295223637Sbz		V_pf_tcp_secret_init = 1;
3296223637Sbz	}
3297223637Sbz
3298223637Sbz	ctx = V_pf_tcp_secret_ctx;
3299223637Sbz#else
3300223637Sbz	if (pf_tcp_secret_init == 0) {
3301223637Sbz		arc4random_buf(pf_tcp_secret, sizeof(pf_tcp_secret));
3302223637Sbz		MD5Init(&pf_tcp_secret_ctx);
3303223637Sbz		MD5Update(&pf_tcp_secret_ctx, pf_tcp_secret,
3304223637Sbz		    sizeof(pf_tcp_secret));
3305223637Sbz		pf_tcp_secret_init = 1;
3306223637Sbz	}
3307223637Sbz
3308223637Sbz	ctx = pf_tcp_secret_ctx;
3309223637Sbz#endif
3310223637Sbz
3311223637Sbz	MD5Update(&ctx, (char *)&pd->hdr.tcp->th_sport, sizeof(u_short));
3312223637Sbz	MD5Update(&ctx, (char *)&pd->hdr.tcp->th_dport, sizeof(u_short));
3313223637Sbz	if (pd->af == AF_INET6) {
3314223637Sbz		MD5Update(&ctx, (char *)&pd->src->v6, sizeof(struct in6_addr));
3315223637Sbz		MD5Update(&ctx, (char *)&pd->dst->v6, sizeof(struct in6_addr));
3316223637Sbz	} else {
3317223637Sbz		MD5Update(&ctx, (char *)&pd->src->v4, sizeof(struct in_addr));
3318223637Sbz		MD5Update(&ctx, (char *)&pd->dst->v4, sizeof(struct in_addr));
3319223637Sbz	}
3320223637Sbz	MD5Final((u_char *)digest, &ctx);
3321223637Sbz#ifdef __FreeBSD__
3322223637Sbz	V_pf_tcp_iss_off += 4096;
3323223637Sbz#define	ISN_RANDOM_INCREMENT (4096 - 1)
3324223637Sbz	return (digest[0] + (arc4random() & ISN_RANDOM_INCREMENT) +
3325223637Sbz	    V_pf_tcp_iss_off);
3326223637Sbz#undef	ISN_RANDOM_INCREMENT
3327223637Sbz#else
3328223637Sbz	pf_tcp_iss_off += 4096;
3329223637Sbz	return (digest[0] + tcp_iss + pf_tcp_iss_off);
3330223637Sbz#endif
3331223637Sbz}
3332223637Sbz
3333126258Smlaierint
3334223637Sbzpf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
3335130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3336223637Sbz    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3337135920Smlaier#ifdef __FreeBSD__
3338145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3339135920Smlaier#else
3340145836Smlaier    struct ifqueue *ifq)
3341135920Smlaier#endif
3342126258Smlaier{
3343130613Smlaier	struct pf_rule		*nr = NULL;
3344126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3345126258Smlaier	sa_family_t		 af = pd->af;
3346126258Smlaier	struct pf_rule		*r, *a = NULL;
3347126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3348130613Smlaier	struct pf_src_node	*nsn = NULL;
3349223637Sbz	struct tcphdr		*th = pd->hdr.tcp;
3350223637Sbz	struct pf_state_key	*skw = NULL, *sks = NULL;
3351223637Sbz	struct pf_state_key	*sk = NULL, *nk = NULL;
3352126258Smlaier	u_short			 reason;
3353223637Sbz	int			 rewrite = 0, hdrlen = 0;
3354171168Smlaier	int			 tag = -1, rtableid = -1;
3355145836Smlaier	int			 asd = 0;
3356171168Smlaier	int			 match = 0;
3357223637Sbz	int			 state_icmp = 0;
3358223637Sbz#ifdef __FreeBSD__
3359223637Sbz	u_int16_t		 sport = 0, dport = 0;
3360223637Sbz	u_int16_t		 bproto_sum = 0, bip_sum = 0;
3361223637Sbz#else
3362223637Sbz	u_int16_t		 sport, dport;
3363223637Sbz	u_int16_t		 bproto_sum = 0, bip_sum;
3364223637Sbz#endif
3365223637Sbz	u_int8_t		 icmptype = 0, icmpcode = 0;
3366126258Smlaier
3367223637Sbz
3368223637Sbz	if (direction == PF_IN && pf_check_congestion(ifq)) {
3369145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3370145836Smlaier		return (PF_DROP);
3371145836Smlaier	}
3372145836Smlaier
3373171168Smlaier#ifdef __FreeBSD__
3374171168Smlaier	if (inp != NULL)
3375171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3376223637Sbz	else if (V_debug_pfugidhack) {
3377171168Smlaier		PF_UNLOCK();
3378171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3379223637Sbz		    pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3380171168Smlaier		PF_LOCK();
3381171168Smlaier	}
3382165631Smlaier#endif
3383165631Smlaier
3384223637Sbz	switch (pd->proto) {
3385223637Sbz	case IPPROTO_TCP:
3386223637Sbz		sport = th->th_sport;
3387223637Sbz		dport = th->th_dport;
3388223637Sbz		hdrlen = sizeof(*th);
3389223637Sbz		break;
3390223637Sbz	case IPPROTO_UDP:
3391223637Sbz		sport = pd->hdr.udp->uh_sport;
3392223637Sbz		dport = pd->hdr.udp->uh_dport;
3393223637Sbz		hdrlen = sizeof(*pd->hdr.udp);
3394223637Sbz		break;
3395223637Sbz#ifdef INET
3396223637Sbz	case IPPROTO_ICMP:
3397223637Sbz		if (pd->af != AF_INET)
3398223637Sbz			break;
3399223637Sbz		sport = dport = pd->hdr.icmp->icmp_id;
3400223637Sbz		hdrlen = sizeof(*pd->hdr.icmp);
3401223637Sbz		icmptype = pd->hdr.icmp->icmp_type;
3402223637Sbz		icmpcode = pd->hdr.icmp->icmp_code;
3403223637Sbz
3404223637Sbz		if (icmptype == ICMP_UNREACH ||
3405223637Sbz		    icmptype == ICMP_SOURCEQUENCH ||
3406223637Sbz		    icmptype == ICMP_REDIRECT ||
3407223637Sbz		    icmptype == ICMP_TIMXCEED ||
3408223637Sbz		    icmptype == ICMP_PARAMPROB)
3409223637Sbz			state_icmp++;
3410223637Sbz		break;
3411223637Sbz#endif /* INET */
3412223637Sbz#ifdef INET6
3413223637Sbz	case IPPROTO_ICMPV6:
3414223637Sbz		if (af != AF_INET6)
3415223637Sbz			break;
3416223637Sbz		sport = dport = pd->hdr.icmp6->icmp6_id;
3417223637Sbz		hdrlen = sizeof(*pd->hdr.icmp6);
3418223637Sbz		icmptype = pd->hdr.icmp6->icmp6_type;
3419223637Sbz		icmpcode = pd->hdr.icmp6->icmp6_code;
3420223637Sbz
3421223637Sbz		if (icmptype == ICMP6_DST_UNREACH ||
3422223637Sbz		    icmptype == ICMP6_PACKET_TOO_BIG ||
3423223637Sbz		    icmptype == ICMP6_TIME_EXCEEDED ||
3424223637Sbz		    icmptype == ICMP6_PARAM_PROB)
3425223637Sbz			state_icmp++;
3426223637Sbz		break;
3427223637Sbz#endif /* INET6 */
3428223637Sbz	default:
3429223637Sbz		sport = dport = hdrlen = 0;
3430223637Sbz		break;
3431223637Sbz	}
3432223637Sbz
3433126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3434126258Smlaier
3435223637Sbz	/* check packet for BINAT/NAT/RDR */
3436223637Sbz	if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn,
3437223637Sbz	    &skw, &sks, &sk, &nk, saddr, daddr, sport, dport)) != NULL) {
3438223637Sbz		if (nk == NULL || sk == NULL) {
3439223637Sbz			REASON_SET(&reason, PFRES_MEMORY);
3440223637Sbz			goto cleanup;
3441126258Smlaier		}
3442223637Sbz
3443223637Sbz		if (pd->ip_sum)
3444223637Sbz			bip_sum = *pd->ip_sum;
3445223637Sbz
3446223637Sbz		switch (pd->proto) {
3447223637Sbz		case IPPROTO_TCP:
3448223637Sbz			bproto_sum = th->th_sum;
3449223637Sbz			pd->proto_sum = &th->th_sum;
3450223637Sbz
3451223637Sbz			if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) ||
3452223637Sbz			    nk->port[pd->sidx] != sport) {
3453293896Sglebius				pf_change_ap(m, saddr, &th->th_sport, pd->ip_sum,
3454223637Sbz				    &th->th_sum, &nk->addr[pd->sidx],
3455223637Sbz				    nk->port[pd->sidx], 0, af);
3456223637Sbz				pd->sport = &th->th_sport;
3457223637Sbz				sport = th->th_sport;
3458223637Sbz			}
3459223637Sbz
3460223637Sbz			if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) ||
3461223637Sbz			    nk->port[pd->didx] != dport) {
3462293896Sglebius				pf_change_ap(m, daddr, &th->th_dport, pd->ip_sum,
3463223637Sbz				    &th->th_sum, &nk->addr[pd->didx],
3464223637Sbz				    nk->port[pd->didx], 0, af);
3465223637Sbz				dport = th->th_dport;
3466223637Sbz				pd->dport = &th->th_dport;
3467223637Sbz			}
3468126258Smlaier			rewrite++;
3469223637Sbz			break;
3470223637Sbz		case IPPROTO_UDP:
3471223637Sbz			bproto_sum = pd->hdr.udp->uh_sum;
3472223637Sbz			pd->proto_sum = &pd->hdr.udp->uh_sum;
3473223637Sbz
3474223637Sbz			if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) ||
3475223637Sbz			    nk->port[pd->sidx] != sport) {
3476293896Sglebius				pf_change_ap(m, saddr, &pd->hdr.udp->uh_sport,
3477223637Sbz				    pd->ip_sum, &pd->hdr.udp->uh_sum,
3478223637Sbz				    &nk->addr[pd->sidx],
3479223637Sbz				    nk->port[pd->sidx], 1, af);
3480223637Sbz				sport = pd->hdr.udp->uh_sport;
3481223637Sbz				pd->sport = &pd->hdr.udp->uh_sport;
3482223637Sbz			}
3483223637Sbz
3484223637Sbz			if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) ||
3485223637Sbz			    nk->port[pd->didx] != dport) {
3486293896Sglebius				pf_change_ap(m, daddr, &pd->hdr.udp->uh_dport,
3487223637Sbz				    pd->ip_sum, &pd->hdr.udp->uh_sum,
3488223637Sbz				    &nk->addr[pd->didx],
3489223637Sbz				    nk->port[pd->didx], 1, af);
3490223637Sbz				dport = pd->hdr.udp->uh_dport;
3491223637Sbz				pd->dport = &pd->hdr.udp->uh_dport;
3492223637Sbz			}
3493223637Sbz			rewrite++;
3494223637Sbz			break;
3495223637Sbz#ifdef INET
3496223637Sbz		case IPPROTO_ICMP:
3497223637Sbz			nk->port[0] = nk->port[1];
3498223637Sbz			if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET))
3499223637Sbz				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3500223637Sbz				    nk->addr[pd->sidx].v4.s_addr, 0);
3501223637Sbz
3502223637Sbz			if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET))
3503223637Sbz				pf_change_a(&daddr->v4.s_addr, pd->ip_sum,
3504223637Sbz				    nk->addr[pd->didx].v4.s_addr, 0);
3505223637Sbz
3506223637Sbz			if (nk->port[1] != pd->hdr.icmp->icmp_id) {
3507223637Sbz				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
3508223637Sbz				    pd->hdr.icmp->icmp_cksum, sport,
3509223637Sbz				    nk->port[1], 0);
3510223637Sbz				pd->hdr.icmp->icmp_id = nk->port[1];
3511223637Sbz				pd->sport = &pd->hdr.icmp->icmp_id;
3512223637Sbz			}
3513223637Sbz			m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp);
3514223637Sbz			break;
3515223637Sbz#endif /* INET */
3516223637Sbz#ifdef INET6
3517223637Sbz		case IPPROTO_ICMPV6:
3518223637Sbz			nk->port[0] = nk->port[1];
3519223637Sbz			if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6))
3520223637Sbz				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
3521223637Sbz				    &nk->addr[pd->sidx], 0);
3522223637Sbz
3523223637Sbz			if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6))
3524223637Sbz				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
3525223637Sbz				    &nk->addr[pd->didx], 0);
3526223637Sbz			rewrite++;
3527223637Sbz			break;
3528223637Sbz#endif /* INET */
3529223637Sbz		default:
3530223637Sbz			switch (af) {
3531223637Sbz#ifdef INET
3532223637Sbz			case AF_INET:
3533223637Sbz				if (PF_ANEQ(saddr,
3534223637Sbz				    &nk->addr[pd->sidx], AF_INET))
3535223637Sbz					pf_change_a(&saddr->v4.s_addr,
3536223637Sbz					    pd->ip_sum,
3537223637Sbz					    nk->addr[pd->sidx].v4.s_addr, 0);
3538223637Sbz
3539223637Sbz				if (PF_ANEQ(daddr,
3540223637Sbz				    &nk->addr[pd->didx], AF_INET))
3541223637Sbz					pf_change_a(&daddr->v4.s_addr,
3542223637Sbz					    pd->ip_sum,
3543223637Sbz					    nk->addr[pd->didx].v4.s_addr, 0);
3544223637Sbz				break;
3545223637Sbz#endif /* INET */
3546223637Sbz#ifdef INET6
3547223637Sbz			case AF_INET6:
3548223637Sbz				if (PF_ANEQ(saddr,
3549223637Sbz				    &nk->addr[pd->sidx], AF_INET6))
3550223637Sbz					PF_ACPY(saddr, &nk->addr[pd->sidx], af);
3551223637Sbz
3552223637Sbz				if (PF_ANEQ(daddr,
3553223637Sbz				    &nk->addr[pd->didx], AF_INET6))
3554223637Sbz					PF_ACPY(saddr, &nk->addr[pd->didx], af);
3555223637Sbz				break;
3556223637Sbz#endif /* INET */
3557223637Sbz			}
3558223637Sbz			break;
3559126258Smlaier		}
3560223637Sbz		if (nr->natpass)
3561223637Sbz			r = NULL;
3562223637Sbz		pd->nat_rule = nr;
3563126258Smlaier	}
3564126258Smlaier
3565126258Smlaier	while (r != NULL) {
3566126258Smlaier		r->evaluations++;
3567171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3568126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3569126258Smlaier		else if (r->direction && r->direction != direction)
3570126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3571126258Smlaier		else if (r->af && r->af != af)
3572126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3573223637Sbz		else if (r->proto && r->proto != pd->proto)
3574126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3575171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3576232292Sbz		    r->src.neg, kif, M_GETFIB(m)))
3577126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3578223637Sbz		/* tcp/udp only. port_op always 0 in other cases */
3579126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3580223637Sbz		    r->src.port[0], r->src.port[1], sport))
3581126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3582171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3583232292Sbz		    r->dst.neg, NULL, M_GETFIB(m)))
3584126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3585223637Sbz		/* tcp/udp only. port_op always 0 in other cases */
3586126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3587223637Sbz		    r->dst.port[0], r->dst.port[1], dport))
3588126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3589223637Sbz		/* icmp only. type always 0 in other cases */
3590223637Sbz		else if (r->type && r->type != icmptype + 1)
3591223637Sbz			r = TAILQ_NEXT(r, entries);
3592223637Sbz		/* icmp only. type always 0 in other cases */
3593223637Sbz		else if (r->code && r->code != icmpcode + 1)
3594223637Sbz			r = TAILQ_NEXT(r, entries);
3595171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3596126258Smlaier			r = TAILQ_NEXT(r, entries);
3597126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3598126258Smlaier			r = TAILQ_NEXT(r, entries);
3599223637Sbz		else if (pd->proto == IPPROTO_TCP &&
3600223637Sbz		    (r->flagset & th->th_flags) != r->flags)
3601126258Smlaier			r = TAILQ_NEXT(r, entries);
3602223637Sbz		/* tcp/udp only. uid.op always 0 in other cases */
3603171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3604135920Smlaier#ifdef __FreeBSD__
3605171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3606135920Smlaier#else
3607171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3608135920Smlaier#endif
3609126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3610171168Smlaier		    pd->lookup.uid))
3611126258Smlaier			r = TAILQ_NEXT(r, entries);
3612223637Sbz		/* tcp/udp only. gid.op always 0 in other cases */
3613171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3614135920Smlaier#ifdef __FreeBSD__
3615171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3616135920Smlaier#else
3617171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3618135920Smlaier#endif
3619126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3620171168Smlaier		    pd->lookup.gid))
3621126258Smlaier			r = TAILQ_NEXT(r, entries);
3622223637Sbz		else if (r->prob &&
3623223637Sbz#ifdef __FreeBSD__
3624223637Sbz		    r->prob <= arc4random())
3625223637Sbz#else
3626223637Sbz		    r->prob <= arc4random_uniform(UINT_MAX - 1) + 1)
3627223637Sbz#endif
3628126258Smlaier			r = TAILQ_NEXT(r, entries);
3629223637Sbz#ifdef __FreeBSD__
3630223637Sbz		else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag))
3631223637Sbz#else
3632223637Sbz		else if (r->match_tag && !pf_match_tag(m, r, &tag))
3633223637Sbz#endif
3634126258Smlaier			r = TAILQ_NEXT(r, entries);
3635223637Sbz		else if (r->os_fingerprint != PF_OSFP_ANY &&
3636223637Sbz		    (pd->proto != IPPROTO_TCP || !pf_osfp_match(
3637223637Sbz		    pf_osfp_fingerprint(pd, m, off, th),
3638223637Sbz		    r->os_fingerprint)))
3639126258Smlaier			r = TAILQ_NEXT(r, entries);
3640126258Smlaier		else {
3641126258Smlaier			if (r->tag)
3642126258Smlaier				tag = r->tag;
3643171168Smlaier			if (r->rtableid >= 0)
3644171168Smlaier				rtableid = r->rtableid;
3645126258Smlaier			if (r->anchor == NULL) {
3646171168Smlaier				match = 1;
3647126258Smlaier				*rm = r;
3648126258Smlaier				*am = a;
3649126258Smlaier				*rsm = ruleset;
3650126258Smlaier				if ((*rm)->quick)
3651126258Smlaier					break;
3652126258Smlaier				r = TAILQ_NEXT(r, entries);
3653126258Smlaier			} else
3654145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3655171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3656126258Smlaier		}
3657171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3658171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3659171168Smlaier			break;
3660126258Smlaier	}
3661126258Smlaier	r = *rm;
3662126258Smlaier	a = *am;
3663126258Smlaier	ruleset = *rsm;
3664126258Smlaier
3665126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3666126258Smlaier
3667223637Sbz	if (r->log || (nr != NULL && nr->log)) {
3668126258Smlaier		if (rewrite)
3669223637Sbz			m_copyback(m, off, hdrlen, pd->hdr.any);
3670171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3671171168Smlaier		    a, ruleset, pd);
3672126258Smlaier	}
3673126258Smlaier
3674126258Smlaier	if ((r->action == PF_DROP) &&
3675126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3676126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3677126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3678126258Smlaier		/* undo NAT changes, if they have taken place */
3679130613Smlaier		if (nr != NULL) {
3680223637Sbz			PF_ACPY(saddr, &sk->addr[pd->sidx], af);
3681223637Sbz			PF_ACPY(daddr, &sk->addr[pd->didx], af);
3682223637Sbz			if (pd->sport)
3683223637Sbz				*pd->sport = sk->port[pd->sidx];
3684223637Sbz			if (pd->dport)
3685223637Sbz				*pd->dport = sk->port[pd->didx];
3686223637Sbz			if (pd->proto_sum)
3687223637Sbz				*pd->proto_sum = bproto_sum;
3688223637Sbz			if (pd->ip_sum)
3689223637Sbz				*pd->ip_sum = bip_sum;
3690223637Sbz			m_copyback(m, off, hdrlen, pd->hdr.any);
3691126258Smlaier		}
3692223637Sbz		if (pd->proto == IPPROTO_TCP &&
3693223637Sbz		    ((r->rule_flag & PFRULE_RETURNRST) ||
3694126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3695126258Smlaier		    !(th->th_flags & TH_RST)) {
3696223637Sbz			u_int32_t	 ack = ntohl(th->th_seq) + pd->p_len;
3697223637Sbz			int		 len = 0;
3698223637Sbz#ifdef INET
3699223637Sbz			struct ip	*h4;
3700223637Sbz#endif
3701223637Sbz#ifdef INET6
3702223637Sbz			struct ip6_hdr	*h6;
3703223637Sbz#endif
3704126258Smlaier
3705223637Sbz			switch (af) {
3706223637Sbz#ifdef INET
3707223637Sbz			case AF_INET:
3708223637Sbz				h4 = mtod(m, struct ip *);
3709223637Sbz				len = ntohs(h4->ip_len) - off;
3710223637Sbz				break;
3711223637Sbz#endif
3712223637Sbz#ifdef INET6
3713223637Sbz			case AF_INET6:
3714223637Sbz				h6 = mtod(m, struct ip6_hdr *);
3715223637Sbz				len = ntohs(h6->ip6_plen) - (off - sizeof(*h6));
3716223637Sbz				break;
3717223637Sbz#endif
3718223637Sbz			}
3719223637Sbz
3720223637Sbz			if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af))
3721223637Sbz				REASON_SET(&reason, PFRES_PROTCKSUM);
3722223637Sbz			else {
3723223637Sbz				if (th->th_flags & TH_SYN)
3724223637Sbz					ack++;
3725223637Sbz				if (th->th_flags & TH_FIN)
3726223637Sbz					ack++;
3727162238Scsjp#ifdef __FreeBSD__
3728223637Sbz				pf_send_tcp(m, r, af, pd->dst,
3729162238Scsjp#else
3730223637Sbz				pf_send_tcp(r, af, pd->dst,
3731162238Scsjp#endif
3732223637Sbz				    pd->src, th->th_dport, th->th_sport,
3733223637Sbz				    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3734223637Sbz				    r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
3735223637Sbz			}
3736223637Sbz		} else if (pd->proto != IPPROTO_ICMP && af == AF_INET &&
3737223637Sbz		    r->return_icmp)
3738126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3739126258Smlaier			    r->return_icmp & 255, af, r);
3740223637Sbz		else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 &&
3741223637Sbz		    r->return_icmp6)
3742126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3743126258Smlaier			    r->return_icmp6 & 255, af, r);
3744126258Smlaier	}
3745126258Smlaier
3746126258Smlaier	if (r->action == PF_DROP)
3747223637Sbz		goto cleanup;
3748126258Smlaier
3749223637Sbz#ifdef __FreeBSD__
3750223637Sbz	if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag)) {
3751223637Sbz#else
3752223637Sbz	if (pf_tag_packet(m, tag, rtableid)) {
3753223637Sbz#endif
3754126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3755223637Sbz		goto cleanup;
3756126258Smlaier	}
3757126258Smlaier
3758223637Sbz	if (!state_icmp && (r->keep_state || nr != NULL ||
3759223637Sbz	    (pd->flags & PFDESC_TCP_NORM))) {
3760223637Sbz		int action;
3761223637Sbz		action = pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m,
3762223637Sbz		    off, sport, dport, &rewrite, kif, sm, tag, bproto_sum,
3763223637Sbz		    bip_sum, hdrlen);
3764223637Sbz		if (action != PF_PASS)
3765223637Sbz			return (action);
3766223637Sbz	} else {
3767223637Sbz#ifdef __FreeBSD__
3768223637Sbz		if (sk != NULL)
3769223637Sbz			pool_put(&V_pf_state_key_pl, sk);
3770223637Sbz		if (nk != NULL)
3771223637Sbz			pool_put(&V_pf_state_key_pl, nk);
3772223637Sbz#else
3773223637Sbz		if (sk != NULL)
3774223637Sbz			pool_put(&pf_state_key_pl, sk);
3775223637Sbz		if (nk != NULL)
3776223637Sbz			pool_put(&pf_state_key_pl, nk);
3777223637Sbz#endif
3778223637Sbz	}
3779126258Smlaier
3780223637Sbz	/* copy back packet headers if we performed NAT operations */
3781223637Sbz	if (rewrite)
3782223637Sbz		m_copyback(m, off, hdrlen, pd->hdr.any);
3783130613Smlaier
3784223637Sbz#if NPFSYNC > 0
3785223637Sbz	if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) &&
3786223637Sbz#ifdef __FreeBSD__
3787223637Sbz	    direction == PF_OUT && pfsync_up_ptr != NULL && pfsync_up_ptr()) {
3788223637Sbz#else
3789223637Sbz	    direction == PF_OUT && pfsync_up()) {
3790223637Sbz#endif
3791223637Sbz		/*
3792223637Sbz		 * We want the state created, but we dont
3793223637Sbz		 * want to send this in case a partner
3794223637Sbz		 * firewall has to know about it to allow
3795223637Sbz		 * replies through it.
3796223637Sbz		 */
3797223637Sbz#ifdef __FreeBSD__
3798228182Sglebius		if (pfsync_defer_ptr != NULL &&
3799228182Sglebius			pfsync_defer_ptr(*sm, m))
3800223637Sbz#else
3801223637Sbz		if (pfsync_defer(*sm, m))
3802223637Sbz#endif
3803223637Sbz			return (PF_DEFER);
3804223637Sbz	}
3805223637Sbz#endif
3806223637Sbz
3807223637Sbz	return (PF_PASS);
3808223637Sbz
3809130613Smlaiercleanup:
3810223637Sbz#ifdef __FreeBSD__
3811223637Sbz	if (sk != NULL)
3812223637Sbz		pool_put(&V_pf_state_key_pl, sk);
3813223637Sbz	if (nk != NULL)
3814223637Sbz		pool_put(&V_pf_state_key_pl, nk);
3815223637Sbz#else
3816223637Sbz	if (sk != NULL)
3817223637Sbz		pool_put(&pf_state_key_pl, sk);
3818223637Sbz	if (nk != NULL)
3819223637Sbz		pool_put(&pf_state_key_pl, nk);
3820223637Sbz#endif
3821223637Sbz	return (PF_DROP);
3822223637Sbz}
3823126258Smlaier
3824223637Sbzstatic __inline int
3825223637Sbzpf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a,
3826223637Sbz    struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *skw,
3827223637Sbz    struct pf_state_key *sks, struct pf_state_key *nk, struct pf_state_key *sk,
3828223637Sbz    struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite,
3829223637Sbz    struct pfi_kif *kif, struct pf_state **sm, int tag, u_int16_t bproto_sum,
3830223637Sbz    u_int16_t bip_sum, int hdrlen)
3831223637Sbz{
3832223637Sbz	struct pf_state		*s = NULL;
3833223637Sbz	struct pf_src_node	*sn = NULL;
3834223637Sbz	struct tcphdr		*th = pd->hdr.tcp;
3835223637Sbz#ifdef __FreeBSD__
3836223637Sbz	u_int16_t		 mss = V_tcp_mssdflt;
3837223637Sbz#else
3838223637Sbz	u_int16_t		 mss = tcp_mssdflt;
3839223637Sbz#endif
3840223637Sbz	u_short			 reason;
3841223637Sbz
3842223637Sbz	/* check maximums */
3843223637Sbz	if (r->max_states && (r->states_cur >= r->max_states)) {
3844223637Sbz#ifdef __FreeBSD__
3845223637Sbz		V_pf_status.lcounters[LCNT_STATES]++;
3846223637Sbz#else
3847223637Sbz		pf_status.lcounters[LCNT_STATES]++;
3848223637Sbz#endif
3849223637Sbz		REASON_SET(&reason, PFRES_MAXSTATES);
3850223637Sbz		return (PF_DROP);
3851223637Sbz	}
3852223637Sbz	/* src node for filter rule */
3853223637Sbz	if ((r->rule_flag & PFRULE_SRCTRACK ||
3854223637Sbz	    r->rpool.opts & PF_POOL_STICKYADDR) &&
3855223637Sbz	    pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) {
3856223637Sbz		REASON_SET(&reason, PFRES_SRCLIMIT);
3857223637Sbz		goto csfailed;
3858223637Sbz	}
3859223637Sbz	/* src node for translation rule */
3860223637Sbz	if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3861223637Sbz	    pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], pd->af)) {
3862223637Sbz		REASON_SET(&reason, PFRES_SRCLIMIT);
3863223637Sbz		goto csfailed;
3864223637Sbz	}
3865223637Sbz#ifdef __FreeBSD__
3866223637Sbz	s = pool_get(&V_pf_state_pl, PR_NOWAIT | PR_ZERO);
3867223637Sbz#else
3868223637Sbz	s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO);
3869223637Sbz#endif
3870223637Sbz	if (s == NULL) {
3871223637Sbz		REASON_SET(&reason, PFRES_MEMORY);
3872223637Sbz		goto csfailed;
3873223637Sbz	}
3874223637Sbz	s->rule.ptr = r;
3875223637Sbz	s->nat_rule.ptr = nr;
3876223637Sbz	s->anchor.ptr = a;
3877223637Sbz	STATE_INC_COUNTERS(s);
3878223637Sbz	if (r->allow_opts)
3879223637Sbz		s->state_flags |= PFSTATE_ALLOWOPTS;
3880223637Sbz	if (r->rule_flag & PFRULE_STATESLOPPY)
3881223637Sbz		s->state_flags |= PFSTATE_SLOPPY;
3882223637Sbz	if (r->rule_flag & PFRULE_PFLOW)
3883223637Sbz		s->state_flags |= PFSTATE_PFLOW;
3884223637Sbz	s->log = r->log & PF_LOG_ALL;
3885223637Sbz	s->sync_state = PFSYNC_S_NONE;
3886223637Sbz	if (nr != NULL)
3887223637Sbz		s->log |= nr->log & PF_LOG_ALL;
3888223637Sbz	switch (pd->proto) {
3889223637Sbz	case IPPROTO_TCP:
3890126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3891223637Sbz		s->src.seqhi = s->src.seqlo + pd->p_len + 1;
3892126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3893126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3894126258Smlaier			/* Generate sequence number modulator */
3895223637Sbz			if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) ==
3896223637Sbz			    0)
3897223637Sbz				s->src.seqdiff = 1;
3898293896Sglebius			pf_change_proto_a(m, &th->th_seq, &th->th_sum,
3899126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3900223637Sbz			*rewrite = 1;
3901126258Smlaier		} else
3902126258Smlaier			s->src.seqdiff = 0;
3903126258Smlaier		if (th->th_flags & TH_SYN) {
3904126258Smlaier			s->src.seqhi++;
3905223637Sbz			s->src.wscale = pf_get_wscale(m, off,
3906223637Sbz			    th->th_off, pd->af);
3907126258Smlaier		}
3908126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3909126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3910126258Smlaier			/* Remove scale factor from initial window */
3911126258Smlaier			int win = s->src.max_win;
3912126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3913126258Smlaier			s->src.max_win = (win - 1) >>
3914126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3915126258Smlaier		}
3916126258Smlaier		if (th->th_flags & TH_FIN)
3917126258Smlaier			s->src.seqhi++;
3918126258Smlaier		s->dst.seqhi = 1;
3919126258Smlaier		s->dst.max_win = 1;
3920126258Smlaier		s->src.state = TCPS_SYN_SENT;
3921126258Smlaier		s->dst.state = TCPS_CLOSED;
3922126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3923223637Sbz		break;
3924223637Sbz	case IPPROTO_UDP:
3925223637Sbz		s->src.state = PFUDPS_SINGLE;
3926223637Sbz		s->dst.state = PFUDPS_NO_TRAFFIC;
3927223637Sbz		s->timeout = PFTM_UDP_FIRST_PACKET;
3928223637Sbz		break;
3929223637Sbz	case IPPROTO_ICMP:
3930223637Sbz#ifdef INET6
3931223637Sbz	case IPPROTO_ICMPV6:
3932223637Sbz#endif
3933223637Sbz		s->timeout = PFTM_ICMP_FIRST_PACKET;
3934223637Sbz		break;
3935223637Sbz	default:
3936223637Sbz		s->src.state = PFOTHERS_SINGLE;
3937223637Sbz		s->dst.state = PFOTHERS_NO_TRAFFIC;
3938223637Sbz		s->timeout = PFTM_OTHER_FIRST_PACKET;
3939223637Sbz	}
3940223637Sbz
3941223637Sbz	s->creation = time_second;
3942223637Sbz	s->expire = time_second;
3943223637Sbz
3944223637Sbz	if (sn != NULL) {
3945223637Sbz		s->src_node = sn;
3946223637Sbz		s->src_node->states++;
3947223637Sbz	}
3948223637Sbz	if (nsn != NULL) {
3949223637Sbz		/* XXX We only modify one side for now. */
3950223637Sbz		PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af);
3951223637Sbz		s->nat_src_node = nsn;
3952223637Sbz		s->nat_src_node->states++;
3953223637Sbz	}
3954223637Sbz	if (pd->proto == IPPROTO_TCP) {
3955126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3956126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3957126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3958130613Smlaier			pf_src_tree_remove_state(s);
3959145836Smlaier			STATE_DEC_COUNTERS(s);
3960223637Sbz#ifdef __FreeBSD__
3961223637Sbz			pool_put(&V_pf_state_pl, s);
3962223637Sbz#else
3963126258Smlaier			pool_put(&pf_state_pl, s);
3964223637Sbz#endif
3965126258Smlaier			return (PF_DROP);
3966126258Smlaier		}
3967126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3968145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3969223637Sbz		    &s->src, &s->dst, rewrite)) {
3970145836Smlaier			/* This really shouldn't happen!!! */
3971145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3972145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3973126258Smlaier			pf_normalize_tcp_cleanup(s);
3974130613Smlaier			pf_src_tree_remove_state(s);
3975145836Smlaier			STATE_DEC_COUNTERS(s);
3976162238Scsjp#ifdef __FreeBSD__
3977223637Sbz			pool_put(&V_pf_state_pl, s);
3978162238Scsjp#else
3979223637Sbz			pool_put(&pf_state_pl, s);
3980162238Scsjp#endif
3981223637Sbz			return (PF_DROP);
3982126258Smlaier		}
3983126258Smlaier	}
3984223637Sbz	s->direction = pd->dir;
3985126258Smlaier
3986223637Sbz	if (sk == NULL && pf_state_key_setup(pd, nr, &skw, &sks, &sk, &nk,
3987223637Sbz	    pd->src, pd->dst, sport, dport))
3988223637Sbz		goto csfailed;
3989126258Smlaier
3990223637Sbz	if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) {
3991223637Sbz		if (pd->proto == IPPROTO_TCP)
3992223637Sbz			pf_normalize_tcp_cleanup(s);
3993223637Sbz		REASON_SET(&reason, PFRES_STATEINS);
3994223637Sbz		pf_src_tree_remove_state(s);
3995223637Sbz		STATE_DEC_COUNTERS(s);
3996135920Smlaier#ifdef __FreeBSD__
3997223637Sbz		pool_put(&V_pf_state_pl, s);
3998135920Smlaier#else
3999223637Sbz		pool_put(&pf_state_pl, s);
4000135920Smlaier#endif
4001223637Sbz		return (PF_DROP);
4002223637Sbz	} else
4003223637Sbz		*sm = s;
4004126258Smlaier
4005223637Sbz	pf_set_rt_ifp(s, pd->src);	/* needs s->state_key set */
4006223637Sbz	if (tag > 0) {
4007223637Sbz		pf_tag_ref(tag);
4008223637Sbz		s->tag = tag;
4009145836Smlaier	}
4010223637Sbz	if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) ==
4011223637Sbz	    TH_SYN && r->keep_state == PF_STATE_SYNPROXY) {
4012223637Sbz		s->src.state = PF_TCPS_PROXY_SRC;
4013223637Sbz		/* undo NAT changes, if they have taken place */
4014223637Sbz		if (nr != NULL) {
4015223637Sbz			struct pf_state_key *skt = s->key[PF_SK_WIRE];
4016223637Sbz			if (pd->dir == PF_OUT)
4017223637Sbz				skt = s->key[PF_SK_STACK];
4018223637Sbz			PF_ACPY(pd->src, &skt->addr[pd->sidx], pd->af);
4019223637Sbz			PF_ACPY(pd->dst, &skt->addr[pd->didx], pd->af);
4020223637Sbz			if (pd->sport)
4021223637Sbz				*pd->sport = skt->port[pd->sidx];
4022223637Sbz			if (pd->dport)
4023223637Sbz				*pd->dport = skt->port[pd->didx];
4024223637Sbz			if (pd->proto_sum)
4025223637Sbz				*pd->proto_sum = bproto_sum;
4026223637Sbz			if (pd->ip_sum)
4027223637Sbz				*pd->ip_sum = bip_sum;
4028223637Sbz			m_copyback(m, off, hdrlen, pd->hdr.any);
4029223637Sbz		}
4030223637Sbz		s->src.seqhi = htonl(arc4random());
4031223637Sbz		/* Find mss option */
4032232292Sbz		int rtid = M_GETFIB(m);
4033223637Sbz		mss = pf_get_mss(m, off, th->th_off, pd->af);
4034232292Sbz		mss = pf_calc_mss(pd->src, pd->af, rtid, mss);
4035232292Sbz		mss = pf_calc_mss(pd->dst, pd->af, rtid, mss);
4036223637Sbz		s->src.mss = mss;
4037171168Smlaier#ifdef __FreeBSD__
4038223637Sbz		pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport,
4039223637Sbz#else
4040223637Sbz		pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport,
4041223637Sbz#endif
4042223637Sbz		    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
4043223637Sbz		    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
4044223637Sbz		REASON_SET(&reason, PFRES_SYNPROXY);
4045223637Sbz		return (PF_SYNPROXY_DROP);
4046171168Smlaier	}
4047165631Smlaier
4048223637Sbz	return (PF_PASS);
4049126258Smlaier
4050223637Sbzcsfailed:
4051135920Smlaier#ifdef __FreeBSD__
4052223637Sbz	if (sk != NULL)
4053223637Sbz		pool_put(&V_pf_state_key_pl, sk);
4054223637Sbz	if (nk != NULL)
4055223637Sbz		pool_put(&V_pf_state_key_pl, nk);
4056135920Smlaier#else
4057223637Sbz	if (sk != NULL)
4058223637Sbz		pool_put(&pf_state_key_pl, sk);
4059223637Sbz	if (nk != NULL)
4060223637Sbz		pool_put(&pf_state_key_pl, nk);
4061135920Smlaier#endif
4062223637Sbz
4063223637Sbz	if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4064135920Smlaier#ifdef __FreeBSD__
4065223637Sbz		RB_REMOVE(pf_src_tree, &V_tree_src_tracking, sn);
4066223637Sbz		V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4067223637Sbz		V_pf_status.src_nodes--;
4068223637Sbz		pool_put(&V_pf_src_tree_pl, sn);
4069135920Smlaier#else
4070223637Sbz		RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4071223637Sbz		pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4072223637Sbz		pf_status.src_nodes--;
4073223637Sbz		pool_put(&pf_src_tree_pl, sn);
4074135920Smlaier#endif
4075126258Smlaier	}
4076223637Sbz	if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) {
4077171168Smlaier#ifdef __FreeBSD__
4078223637Sbz		RB_REMOVE(pf_src_tree, &V_tree_src_tracking, nsn);
4079223637Sbz		V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4080223637Sbz		V_pf_status.src_nodes--;
4081223637Sbz		pool_put(&V_pf_src_tree_pl, nsn);
4082171168Smlaier#else
4083223637Sbz		RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4084223637Sbz		pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4085223637Sbz		pf_status.src_nodes--;
4086223637Sbz		pool_put(&pf_src_tree_pl, nsn);
4087171168Smlaier#endif
4088126258Smlaier	}
4089223637Sbz	return (PF_DROP);
4090126258Smlaier}
4091126258Smlaier
4092126258Smlaierint
4093130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4094126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4095126258Smlaier    struct pf_ruleset **rsm)
4096126258Smlaier{
4097126258Smlaier	struct pf_rule		*r, *a = NULL;
4098126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4099126258Smlaier	sa_family_t		 af = pd->af;
4100126258Smlaier	u_short			 reason;
4101126258Smlaier	int			 tag = -1;
4102145836Smlaier	int			 asd = 0;
4103171168Smlaier	int			 match = 0;
4104126258Smlaier
4105126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4106126258Smlaier	while (r != NULL) {
4107126258Smlaier		r->evaluations++;
4108171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4109126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4110126258Smlaier		else if (r->direction && r->direction != direction)
4111126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4112126258Smlaier		else if (r->af && r->af != af)
4113126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4114126258Smlaier		else if (r->proto && r->proto != pd->proto)
4115126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4116171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4117232292Sbz		    r->src.neg, kif, M_GETFIB(m)))
4118126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4119171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4120232292Sbz		    r->dst.neg, NULL, M_GETFIB(m)))
4121126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4122171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4123126258Smlaier			r = TAILQ_NEXT(r, entries);
4124173815Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4125126258Smlaier			r = TAILQ_NEXT(r, entries);
4126173815Smlaier		else if (pd->proto == IPPROTO_UDP &&
4127173815Smlaier		    (r->src.port_op || r->dst.port_op))
4128173815Smlaier			r = TAILQ_NEXT(r, entries);
4129173815Smlaier		else if (pd->proto == IPPROTO_TCP &&
4130173815Smlaier		    (r->src.port_op || r->dst.port_op || r->flagset))
4131173815Smlaier			r = TAILQ_NEXT(r, entries);
4132173815Smlaier		else if ((pd->proto == IPPROTO_ICMP ||
4133173815Smlaier		    pd->proto == IPPROTO_ICMPV6) &&
4134173815Smlaier		    (r->type || r->code))
4135173815Smlaier			r = TAILQ_NEXT(r, entries);
4136223637Sbz		else if (r->prob && r->prob <=
4137223637Sbz		    (arc4random() % (UINT_MAX - 1) + 1))
4138126258Smlaier			r = TAILQ_NEXT(r, entries);
4139223637Sbz#ifdef __FreeBSD__
4140223637Sbz		else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag))
4141223637Sbz#else
4142223637Sbz		else if (r->match_tag && !pf_match_tag(m, r, &tag))
4143223637Sbz#endif
4144126258Smlaier			r = TAILQ_NEXT(r, entries);
4145126258Smlaier		else {
4146126258Smlaier			if (r->anchor == NULL) {
4147171168Smlaier				match = 1;
4148126258Smlaier				*rm = r;
4149126258Smlaier				*am = a;
4150126258Smlaier				*rsm = ruleset;
4151126258Smlaier				if ((*rm)->quick)
4152126258Smlaier					break;
4153126258Smlaier				r = TAILQ_NEXT(r, entries);
4154126258Smlaier			} else
4155145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4156171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4157126258Smlaier		}
4158171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4159171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4160171168Smlaier			break;
4161126258Smlaier	}
4162126258Smlaier	r = *rm;
4163126258Smlaier	a = *am;
4164126258Smlaier	ruleset = *rsm;
4165126258Smlaier
4166126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4167130613Smlaier
4168126258Smlaier	if (r->log)
4169171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
4170171168Smlaier		    pd);
4171126258Smlaier
4172126258Smlaier	if (r->action != PF_PASS)
4173126258Smlaier		return (PF_DROP);
4174126258Smlaier
4175223637Sbz#ifdef __FreeBSD__
4176223637Sbz	if (pf_tag_packet(m, tag, -1, pd->pf_mtag)) {
4177223637Sbz#else
4178223637Sbz	if (pf_tag_packet(m, tag, -1)) {
4179223637Sbz#endif
4180126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4181126258Smlaier		return (PF_DROP);
4182126258Smlaier	}
4183126258Smlaier
4184126258Smlaier	return (PF_PASS);
4185126258Smlaier}
4186126258Smlaier
4187126258Smlaierint
4188200930Sdelphijpf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst,
4189200930Sdelphij	struct pf_state **state, struct pfi_kif *kif, struct mbuf *m, int off,
4190200930Sdelphij	struct pf_pdesc *pd, u_short *reason, int *copyback)
4191126258Smlaier{
4192223637Sbz	struct tcphdr		*th = pd->hdr.tcp;
4193223637Sbz	u_int16_t		 win = ntohs(th->th_win);
4194223637Sbz	u_int32_t		 ack, end, seq, orig_seq;
4195223637Sbz	u_int8_t		 sws, dws;
4196223637Sbz	int			 ackskew;
4197126258Smlaier
4198126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4199126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4200126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4201126258Smlaier	} else
4202126258Smlaier		sws = dws = 0;
4203126258Smlaier
4204126258Smlaier	/*
4205126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4206126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4207126258Smlaier	 *	tcp_filtering.ps
4208126258Smlaier	 */
4209126258Smlaier
4210145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4211126258Smlaier	if (src->seqlo == 0) {
4212126258Smlaier		/* First packet from this end. Set its state */
4213126258Smlaier
4214126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4215126258Smlaier		    src->scrub == NULL) {
4216126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4217126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4218126258Smlaier				return (PF_DROP);
4219126258Smlaier			}
4220126258Smlaier		}
4221126258Smlaier
4222126258Smlaier		/* Deferred generation of sequence number modulator */
4223126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4224223637Sbz			/* use random iss for the TCP server */
4225223637Sbz			while ((src->seqdiff = arc4random() - seq) == 0)
4226126258Smlaier				;
4227126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4228293896Sglebius			pf_change_proto_a(m, &th->th_seq, &th->th_sum, htonl(seq +
4229126258Smlaier			    src->seqdiff), 0);
4230293896Sglebius			pf_change_proto_a(m, &th->th_ack, &th->th_sum, htonl(ack), 0);
4231200930Sdelphij			*copyback = 1;
4232126258Smlaier		} else {
4233126258Smlaier			ack = ntohl(th->th_ack);
4234126258Smlaier		}
4235126258Smlaier
4236126258Smlaier		end = seq + pd->p_len;
4237126258Smlaier		if (th->th_flags & TH_SYN) {
4238126258Smlaier			end++;
4239126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4240126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4241126258Smlaier				    pd->af);
4242126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4243126258Smlaier					/* Remove scale factor from initial
4244126258Smlaier					 * window */
4245126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4246126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4247126258Smlaier					    >> sws;
4248126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4249126258Smlaier				} else {
4250126258Smlaier					/* fixup other window */
4251126258Smlaier					dst->max_win <<= dst->wscale &
4252126258Smlaier					    PF_WSCALE_MASK;
4253126258Smlaier					/* in case of a retrans SYN|ACK */
4254126258Smlaier					dst->wscale = 0;
4255126258Smlaier				}
4256126258Smlaier			}
4257126258Smlaier		}
4258126258Smlaier		if (th->th_flags & TH_FIN)
4259126258Smlaier			end++;
4260126258Smlaier
4261126258Smlaier		src->seqlo = seq;
4262126258Smlaier		if (src->state < TCPS_SYN_SENT)
4263126258Smlaier			src->state = TCPS_SYN_SENT;
4264126258Smlaier
4265126258Smlaier		/*
4266126258Smlaier		 * May need to slide the window (seqhi may have been set by
4267126258Smlaier		 * the crappy stack check or if we picked up the connection
4268126258Smlaier		 * after establishment)
4269126258Smlaier		 */
4270126258Smlaier		if (src->seqhi == 1 ||
4271126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4272126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4273126258Smlaier		if (win > src->max_win)
4274126258Smlaier			src->max_win = win;
4275126258Smlaier
4276126258Smlaier	} else {
4277126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4278126258Smlaier		if (src->seqdiff) {
4279126258Smlaier			/* Modulate sequence numbers */
4280293896Sglebius			pf_change_proto_a(m, &th->th_seq, &th->th_sum, htonl(seq +
4281126258Smlaier			    src->seqdiff), 0);
4282293896Sglebius			pf_change_proto_a(m, &th->th_ack, &th->th_sum, htonl(ack), 0);
4283200930Sdelphij			*copyback = 1;
4284126258Smlaier		}
4285126258Smlaier		end = seq + pd->p_len;
4286126258Smlaier		if (th->th_flags & TH_SYN)
4287126258Smlaier			end++;
4288126258Smlaier		if (th->th_flags & TH_FIN)
4289126258Smlaier			end++;
4290126258Smlaier	}
4291126258Smlaier
4292126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4293126258Smlaier		/* Let it pass through the ack skew check */
4294126258Smlaier		ack = dst->seqlo;
4295126258Smlaier	} else if ((ack == 0 &&
4296126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4297126258Smlaier	    /* broken tcp stacks do not set ack */
4298126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4299126258Smlaier		/*
4300126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4301126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4302126258Smlaier		 */
4303126258Smlaier		ack = dst->seqlo;
4304126258Smlaier	}
4305126258Smlaier
4306126258Smlaier	if (seq == end) {
4307126258Smlaier		/* Ease sequencing restrictions on no data packets */
4308126258Smlaier		seq = src->seqlo;
4309126258Smlaier		end = seq;
4310126258Smlaier	}
4311126258Smlaier
4312126258Smlaier	ackskew = dst->seqlo - ack;
4313126258Smlaier
4314171168Smlaier
4315171168Smlaier	/*
4316171168Smlaier	 * Need to demodulate the sequence numbers in any TCP SACK options
4317171168Smlaier	 * (Selective ACK). We could optionally validate the SACK values
4318171168Smlaier	 * against the current ACK window, either forwards or backwards, but
4319171168Smlaier	 * I'm not confident that SACK has been implemented properly
4320171168Smlaier	 * everywhere. It wouldn't surprise me if several stacks accidently
4321171168Smlaier	 * SACK too far backwards of previously ACKed data. There really aren't
4322171168Smlaier	 * any security implications of bad SACKing unless the target stack
4323171168Smlaier	 * doesn't validate the option length correctly. Someone trying to
4324171168Smlaier	 * spoof into a TCP connection won't bother blindly sending SACK
4325171168Smlaier	 * options anyway.
4326171168Smlaier	 */
4327171168Smlaier	if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
4328171168Smlaier		if (pf_modulate_sack(m, off, pd, th, dst))
4329200930Sdelphij			*copyback = 1;
4330171168Smlaier	}
4331171168Smlaier
4332171168Smlaier
4333223637Sbz#define	MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4334126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4335126258Smlaier	    /* Last octet inside other's window space */
4336126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4337126258Smlaier	    /* Retrans: not more than one window back */
4338126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4339126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4340145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4341126258Smlaier	    /* Acking not more than one window forward */
4342145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4343223637Sbz	    (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo) ||
4344223637Sbz	    (pd->flags & PFDESC_IP_REAS) == 0)) {
4345171168Smlaier	    /* Require an exact/+1 sequence match on resets when possible */
4346126258Smlaier
4347145836Smlaier		if (dst->scrub || src->scrub) {
4348145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4349200930Sdelphij			    *state, src, dst, copyback))
4350145836Smlaier				return (PF_DROP);
4351145836Smlaier		}
4352145836Smlaier
4353126258Smlaier		/* update max window */
4354126258Smlaier		if (src->max_win < win)
4355126258Smlaier			src->max_win = win;
4356126258Smlaier		/* synchronize sequencing */
4357126258Smlaier		if (SEQ_GT(end, src->seqlo))
4358126258Smlaier			src->seqlo = end;
4359126258Smlaier		/* slide the window of what the other end can send */
4360126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4361126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4362126258Smlaier
4363126258Smlaier
4364126258Smlaier		/* update states */
4365126258Smlaier		if (th->th_flags & TH_SYN)
4366126258Smlaier			if (src->state < TCPS_SYN_SENT)
4367126258Smlaier				src->state = TCPS_SYN_SENT;
4368126258Smlaier		if (th->th_flags & TH_FIN)
4369126258Smlaier			if (src->state < TCPS_CLOSING)
4370126258Smlaier				src->state = TCPS_CLOSING;
4371126258Smlaier		if (th->th_flags & TH_ACK) {
4372145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
4373126258Smlaier				dst->state = TCPS_ESTABLISHED;
4374145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
4375145836Smlaier				    (*state)->src_node != NULL &&
4376145836Smlaier				    pf_src_connlimit(state)) {
4377145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
4378145836Smlaier					return (PF_DROP);
4379145836Smlaier				}
4380145836Smlaier			} else if (dst->state == TCPS_CLOSING)
4381126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4382126258Smlaier		}
4383126258Smlaier		if (th->th_flags & TH_RST)
4384126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4385126258Smlaier
4386126258Smlaier		/* update expire time */
4387126261Smlaier		(*state)->expire = time_second;
4388126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4389126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4390126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4391171168Smlaier		else if (src->state >= TCPS_CLOSING &&
4392171168Smlaier		    dst->state >= TCPS_CLOSING)
4393126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4394126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
4395126258Smlaier		    dst->state < TCPS_ESTABLISHED)
4396126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
4397126258Smlaier		else if (src->state >= TCPS_CLOSING ||
4398126258Smlaier		    dst->state >= TCPS_CLOSING)
4399126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
4400126258Smlaier		else
4401126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
4402126258Smlaier
4403126258Smlaier		/* Fall through to PASS packet */
4404126258Smlaier
4405126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
4406126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
4407126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
4408126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
4409126258Smlaier	    /* Within a window forward of the originating packet */
4410126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
4411126258Smlaier	    /* Within a window backward of the originating packet */
4412126258Smlaier
4413126258Smlaier		/*
4414126258Smlaier		 * This currently handles three situations:
4415126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
4416126258Smlaier		 *     replies.
4417126258Smlaier		 *  2) When PF catches an already established stream (the
4418126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
4419126258Smlaier		 *     changed...)
4420126258Smlaier		 *  3) Packets get funky immediately after the connection
4421126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
4422126258Smlaier		 *     that web servers like to spew after a close)
4423126258Smlaier		 *
4424126258Smlaier		 * This must be a little more careful than the above code
4425126258Smlaier		 * since packet floods will also be caught here. We don't
4426126258Smlaier		 * update the TTL here to mitigate the damage of a packet
4427126258Smlaier		 * flood and so the same code can handle awkward establishment
4428126258Smlaier		 * and a loosened connection close.
4429126258Smlaier		 * In the establishment case, a correct peer response will
4430126258Smlaier		 * validate the connection, go through the normal state code
4431126258Smlaier		 * and keep updating the state TTL.
4432126258Smlaier		 */
4433126258Smlaier
4434223637Sbz#ifdef __FreeBSD__
4435223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC) {
4436223637Sbz#else
4437126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4438223637Sbz#endif
4439126258Smlaier			printf("pf: loose state match: ");
4440126258Smlaier			pf_print_state(*state);
4441126258Smlaier			pf_print_flags(th->th_flags);
4442171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
4443223637Sbz			    "pkts=%llu:%llu dir=%s,%s\n", seq, orig_seq, ack,
4444171168Smlaier#ifdef __FreeBSD__
4445223637Sbz			    pd->p_len, ackskew, (unsigned long long)(*state)->packets[0],
4446223637Sbz			    (unsigned long long)(*state)->packets[1],
4447171168Smlaier#else
4448223637Sbz			    pd->p_len, ackskew, (*state)->packets[0],
4449223637Sbz			    (*state)->packets[1],
4450171168Smlaier#endif
4451223637Sbz			    pd->dir == PF_IN ? "in" : "out",
4452223637Sbz			    pd->dir == (*state)->direction ? "fwd" : "rev");
4453126258Smlaier		}
4454126258Smlaier
4455145836Smlaier		if (dst->scrub || src->scrub) {
4456145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4457200930Sdelphij			    *state, src, dst, copyback))
4458145836Smlaier				return (PF_DROP);
4459145836Smlaier		}
4460145836Smlaier
4461126258Smlaier		/* update max window */
4462126258Smlaier		if (src->max_win < win)
4463126258Smlaier			src->max_win = win;
4464126258Smlaier		/* synchronize sequencing */
4465126258Smlaier		if (SEQ_GT(end, src->seqlo))
4466126258Smlaier			src->seqlo = end;
4467126258Smlaier		/* slide the window of what the other end can send */
4468126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4469126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4470126258Smlaier
4471126258Smlaier		/*
4472126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
4473126258Smlaier		 * SYN and not an already established connection.
4474126258Smlaier		 */
4475126258Smlaier
4476126258Smlaier		if (th->th_flags & TH_FIN)
4477126258Smlaier			if (src->state < TCPS_CLOSING)
4478126258Smlaier				src->state = TCPS_CLOSING;
4479126258Smlaier		if (th->th_flags & TH_RST)
4480126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4481126258Smlaier
4482126258Smlaier		/* Fall through to PASS packet */
4483126258Smlaier
4484126258Smlaier	} else {
4485126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
4486126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
4487126258Smlaier			/* Send RST for state mismatches during handshake */
4488145836Smlaier			if (!(th->th_flags & TH_RST))
4489162238Scsjp#ifdef __FreeBSD__
4490223637Sbz				pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4491162238Scsjp#else
4492126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
4493162238Scsjp#endif
4494126258Smlaier				    pd->dst, pd->src, th->th_dport,
4495145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
4496145836Smlaier				    TH_RST, 0, 0,
4497171168Smlaier				    (*state)->rule.ptr->return_ttl, 1, 0,
4498145836Smlaier				    pd->eh, kif->pfik_ifp);
4499126258Smlaier			src->seqlo = 0;
4500126258Smlaier			src->seqhi = 1;
4501126258Smlaier			src->max_win = 1;
4502223637Sbz#ifdef __FreeBSD__
4503223637Sbz		} else if (V_pf_status.debug >= PF_DEBUG_MISC) {
4504223637Sbz#else
4505126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
4506223637Sbz#endif
4507126258Smlaier			printf("pf: BAD state: ");
4508126258Smlaier			pf_print_state(*state);
4509126258Smlaier			pf_print_flags(th->th_flags);
4510171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
4511171168Smlaier			    "pkts=%llu:%llu dir=%s,%s\n",
4512171168Smlaier			    seq, orig_seq, ack, pd->p_len, ackskew,
4513171168Smlaier#ifdef __FreeBSD__
4514171168Smlaier			    (unsigned long long)(*state)->packets[0],
4515171168Smlaier			    (unsigned long long)(*state)->packets[1],
4516171168Smlaier#else
4517126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
4518171168Smlaier#endif
4519223637Sbz			    pd->dir == PF_IN ? "in" : "out",
4520223637Sbz			    pd->dir == (*state)->direction ? "fwd" : "rev");
4521126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
4522126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
4523126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
4524126258Smlaier			    ' ': '2',
4525126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
4526126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
4527126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
4528126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
4529126258Smlaier		}
4530145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
4531126258Smlaier		return (PF_DROP);
4532126258Smlaier	}
4533126258Smlaier
4534200930Sdelphij	return (PF_PASS);
4535200930Sdelphij}
4536126258Smlaier
4537200930Sdelphijint
4538200930Sdelphijpf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst,
4539200930Sdelphij	struct pf_state **state, struct pf_pdesc *pd, u_short *reason)
4540200930Sdelphij{
4541200930Sdelphij	struct tcphdr		*th = pd->hdr.tcp;
4542200930Sdelphij
4543200930Sdelphij	if (th->th_flags & TH_SYN)
4544200930Sdelphij		if (src->state < TCPS_SYN_SENT)
4545200930Sdelphij			src->state = TCPS_SYN_SENT;
4546200930Sdelphij	if (th->th_flags & TH_FIN)
4547200930Sdelphij		if (src->state < TCPS_CLOSING)
4548200930Sdelphij			src->state = TCPS_CLOSING;
4549200930Sdelphij	if (th->th_flags & TH_ACK) {
4550200930Sdelphij		if (dst->state == TCPS_SYN_SENT) {
4551200930Sdelphij			dst->state = TCPS_ESTABLISHED;
4552200930Sdelphij			if (src->state == TCPS_ESTABLISHED &&
4553200930Sdelphij			    (*state)->src_node != NULL &&
4554200930Sdelphij			    pf_src_connlimit(state)) {
4555200930Sdelphij				REASON_SET(reason, PFRES_SRCLIMIT);
4556200930Sdelphij				return (PF_DROP);
4557200930Sdelphij			}
4558200930Sdelphij		} else if (dst->state == TCPS_CLOSING) {
4559200930Sdelphij			dst->state = TCPS_FIN_WAIT_2;
4560200930Sdelphij		} else if (src->state == TCPS_SYN_SENT &&
4561200930Sdelphij		    dst->state < TCPS_SYN_SENT) {
4562200930Sdelphij			/*
4563200930Sdelphij			 * Handle a special sloppy case where we only see one
4564200930Sdelphij			 * half of the connection. If there is a ACK after
4565200930Sdelphij			 * the initial SYN without ever seeing a packet from
4566200930Sdelphij			 * the destination, set the connection to established.
4567200930Sdelphij			 */
4568200930Sdelphij			dst->state = src->state = TCPS_ESTABLISHED;
4569200930Sdelphij			if ((*state)->src_node != NULL &&
4570200930Sdelphij			    pf_src_connlimit(state)) {
4571200930Sdelphij				REASON_SET(reason, PFRES_SRCLIMIT);
4572200930Sdelphij				return (PF_DROP);
4573200930Sdelphij			}
4574200930Sdelphij		} else if (src->state == TCPS_CLOSING &&
4575200930Sdelphij		    dst->state == TCPS_ESTABLISHED &&
4576200930Sdelphij		    dst->seqlo == 0) {
4577200930Sdelphij			/*
4578200930Sdelphij			 * Handle the closing of half connections where we
4579200930Sdelphij			 * don't see the full bidirectional FIN/ACK+ACK
4580200930Sdelphij			 * handshake.
4581200930Sdelphij			 */
4582200930Sdelphij			dst->state = TCPS_CLOSING;
4583200930Sdelphij		}
4584200930Sdelphij	}
4585200930Sdelphij	if (th->th_flags & TH_RST)
4586200930Sdelphij		src->state = dst->state = TCPS_TIME_WAIT;
4587200930Sdelphij
4588200930Sdelphij	/* update expire time */
4589200930Sdelphij	(*state)->expire = time_second;
4590200930Sdelphij	if (src->state >= TCPS_FIN_WAIT_2 &&
4591200930Sdelphij	    dst->state >= TCPS_FIN_WAIT_2)
4592200930Sdelphij		(*state)->timeout = PFTM_TCP_CLOSED;
4593200930Sdelphij	else if (src->state >= TCPS_CLOSING &&
4594200930Sdelphij	    dst->state >= TCPS_CLOSING)
4595200930Sdelphij		(*state)->timeout = PFTM_TCP_FIN_WAIT;
4596200930Sdelphij	else if (src->state < TCPS_ESTABLISHED ||
4597200930Sdelphij	    dst->state < TCPS_ESTABLISHED)
4598200930Sdelphij		(*state)->timeout = PFTM_TCP_OPENING;
4599200930Sdelphij	else if (src->state >= TCPS_CLOSING ||
4600200930Sdelphij	    dst->state >= TCPS_CLOSING)
4601200930Sdelphij		(*state)->timeout = PFTM_TCP_CLOSING;
4602200930Sdelphij	else
4603200930Sdelphij		(*state)->timeout = PFTM_TCP_ESTABLISHED;
4604200930Sdelphij
4605200930Sdelphij	return (PF_PASS);
4606200930Sdelphij}
4607200930Sdelphij
4608200930Sdelphijint
4609200930Sdelphijpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4610200930Sdelphij    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4611200930Sdelphij    u_short *reason)
4612200930Sdelphij{
4613223637Sbz	struct pf_state_key_cmp	 key;
4614200930Sdelphij	struct tcphdr		*th = pd->hdr.tcp;
4615200930Sdelphij	int			 copyback = 0;
4616200930Sdelphij	struct pf_state_peer	*src, *dst;
4617223637Sbz	struct pf_state_key	*sk;
4618200930Sdelphij
4619200930Sdelphij	key.af = pd->af;
4620200930Sdelphij	key.proto = IPPROTO_TCP;
4621223637Sbz	if (direction == PF_IN)	{	/* wire side, straight */
4622223637Sbz		PF_ACPY(&key.addr[0], pd->src, key.af);
4623223637Sbz		PF_ACPY(&key.addr[1], pd->dst, key.af);
4624223637Sbz		key.port[0] = th->th_sport;
4625223637Sbz		key.port[1] = th->th_dport;
4626223637Sbz	} else {			/* stack side, reverse */
4627223637Sbz		PF_ACPY(&key.addr[1], pd->src, key.af);
4628223637Sbz		PF_ACPY(&key.addr[0], pd->dst, key.af);
4629223637Sbz		key.port[1] = th->th_sport;
4630223637Sbz		key.port[0] = th->th_dport;
4631200930Sdelphij	}
4632200930Sdelphij
4633223637Sbz#ifdef __FreeBSD__
4634223637Sbz	STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
4635223637Sbz#else
4636223637Sbz	STATE_LOOKUP(kif, &key, direction, *state, m);
4637223637Sbz#endif
4638200930Sdelphij
4639200930Sdelphij	if (direction == (*state)->direction) {
4640200930Sdelphij		src = &(*state)->src;
4641200930Sdelphij		dst = &(*state)->dst;
4642200930Sdelphij	} else {
4643200930Sdelphij		src = &(*state)->dst;
4644200930Sdelphij		dst = &(*state)->src;
4645200930Sdelphij	}
4646200930Sdelphij
4647223637Sbz	sk = (*state)->key[pd->didx];
4648223637Sbz
4649200930Sdelphij	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4650200930Sdelphij		if (direction != (*state)->direction) {
4651200930Sdelphij			REASON_SET(reason, PFRES_SYNPROXY);
4652200930Sdelphij			return (PF_SYNPROXY_DROP);
4653200930Sdelphij		}
4654200930Sdelphij		if (th->th_flags & TH_SYN) {
4655200930Sdelphij			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4656200930Sdelphij				REASON_SET(reason, PFRES_SYNPROXY);
4657200930Sdelphij				return (PF_DROP);
4658200930Sdelphij			}
4659200930Sdelphij#ifdef __FreeBSD__
4660200930Sdelphij			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4661200930Sdelphij#else
4662200930Sdelphij			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4663200930Sdelphij#endif
4664200930Sdelphij			    pd->src, th->th_dport, th->th_sport,
4665200930Sdelphij			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4666200930Sdelphij			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4667200930Sdelphij			    0, NULL, NULL);
4668200930Sdelphij			REASON_SET(reason, PFRES_SYNPROXY);
4669200930Sdelphij			return (PF_SYNPROXY_DROP);
4670200930Sdelphij		} else if (!(th->th_flags & TH_ACK) ||
4671200930Sdelphij		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4672200930Sdelphij		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4673200930Sdelphij			REASON_SET(reason, PFRES_SYNPROXY);
4674200930Sdelphij			return (PF_DROP);
4675200930Sdelphij		} else if ((*state)->src_node != NULL &&
4676200930Sdelphij		    pf_src_connlimit(state)) {
4677200930Sdelphij			REASON_SET(reason, PFRES_SRCLIMIT);
4678200930Sdelphij			return (PF_DROP);
4679200930Sdelphij		} else
4680200930Sdelphij			(*state)->src.state = PF_TCPS_PROXY_DST;
4681200930Sdelphij	}
4682200930Sdelphij	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4683200930Sdelphij		if (direction == (*state)->direction) {
4684200930Sdelphij			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4685200930Sdelphij			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4686200930Sdelphij			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4687200930Sdelphij				REASON_SET(reason, PFRES_SYNPROXY);
4688200930Sdelphij				return (PF_DROP);
4689200930Sdelphij			}
4690200930Sdelphij			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4691200930Sdelphij			if ((*state)->dst.seqhi == 1)
4692200930Sdelphij				(*state)->dst.seqhi = htonl(arc4random());
4693200930Sdelphij#ifdef __FreeBSD__
4694200930Sdelphij			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4695200930Sdelphij#else
4696223637Sbz			pf_send_tcp((*state)->rule.ptr, pd->af,
4697200930Sdelphij#endif
4698223637Sbz			    &sk->addr[pd->sidx], &sk->addr[pd->didx],
4699223637Sbz			    sk->port[pd->sidx], sk->port[pd->didx],
4700200930Sdelphij			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4701200930Sdelphij			    (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
4702200930Sdelphij			REASON_SET(reason, PFRES_SYNPROXY);
4703200930Sdelphij			return (PF_SYNPROXY_DROP);
4704200930Sdelphij		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4705200930Sdelphij		    (TH_SYN|TH_ACK)) ||
4706200930Sdelphij		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4707200930Sdelphij			REASON_SET(reason, PFRES_SYNPROXY);
4708200930Sdelphij			return (PF_DROP);
4709200930Sdelphij		} else {
4710200930Sdelphij			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4711200930Sdelphij			(*state)->dst.seqlo = ntohl(th->th_seq);
4712200930Sdelphij#ifdef __FreeBSD__
4713200930Sdelphij			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4714200930Sdelphij#else
4715200930Sdelphij			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4716200930Sdelphij#endif
4717200930Sdelphij			    pd->src, th->th_dport, th->th_sport,
4718200930Sdelphij			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4719200930Sdelphij			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4720200930Sdelphij			    (*state)->tag, NULL, NULL);
4721200930Sdelphij#ifdef __FreeBSD__
4722200930Sdelphij			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4723200930Sdelphij#else
4724223637Sbz			pf_send_tcp((*state)->rule.ptr, pd->af,
4725200930Sdelphij#endif
4726223637Sbz			    &sk->addr[pd->sidx], &sk->addr[pd->didx],
4727223637Sbz			    sk->port[pd->sidx], sk->port[pd->didx],
4728200930Sdelphij			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4729200930Sdelphij			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4730200930Sdelphij			    0, NULL, NULL);
4731200930Sdelphij			(*state)->src.seqdiff = (*state)->dst.seqhi -
4732200930Sdelphij			    (*state)->src.seqlo;
4733200930Sdelphij			(*state)->dst.seqdiff = (*state)->src.seqhi -
4734200930Sdelphij			    (*state)->dst.seqlo;
4735200930Sdelphij			(*state)->src.seqhi = (*state)->src.seqlo +
4736200930Sdelphij			    (*state)->dst.max_win;
4737200930Sdelphij			(*state)->dst.seqhi = (*state)->dst.seqlo +
4738200930Sdelphij			    (*state)->src.max_win;
4739200930Sdelphij			(*state)->src.wscale = (*state)->dst.wscale = 0;
4740200930Sdelphij			(*state)->src.state = (*state)->dst.state =
4741200930Sdelphij			    TCPS_ESTABLISHED;
4742200930Sdelphij			REASON_SET(reason, PFRES_SYNPROXY);
4743200930Sdelphij			return (PF_SYNPROXY_DROP);
4744200930Sdelphij		}
4745200930Sdelphij	}
4746200930Sdelphij
4747200930Sdelphij	if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) &&
4748200930Sdelphij	    dst->state >= TCPS_FIN_WAIT_2 &&
4749200930Sdelphij	    src->state >= TCPS_FIN_WAIT_2) {
4750223637Sbz#ifdef __FreeBSD__
4751223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC) {
4752223637Sbz#else
4753200930Sdelphij		if (pf_status.debug >= PF_DEBUG_MISC) {
4754223637Sbz#endif
4755200930Sdelphij			printf("pf: state reuse ");
4756200930Sdelphij			pf_print_state(*state);
4757200930Sdelphij			pf_print_flags(th->th_flags);
4758200930Sdelphij			printf("\n");
4759200930Sdelphij		}
4760200930Sdelphij		/* XXX make sure it's the same direction ?? */
4761200930Sdelphij		(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
4762200930Sdelphij		pf_unlink_state(*state);
4763200930Sdelphij		*state = NULL;
4764200930Sdelphij		return (PF_DROP);
4765200930Sdelphij	}
4766200930Sdelphij
4767200930Sdelphij	if ((*state)->state_flags & PFSTATE_SLOPPY) {
4768200930Sdelphij		if (pf_tcp_track_sloppy(src, dst, state, pd, reason) == PF_DROP)
4769200930Sdelphij			return (PF_DROP);
4770200930Sdelphij	} else {
4771200930Sdelphij		if (pf_tcp_track_full(src, dst, state, kif, m, off, pd, reason,
4772200930Sdelphij		    &copyback) == PF_DROP)
4773200930Sdelphij			return (PF_DROP);
4774200930Sdelphij	}
4775200930Sdelphij
4776126258Smlaier	/* translate source/destination address, if necessary */
4777223637Sbz	if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
4778223637Sbz		struct pf_state_key *nk = (*state)->key[pd->didx];
4779223637Sbz
4780223637Sbz		if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) ||
4781223637Sbz		    nk->port[pd->sidx] != th->th_sport)
4782293896Sglebius			pf_change_ap(m, pd->src, &th->th_sport,
4783293896Sglebius			    pd->ip_sum, &th->th_sum, &nk->addr[pd->sidx],
4784223637Sbz			    nk->port[pd->sidx], 0, pd->af);
4785223637Sbz
4786223637Sbz		if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) ||
4787223637Sbz		    nk->port[pd->didx] != th->th_dport)
4788293896Sglebius			pf_change_ap(m, pd->dst, &th->th_dport,
4789293896Sglebius			    pd->ip_sum, &th->th_sum, &nk->addr[pd->didx],
4790223637Sbz			    nk->port[pd->didx], 0, pd->af);
4791223637Sbz		copyback = 1;
4792126258Smlaier	}
4793126258Smlaier
4794223637Sbz	/* Copyback sequence modulation or stateful scrub changes if needed */
4795223637Sbz	if (copyback)
4796223637Sbz#ifdef __FreeBSD__
4797223637Sbz		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4798223637Sbz#else
4799223637Sbz		m_copyback(m, off, sizeof(*th), th);
4800223637Sbz#endif
4801223637Sbz
4802126258Smlaier	return (PF_PASS);
4803126258Smlaier}
4804126258Smlaier
4805126258Smlaierint
4806130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
4807130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
4808126258Smlaier{
4809126258Smlaier	struct pf_state_peer	*src, *dst;
4810223637Sbz	struct pf_state_key_cmp	 key;
4811126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
4812126258Smlaier
4813126258Smlaier	key.af = pd->af;
4814126258Smlaier	key.proto = IPPROTO_UDP;
4815223637Sbz	if (direction == PF_IN)	{	/* wire side, straight */
4816223637Sbz		PF_ACPY(&key.addr[0], pd->src, key.af);
4817223637Sbz		PF_ACPY(&key.addr[1], pd->dst, key.af);
4818223637Sbz		key.port[0] = uh->uh_sport;
4819223637Sbz		key.port[1] = uh->uh_dport;
4820223637Sbz	} else {			/* stack side, reverse */
4821223637Sbz		PF_ACPY(&key.addr[1], pd->src, key.af);
4822223637Sbz		PF_ACPY(&key.addr[0], pd->dst, key.af);
4823223637Sbz		key.port[1] = uh->uh_sport;
4824223637Sbz		key.port[0] = uh->uh_dport;
4825130613Smlaier	}
4826126258Smlaier
4827223637Sbz#ifdef __FreeBSD__
4828223637Sbz	STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
4829223637Sbz#else
4830223637Sbz	STATE_LOOKUP(kif, &key, direction, *state, m);
4831223637Sbz#endif
4832126258Smlaier
4833126258Smlaier	if (direction == (*state)->direction) {
4834126258Smlaier		src = &(*state)->src;
4835126258Smlaier		dst = &(*state)->dst;
4836126258Smlaier	} else {
4837126258Smlaier		src = &(*state)->dst;
4838126258Smlaier		dst = &(*state)->src;
4839126258Smlaier	}
4840126258Smlaier
4841126258Smlaier	/* update states */
4842126258Smlaier	if (src->state < PFUDPS_SINGLE)
4843126258Smlaier		src->state = PFUDPS_SINGLE;
4844126258Smlaier	if (dst->state == PFUDPS_SINGLE)
4845126258Smlaier		dst->state = PFUDPS_MULTIPLE;
4846126258Smlaier
4847126258Smlaier	/* update expire time */
4848126261Smlaier	(*state)->expire = time_second;
4849126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
4850126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
4851126258Smlaier	else
4852126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
4853126258Smlaier
4854126258Smlaier	/* translate source/destination address, if necessary */
4855223637Sbz	if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
4856223637Sbz		struct pf_state_key *nk = (*state)->key[pd->didx];
4857223637Sbz
4858223637Sbz		if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) ||
4859223637Sbz		    nk->port[pd->sidx] != uh->uh_sport)
4860293896Sglebius			pf_change_ap(m, pd->src, &uh->uh_sport, pd->ip_sum,
4861223637Sbz			    &uh->uh_sum, &nk->addr[pd->sidx],
4862223637Sbz			    nk->port[pd->sidx], 1, pd->af);
4863223637Sbz
4864223637Sbz		if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) ||
4865223637Sbz		    nk->port[pd->didx] != uh->uh_dport)
4866293896Sglebius			pf_change_ap(m, pd->dst, &uh->uh_dport, pd->ip_sum,
4867223637Sbz			    &uh->uh_sum, &nk->addr[pd->didx],
4868223637Sbz			    nk->port[pd->didx], 1, pd->af);
4869223637Sbz#ifdef __FreeBSD__
4870126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
4871223637Sbz#else
4872223637Sbz		m_copyback(m, off, sizeof(*uh), uh);
4873223637Sbz#endif
4874126258Smlaier	}
4875126258Smlaier
4876126258Smlaier	return (PF_PASS);
4877126258Smlaier}
4878126258Smlaier
4879126258Smlaierint
4880130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
4881145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
4882126258Smlaier{
4883223637Sbz	struct pf_addr  *saddr = pd->src, *daddr = pd->dst;
4884223637Sbz#ifdef __FreeBSD__
4885223637Sbz	u_int16_t	 icmpid = 0, *icmpsum;
4886223637Sbz#else
4887223637Sbz	u_int16_t	 icmpid, *icmpsum;
4888223637Sbz#endif
4889223637Sbz	u_int8_t	 icmptype;
4890130613Smlaier	int		 state_icmp = 0;
4891223637Sbz	struct pf_state_key_cmp key;
4892126258Smlaier
4893126258Smlaier	switch (pd->proto) {
4894126258Smlaier#ifdef INET
4895126258Smlaier	case IPPROTO_ICMP:
4896126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4897126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4898126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
4899126258Smlaier
4900126258Smlaier		if (icmptype == ICMP_UNREACH ||
4901126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4902126258Smlaier		    icmptype == ICMP_REDIRECT ||
4903126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4904126258Smlaier		    icmptype == ICMP_PARAMPROB)
4905126258Smlaier			state_icmp++;
4906126258Smlaier		break;
4907126258Smlaier#endif /* INET */
4908126258Smlaier#ifdef INET6
4909126258Smlaier	case IPPROTO_ICMPV6:
4910126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4911126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4912126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
4913126258Smlaier
4914126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4915126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4916126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4917126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4918126258Smlaier			state_icmp++;
4919126258Smlaier		break;
4920126258Smlaier#endif /* INET6 */
4921126258Smlaier	}
4922126258Smlaier
4923126258Smlaier	if (!state_icmp) {
4924126258Smlaier
4925126258Smlaier		/*
4926126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
4927126258Smlaier		 * Search for an ICMP state.
4928126258Smlaier		 */
4929126258Smlaier		key.af = pd->af;
4930126258Smlaier		key.proto = pd->proto;
4931223637Sbz		key.port[0] = key.port[1] = icmpid;
4932223637Sbz		if (direction == PF_IN)	{	/* wire side, straight */
4933223637Sbz			PF_ACPY(&key.addr[0], pd->src, key.af);
4934223637Sbz			PF_ACPY(&key.addr[1], pd->dst, key.af);
4935223637Sbz		} else {			/* stack side, reverse */
4936223637Sbz			PF_ACPY(&key.addr[1], pd->src, key.af);
4937223637Sbz			PF_ACPY(&key.addr[0], pd->dst, key.af);
4938130613Smlaier		}
4939126258Smlaier
4940223637Sbz#ifdef __FreeBSD__
4941223637Sbz		STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
4942223637Sbz#else
4943223637Sbz		STATE_LOOKUP(kif, &key, direction, *state, m);
4944223637Sbz#endif
4945126258Smlaier
4946126261Smlaier		(*state)->expire = time_second;
4947126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
4948126258Smlaier
4949126258Smlaier		/* translate source/destination address, if necessary */
4950223637Sbz		if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
4951223637Sbz			struct pf_state_key *nk = (*state)->key[pd->didx];
4952223637Sbz
4953223637Sbz			switch (pd->af) {
4954126258Smlaier#ifdef INET
4955223637Sbz			case AF_INET:
4956223637Sbz				if (PF_ANEQ(pd->src,
4957223637Sbz				    &nk->addr[pd->sidx], AF_INET))
4958126258Smlaier					pf_change_a(&saddr->v4.s_addr,
4959126258Smlaier					    pd->ip_sum,
4960223637Sbz					    nk->addr[pd->sidx].v4.s_addr, 0);
4961223637Sbz
4962223637Sbz				if (PF_ANEQ(pd->dst, &nk->addr[pd->didx],
4963223637Sbz				    AF_INET))
4964223637Sbz					pf_change_a(&daddr->v4.s_addr,
4965223637Sbz					    pd->ip_sum,
4966223637Sbz					    nk->addr[pd->didx].v4.s_addr, 0);
4967223637Sbz
4968223637Sbz				if (nk->port[0] !=
4969223637Sbz				    pd->hdr.icmp->icmp_id) {
4970149884Smlaier					pd->hdr.icmp->icmp_cksum =
4971149884Smlaier					    pf_cksum_fixup(
4972149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
4973223637Sbz					    nk->port[pd->sidx], 0);
4974149884Smlaier					pd->hdr.icmp->icmp_id =
4975223637Sbz					    nk->port[pd->sidx];
4976223637Sbz				}
4977223637Sbz
4978223637Sbz				m_copyback(m, off, ICMP_MINLEN,
4979223637Sbz#ifdef __FreeBSD__
4980223637Sbz				    (caddr_t)
4981223637Sbz#endif
4982223637Sbz				    pd->hdr.icmp);
4983223637Sbz				break;
4984126258Smlaier#endif /* INET */
4985126258Smlaier#ifdef INET6
4986223637Sbz			case AF_INET6:
4987223637Sbz				if (PF_ANEQ(pd->src,
4988223637Sbz				    &nk->addr[pd->sidx], AF_INET6))
4989126258Smlaier					pf_change_a6(saddr,
4990126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4991223637Sbz					    &nk->addr[pd->sidx], 0);
4992223637Sbz
4993223637Sbz				if (PF_ANEQ(pd->dst,
4994223637Sbz				    &nk->addr[pd->didx], AF_INET6))
4995126258Smlaier					pf_change_a6(daddr,
4996126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4997223637Sbz					    &nk->addr[pd->didx], 0);
4998223637Sbz
4999223637Sbz				m_copyback(m, off,
5000223637Sbz				    sizeof(struct icmp6_hdr),
5001223637Sbz#ifdef __FreeBSD__
5002223637Sbz				    (caddr_t)
5003223637Sbz#endif
5004223637Sbz				    pd->hdr.icmp6);
5005223637Sbz				break;
5006126258Smlaier#endif /* INET6 */
5007126258Smlaier			}
5008126258Smlaier		}
5009126258Smlaier		return (PF_PASS);
5010126258Smlaier
5011126258Smlaier	} else {
5012126258Smlaier		/*
5013126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
5014126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
5015126258Smlaier		 */
5016126258Smlaier
5017126258Smlaier		struct pf_pdesc	pd2;
5018223637Sbz#ifdef __FreeBSD__
5019223637Sbz		bzero(&pd2, sizeof pd2);
5020223637Sbz#endif
5021126258Smlaier#ifdef INET
5022126258Smlaier		struct ip	h2;
5023126258Smlaier#endif /* INET */
5024126258Smlaier#ifdef INET6
5025126258Smlaier		struct ip6_hdr	h2_6;
5026126258Smlaier		int		terminal = 0;
5027126258Smlaier#endif /* INET6 */
5028223637Sbz#ifdef __FreeBSD__
5029223637Sbz		int		ipoff2 = 0;
5030223637Sbz		int		off2 = 0;
5031223637Sbz#else
5032223637Sbz		int		ipoff2;
5033223637Sbz		int		off2;
5034223637Sbz#endif
5035126258Smlaier
5036126258Smlaier		pd2.af = pd->af;
5037223637Sbz		/* Payload packet is from the opposite direction. */
5038223637Sbz		pd2.sidx = (direction == PF_IN) ? 1 : 0;
5039223637Sbz		pd2.didx = (direction == PF_IN) ? 0 : 1;
5040126258Smlaier		switch (pd->af) {
5041126258Smlaier#ifdef INET
5042126258Smlaier		case AF_INET:
5043126258Smlaier			/* offset of h2 in mbuf chain */
5044126258Smlaier			ipoff2 = off + ICMP_MINLEN;
5045126258Smlaier
5046126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
5047145836Smlaier			    NULL, reason, pd2.af)) {
5048126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5049126258Smlaier				    ("pf: ICMP error message too short "
5050126258Smlaier				    "(ip)\n"));
5051126258Smlaier				return (PF_DROP);
5052126258Smlaier			}
5053126258Smlaier			/*
5054126258Smlaier			 * ICMP error messages don't refer to non-first
5055126258Smlaier			 * fragments
5056126258Smlaier			 */
5057145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
5058145836Smlaier				REASON_SET(reason, PFRES_FRAG);
5059126258Smlaier				return (PF_DROP);
5060145836Smlaier			}
5061126258Smlaier
5062126258Smlaier			/* offset of protocol header that follows h2 */
5063126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
5064126258Smlaier
5065126258Smlaier			pd2.proto = h2.ip_p;
5066126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
5067126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
5068126258Smlaier			pd2.ip_sum = &h2.ip_sum;
5069126258Smlaier			break;
5070126258Smlaier#endif /* INET */
5071126258Smlaier#ifdef INET6
5072126258Smlaier		case AF_INET6:
5073126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
5074126258Smlaier
5075126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
5076145836Smlaier			    NULL, reason, pd2.af)) {
5077126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5078126258Smlaier				    ("pf: ICMP error message too short "
5079126258Smlaier				    "(ip6)\n"));
5080126258Smlaier				return (PF_DROP);
5081126258Smlaier			}
5082126258Smlaier			pd2.proto = h2_6.ip6_nxt;
5083126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
5084126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
5085126258Smlaier			pd2.ip_sum = NULL;
5086126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
5087126258Smlaier			do {
5088126258Smlaier				switch (pd2.proto) {
5089126258Smlaier				case IPPROTO_FRAGMENT:
5090126258Smlaier					/*
5091126258Smlaier					 * ICMPv6 error messages for
5092126258Smlaier					 * non-first fragments
5093126258Smlaier					 */
5094145836Smlaier					REASON_SET(reason, PFRES_FRAG);
5095126258Smlaier					return (PF_DROP);
5096126258Smlaier				case IPPROTO_AH:
5097126258Smlaier				case IPPROTO_HOPOPTS:
5098126258Smlaier				case IPPROTO_ROUTING:
5099126258Smlaier				case IPPROTO_DSTOPTS: {
5100126258Smlaier					/* get next header and header length */
5101126258Smlaier					struct ip6_ext opt6;
5102126258Smlaier
5103126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
5104145836Smlaier					    sizeof(opt6), NULL, reason,
5105145836Smlaier					    pd2.af)) {
5106126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
5107126258Smlaier						    ("pf: ICMPv6 short opt\n"));
5108126258Smlaier						return (PF_DROP);
5109126258Smlaier					}
5110126258Smlaier					if (pd2.proto == IPPROTO_AH)
5111126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
5112126258Smlaier					else
5113126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
5114126258Smlaier					pd2.proto = opt6.ip6e_nxt;
5115126258Smlaier					/* goto the next header */
5116126258Smlaier					break;
5117126258Smlaier				}
5118126258Smlaier				default:
5119126258Smlaier					terminal++;
5120126258Smlaier					break;
5121126258Smlaier				}
5122126258Smlaier			} while (!terminal);
5123126258Smlaier			break;
5124126258Smlaier#endif /* INET6 */
5125126258Smlaier		}
5126126258Smlaier
5127126258Smlaier		switch (pd2.proto) {
5128126258Smlaier		case IPPROTO_TCP: {
5129126258Smlaier			struct tcphdr		 th;
5130126258Smlaier			u_int32_t		 seq;
5131126258Smlaier			struct pf_state_peer	*src, *dst;
5132126258Smlaier			u_int8_t		 dws;
5133128129Smlaier			int			 copyback = 0;
5134126258Smlaier
5135126258Smlaier			/*
5136126258Smlaier			 * Only the first 8 bytes of the TCP header can be
5137126258Smlaier			 * expected. Don't access any TCP header fields after
5138126258Smlaier			 * th_seq, an ackskew test is not possible.
5139126258Smlaier			 */
5140145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
5141145836Smlaier			    pd2.af)) {
5142126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5143126258Smlaier				    ("pf: ICMP error message too short "
5144126258Smlaier				    "(tcp)\n"));
5145126258Smlaier				return (PF_DROP);
5146126258Smlaier			}
5147126258Smlaier
5148126258Smlaier			key.af = pd2.af;
5149126258Smlaier			key.proto = IPPROTO_TCP;
5150223637Sbz			PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
5151223637Sbz			PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
5152223637Sbz			key.port[pd2.sidx] = th.th_sport;
5153223637Sbz			key.port[pd2.didx] = th.th_dport;
5154126258Smlaier
5155223637Sbz#ifdef __FreeBSD__
5156223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
5157223637Sbz#else
5158223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m);
5159223637Sbz#endif
5160126258Smlaier
5161126258Smlaier			if (direction == (*state)->direction) {
5162126258Smlaier				src = &(*state)->dst;
5163126258Smlaier				dst = &(*state)->src;
5164126258Smlaier			} else {
5165126258Smlaier				src = &(*state)->src;
5166126258Smlaier				dst = &(*state)->dst;
5167126258Smlaier			}
5168126258Smlaier
5169171929Sdhartmei			if (src->wscale && dst->wscale)
5170126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5171126258Smlaier			else
5172126258Smlaier				dws = 0;
5173126258Smlaier
5174126258Smlaier			/* Demodulate sequence number */
5175126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5176128129Smlaier			if (src->seqdiff) {
5177128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5178126258Smlaier				    htonl(seq), 0);
5179128129Smlaier				copyback = 1;
5180128129Smlaier			}
5181126258Smlaier
5182200930Sdelphij			if (!((*state)->state_flags & PFSTATE_SLOPPY) &&
5183200930Sdelphij			    (!SEQ_GEQ(src->seqhi, seq) ||
5184200930Sdelphij			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) {
5185223637Sbz#ifdef __FreeBSD__
5186223637Sbz				if (V_pf_status.debug >= PF_DEBUG_MISC) {
5187223637Sbz#else
5188126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5189223637Sbz#endif
5190126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5191126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5192126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5193126258Smlaier					printf(" -> ");
5194126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5195126258Smlaier					printf(" state: ");
5196126258Smlaier					pf_print_state(*state);
5197126258Smlaier					printf(" seq=%u\n", seq);
5198126258Smlaier				}
5199145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5200126258Smlaier				return (PF_DROP);
5201223637Sbz			} else {
5202223637Sbz#ifdef __FreeBSD__
5203223637Sbz				if (V_pf_status.debug >= PF_DEBUG_MISC) {
5204223637Sbz#else
5205223637Sbz				if (pf_status.debug >= PF_DEBUG_MISC) {
5206223637Sbz#endif
5207223637Sbz					printf("pf: OK ICMP %d:%d ",
5208223637Sbz					    icmptype, pd->hdr.icmp->icmp_code);
5209223637Sbz					pf_print_host(pd->src, 0, pd->af);
5210223637Sbz					printf(" -> ");
5211223637Sbz					pf_print_host(pd->dst, 0, pd->af);
5212223637Sbz					printf(" state: ");
5213223637Sbz					pf_print_state(*state);
5214223637Sbz					printf(" seq=%u\n", seq);
5215223637Sbz				}
5216126258Smlaier			}
5217126258Smlaier
5218223637Sbz			/* translate source/destination address, if necessary */
5219223637Sbz			if ((*state)->key[PF_SK_WIRE] !=
5220223637Sbz			    (*state)->key[PF_SK_STACK]) {
5221223637Sbz				struct pf_state_key *nk =
5222223637Sbz				    (*state)->key[pd->didx];
5223223637Sbz
5224223637Sbz				if (PF_ANEQ(pd2.src,
5225223637Sbz				    &nk->addr[pd2.sidx], pd2.af) ||
5226223637Sbz				    nk->port[pd2.sidx] != th.th_sport)
5227126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5228223637Sbz					    daddr, &nk->addr[pd2.sidx],
5229223637Sbz					    nk->port[pd2.sidx], NULL,
5230126258Smlaier					    pd2.ip_sum, icmpsum,
5231126258Smlaier					    pd->ip_sum, 0, pd2.af);
5232223637Sbz
5233223637Sbz				if (PF_ANEQ(pd2.dst,
5234223637Sbz				    &nk->addr[pd2.didx], pd2.af) ||
5235223637Sbz				    nk->port[pd2.didx] != th.th_dport)
5236126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5237223637Sbz					    NULL, /* XXX Inbound NAT? */
5238223637Sbz					    &nk->addr[pd2.didx],
5239223637Sbz					    nk->port[pd2.didx], NULL,
5240126258Smlaier					    pd2.ip_sum, icmpsum,
5241126258Smlaier					    pd->ip_sum, 0, pd2.af);
5242128129Smlaier				copyback = 1;
5243128129Smlaier			}
5244128129Smlaier
5245128129Smlaier			if (copyback) {
5246126258Smlaier				switch (pd2.af) {
5247126258Smlaier#ifdef INET
5248126258Smlaier				case AF_INET:
5249126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5250223637Sbz#ifdef __FreeBSD__
5251223637Sbz					    (caddr_t)
5252223637Sbz#endif
5253223637Sbz					    pd->hdr.icmp);
5254126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5255223637Sbz#ifdef __FreeBSD__
5256223637Sbz					    (caddr_t)
5257223637Sbz#endif
5258223637Sbz					    &h2);
5259126258Smlaier					break;
5260126258Smlaier#endif /* INET */
5261126258Smlaier#ifdef INET6
5262126258Smlaier				case AF_INET6:
5263126258Smlaier					m_copyback(m, off,
5264126258Smlaier					    sizeof(struct icmp6_hdr),
5265223637Sbz#ifdef __FreeBSD__
5266223637Sbz					    (caddr_t)
5267223637Sbz#endif
5268223637Sbz					    pd->hdr.icmp6);
5269126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5270223637Sbz#ifdef __FreeBSD__
5271223637Sbz					    (caddr_t)
5272223637Sbz#endif
5273223637Sbz					    &h2_6);
5274126258Smlaier					break;
5275126258Smlaier#endif /* INET6 */
5276126258Smlaier				}
5277223637Sbz#ifdef __FreeBSD__
5278126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5279223637Sbz#else
5280223637Sbz				m_copyback(m, off2, 8, &th);
5281223637Sbz#endif
5282126258Smlaier			}
5283126258Smlaier
5284126258Smlaier			return (PF_PASS);
5285126258Smlaier			break;
5286126258Smlaier		}
5287126258Smlaier		case IPPROTO_UDP: {
5288126258Smlaier			struct udphdr		uh;
5289126258Smlaier
5290126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5291145836Smlaier			    NULL, reason, pd2.af)) {
5292126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5293126258Smlaier				    ("pf: ICMP error message too short "
5294126258Smlaier				    "(udp)\n"));
5295126258Smlaier				return (PF_DROP);
5296126258Smlaier			}
5297126258Smlaier
5298126258Smlaier			key.af = pd2.af;
5299126258Smlaier			key.proto = IPPROTO_UDP;
5300223637Sbz			PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
5301223637Sbz			PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
5302223637Sbz			key.port[pd2.sidx] = uh.uh_sport;
5303223637Sbz			key.port[pd2.didx] = uh.uh_dport;
5304126258Smlaier
5305223637Sbz#ifdef __FreeBSD__
5306223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
5307223637Sbz#else
5308223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m);
5309223637Sbz#endif
5310126258Smlaier
5311223637Sbz			/* translate source/destination address, if necessary */
5312223637Sbz			if ((*state)->key[PF_SK_WIRE] !=
5313223637Sbz			    (*state)->key[PF_SK_STACK]) {
5314223637Sbz				struct pf_state_key *nk =
5315223637Sbz				    (*state)->key[pd->didx];
5316223637Sbz
5317223637Sbz				if (PF_ANEQ(pd2.src,
5318223637Sbz				    &nk->addr[pd2.sidx], pd2.af) ||
5319223637Sbz				    nk->port[pd2.sidx] != uh.uh_sport)
5320126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5321223637Sbz					    daddr, &nk->addr[pd2.sidx],
5322223637Sbz					    nk->port[pd2.sidx], &uh.uh_sum,
5323126258Smlaier					    pd2.ip_sum, icmpsum,
5324126258Smlaier					    pd->ip_sum, 1, pd2.af);
5325223637Sbz
5326223637Sbz				if (PF_ANEQ(pd2.dst,
5327223637Sbz				    &nk->addr[pd2.didx], pd2.af) ||
5328223637Sbz				    nk->port[pd2.didx] != uh.uh_dport)
5329126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5330223637Sbz					    NULL, /* XXX Inbound NAT? */
5331223637Sbz					    &nk->addr[pd2.didx],
5332223637Sbz					    nk->port[pd2.didx], &uh.uh_sum,
5333126258Smlaier					    pd2.ip_sum, icmpsum,
5334126258Smlaier					    pd->ip_sum, 1, pd2.af);
5335223637Sbz
5336126258Smlaier				switch (pd2.af) {
5337126258Smlaier#ifdef INET
5338126258Smlaier				case AF_INET:
5339126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5340223637Sbz#ifdef __FreeBSD__
5341223637Sbz					    (caddr_t)
5342223637Sbz#endif
5343223637Sbz					    pd->hdr.icmp);
5344223637Sbz#ifdef __FreeBSD__
5345223637Sbz					m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
5346223637Sbz#else
5347223637Sbz					m_copyback(m, ipoff2, sizeof(h2), &h2);
5348223637Sbz#endif
5349126258Smlaier					break;
5350126258Smlaier#endif /* INET */
5351126258Smlaier#ifdef INET6
5352126258Smlaier				case AF_INET6:
5353126258Smlaier					m_copyback(m, off,
5354126258Smlaier					    sizeof(struct icmp6_hdr),
5355223637Sbz#ifdef __FreeBSD__
5356223637Sbz					    (caddr_t)
5357223637Sbz#endif
5358223637Sbz					    pd->hdr.icmp6);
5359126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5360223637Sbz#ifdef __FreeBSD__
5361223637Sbz					    (caddr_t)
5362223637Sbz#endif
5363223637Sbz					    &h2_6);
5364126258Smlaier					break;
5365126258Smlaier#endif /* INET6 */
5366126258Smlaier				}
5367223637Sbz#ifdef __FreeBSD__
5368223637Sbz				m_copyback(m, off2, sizeof(uh), (caddr_t)&uh);
5369223637Sbz#else
5370223637Sbz				m_copyback(m, off2, sizeof(uh), &uh);
5371223637Sbz#endif
5372126258Smlaier			}
5373126258Smlaier			return (PF_PASS);
5374126258Smlaier			break;
5375126258Smlaier		}
5376126258Smlaier#ifdef INET
5377126258Smlaier		case IPPROTO_ICMP: {
5378126258Smlaier			struct icmp		iih;
5379126258Smlaier
5380126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5381145836Smlaier			    NULL, reason, pd2.af)) {
5382126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5383126258Smlaier				    ("pf: ICMP error message too short i"
5384126258Smlaier				    "(icmp)\n"));
5385126258Smlaier				return (PF_DROP);
5386126258Smlaier			}
5387126258Smlaier
5388126258Smlaier			key.af = pd2.af;
5389126258Smlaier			key.proto = IPPROTO_ICMP;
5390223637Sbz			PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
5391223637Sbz			PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
5392223637Sbz			key.port[0] = key.port[1] = iih.icmp_id;
5393126258Smlaier
5394223637Sbz#ifdef __FreeBSD__
5395223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
5396223637Sbz#else
5397223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m);
5398223637Sbz#endif
5399126258Smlaier
5400223637Sbz			/* translate source/destination address, if necessary */
5401223637Sbz			if ((*state)->key[PF_SK_WIRE] !=
5402223637Sbz			    (*state)->key[PF_SK_STACK]) {
5403223637Sbz				struct pf_state_key *nk =
5404223637Sbz				    (*state)->key[pd->didx];
5405223637Sbz
5406223637Sbz				if (PF_ANEQ(pd2.src,
5407223637Sbz				    &nk->addr[pd2.sidx], pd2.af) ||
5408223637Sbz				    nk->port[pd2.sidx] != iih.icmp_id)
5409126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5410223637Sbz					    daddr, &nk->addr[pd2.sidx],
5411223637Sbz					    nk->port[pd2.sidx], NULL,
5412126258Smlaier					    pd2.ip_sum, icmpsum,
5413126258Smlaier					    pd->ip_sum, 0, AF_INET);
5414223637Sbz
5415223637Sbz				if (PF_ANEQ(pd2.dst,
5416223637Sbz				    &nk->addr[pd2.didx], pd2.af) ||
5417223637Sbz				    nk->port[pd2.didx] != iih.icmp_id)
5418126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5419223637Sbz					    NULL, /* XXX Inbound NAT? */
5420223637Sbz					    &nk->addr[pd2.didx],
5421223637Sbz					    nk->port[pd2.didx], NULL,
5422126258Smlaier					    pd2.ip_sum, icmpsum,
5423126258Smlaier					    pd->ip_sum, 0, AF_INET);
5424223637Sbz
5425223637Sbz#ifdef __FreeBSD__
5426223637Sbz				m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp);
5427223637Sbz				m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
5428223637Sbz				m_copyback(m, off2, ICMP_MINLEN, (caddr_t)&iih);
5429223637Sbz#else
5430223637Sbz				m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
5431223637Sbz				m_copyback(m, ipoff2, sizeof(h2), &h2);
5432223637Sbz				m_copyback(m, off2, ICMP_MINLEN, &iih);
5433223637Sbz#endif
5434126258Smlaier			}
5435126258Smlaier			return (PF_PASS);
5436126258Smlaier			break;
5437126258Smlaier		}
5438126258Smlaier#endif /* INET */
5439126258Smlaier#ifdef INET6
5440126258Smlaier		case IPPROTO_ICMPV6: {
5441126258Smlaier			struct icmp6_hdr	iih;
5442126258Smlaier
5443126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5444145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5445126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5446126258Smlaier				    ("pf: ICMP error message too short "
5447126258Smlaier				    "(icmp6)\n"));
5448126258Smlaier				return (PF_DROP);
5449126258Smlaier			}
5450126258Smlaier
5451126258Smlaier			key.af = pd2.af;
5452126258Smlaier			key.proto = IPPROTO_ICMPV6;
5453223637Sbz			PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
5454223637Sbz			PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
5455223637Sbz			key.port[0] = key.port[1] = iih.icmp6_id;
5456126258Smlaier
5457223637Sbz#ifdef __FreeBSD__
5458223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
5459223637Sbz#else
5460223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m);
5461223637Sbz#endif
5462126258Smlaier
5463223637Sbz			/* translate source/destination address, if necessary */
5464223637Sbz			if ((*state)->key[PF_SK_WIRE] !=
5465223637Sbz			    (*state)->key[PF_SK_STACK]) {
5466223637Sbz				struct pf_state_key *nk =
5467223637Sbz				    (*state)->key[pd->didx];
5468223637Sbz
5469223637Sbz				if (PF_ANEQ(pd2.src,
5470223637Sbz				    &nk->addr[pd2.sidx], pd2.af) ||
5471223637Sbz				    nk->port[pd2.sidx] != iih.icmp6_id)
5472126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5473223637Sbz					    daddr, &nk->addr[pd2.sidx],
5474223637Sbz					    nk->port[pd2.sidx], NULL,
5475126258Smlaier					    pd2.ip_sum, icmpsum,
5476126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5477223637Sbz
5478223637Sbz				if (PF_ANEQ(pd2.dst,
5479223637Sbz				    &nk->addr[pd2.didx], pd2.af) ||
5480223637Sbz				    nk->port[pd2.didx] != iih.icmp6_id)
5481126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5482223637Sbz					    NULL, /* XXX Inbound NAT? */
5483223637Sbz					    &nk->addr[pd2.didx],
5484223637Sbz					    nk->port[pd2.didx], NULL,
5485126258Smlaier					    pd2.ip_sum, icmpsum,
5486126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5487223637Sbz
5488223637Sbz#ifdef __FreeBSD__
5489126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5490126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5491223637Sbz				m_copyback(m, ipoff2, sizeof(h2_6), (caddr_t)&h2_6);
5492126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5493126261Smlaier				    (caddr_t)&iih);
5494223637Sbz#else
5495223637Sbz				m_copyback(m, off, sizeof(struct icmp6_hdr),
5496223637Sbz				    pd->hdr.icmp6);
5497223637Sbz				m_copyback(m, ipoff2, sizeof(h2_6), &h2_6);
5498223637Sbz				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5499223637Sbz				    &iih);
5500223637Sbz#endif
5501126258Smlaier			}
5502126258Smlaier			return (PF_PASS);
5503126258Smlaier			break;
5504126258Smlaier		}
5505126258Smlaier#endif /* INET6 */
5506126258Smlaier		default: {
5507126258Smlaier			key.af = pd2.af;
5508126258Smlaier			key.proto = pd2.proto;
5509223637Sbz			PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
5510223637Sbz			PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
5511223637Sbz			key.port[0] = key.port[1] = 0;
5512126258Smlaier
5513223637Sbz#ifdef __FreeBSD__
5514223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
5515223637Sbz#else
5516223637Sbz			STATE_LOOKUP(kif, &key, direction, *state, m);
5517223637Sbz#endif
5518126258Smlaier
5519223637Sbz			/* translate source/destination address, if necessary */
5520223637Sbz			if ((*state)->key[PF_SK_WIRE] !=
5521223637Sbz			    (*state)->key[PF_SK_STACK]) {
5522223637Sbz				struct pf_state_key *nk =
5523223637Sbz				    (*state)->key[pd->didx];
5524223637Sbz
5525223637Sbz				if (PF_ANEQ(pd2.src,
5526223637Sbz				    &nk->addr[pd2.sidx], pd2.af))
5527223637Sbz					pf_change_icmp(pd2.src, NULL, daddr,
5528223637Sbz					    &nk->addr[pd2.sidx], 0, NULL,
5529126258Smlaier					    pd2.ip_sum, icmpsum,
5530126258Smlaier					    pd->ip_sum, 0, pd2.af);
5531223637Sbz
5532223637Sbz				if (PF_ANEQ(pd2.dst,
5533223637Sbz				    &nk->addr[pd2.didx], pd2.af))
5534223637Sbz					pf_change_icmp(pd2.src, NULL,
5535223637Sbz					    NULL, /* XXX Inbound NAT? */
5536223637Sbz					    &nk->addr[pd2.didx], 0, NULL,
5537126258Smlaier					    pd2.ip_sum, icmpsum,
5538126258Smlaier					    pd->ip_sum, 0, pd2.af);
5539223637Sbz
5540126258Smlaier				switch (pd2.af) {
5541126258Smlaier#ifdef INET
5542126258Smlaier				case AF_INET:
5543223637Sbz#ifdef __FreeBSD__
5544126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5545126261Smlaier					    (caddr_t)pd->hdr.icmp);
5546223637Sbz					m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
5547223637Sbz#else
5548223637Sbz					m_copyback(m, off, ICMP_MINLEN,
5549223637Sbz					    pd->hdr.icmp);
5550223637Sbz					m_copyback(m, ipoff2, sizeof(h2), &h2);
5551223637Sbz#endif
5552126258Smlaier					break;
5553126258Smlaier#endif /* INET */
5554126258Smlaier#ifdef INET6
5555126258Smlaier				case AF_INET6:
5556126258Smlaier					m_copyback(m, off,
5557126258Smlaier					    sizeof(struct icmp6_hdr),
5558223637Sbz#ifdef __FreeBSD__
5559223637Sbz					    (caddr_t)
5560223637Sbz#endif
5561223637Sbz					    pd->hdr.icmp6);
5562126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5563223637Sbz#ifdef __FreeBSD__
5564223637Sbz					    (caddr_t)
5565223637Sbz#endif
5566223637Sbz					    &h2_6);
5567126258Smlaier					break;
5568126258Smlaier#endif /* INET6 */
5569126258Smlaier				}
5570126258Smlaier			}
5571126258Smlaier			return (PF_PASS);
5572126258Smlaier			break;
5573126258Smlaier		}
5574126258Smlaier		}
5575126258Smlaier	}
5576126258Smlaier}
5577126258Smlaier
5578126258Smlaierint
5579130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5580223637Sbz    struct mbuf *m, struct pf_pdesc *pd)
5581126258Smlaier{
5582126258Smlaier	struct pf_state_peer	*src, *dst;
5583223637Sbz	struct pf_state_key_cmp	 key;
5584126258Smlaier
5585126258Smlaier	key.af = pd->af;
5586126258Smlaier	key.proto = pd->proto;
5587130613Smlaier	if (direction == PF_IN)	{
5588223637Sbz		PF_ACPY(&key.addr[0], pd->src, key.af);
5589223637Sbz		PF_ACPY(&key.addr[1], pd->dst, key.af);
5590223637Sbz		key.port[0] = key.port[1] = 0;
5591130613Smlaier	} else {
5592223637Sbz		PF_ACPY(&key.addr[1], pd->src, key.af);
5593223637Sbz		PF_ACPY(&key.addr[0], pd->dst, key.af);
5594223637Sbz		key.port[1] = key.port[0] = 0;
5595130613Smlaier	}
5596126258Smlaier
5597223637Sbz#ifdef __FreeBSD__
5598223637Sbz	STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag);
5599223637Sbz#else
5600223637Sbz	STATE_LOOKUP(kif, &key, direction, *state, m);
5601223637Sbz#endif
5602126258Smlaier
5603126258Smlaier	if (direction == (*state)->direction) {
5604126258Smlaier		src = &(*state)->src;
5605126258Smlaier		dst = &(*state)->dst;
5606126258Smlaier	} else {
5607126258Smlaier		src = &(*state)->dst;
5608126258Smlaier		dst = &(*state)->src;
5609126258Smlaier	}
5610126258Smlaier
5611126258Smlaier	/* update states */
5612126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5613126258Smlaier		src->state = PFOTHERS_SINGLE;
5614126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5615126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5616126258Smlaier
5617126258Smlaier	/* update expire time */
5618126261Smlaier	(*state)->expire = time_second;
5619126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5620126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5621126258Smlaier	else
5622126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5623126258Smlaier
5624126258Smlaier	/* translate source/destination address, if necessary */
5625223637Sbz	if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
5626223637Sbz		struct pf_state_key *nk = (*state)->key[pd->didx];
5627223637Sbz
5628223637Sbz#ifdef __FreeBSD__
5629223637Sbz		KASSERT(nk, ("%s: nk is null", __FUNCTION__));
5630223637Sbz		KASSERT(pd, ("%s: pd is null", __FUNCTION__));
5631223637Sbz		KASSERT(pd->src, ("%s: pd->src is null", __FUNCTION__));
5632223637Sbz		KASSERT(pd->dst, ("%s: pd->dst is null", __FUNCTION__));
5633223637Sbz#else
5634223637Sbz		KASSERT(nk);
5635223637Sbz		KASSERT(pd);
5636223637Sbz		KASSERT(pd->src);
5637223637Sbz		KASSERT(pd->dst);
5638223637Sbz#endif
5639223637Sbz		switch (pd->af) {
5640126258Smlaier#ifdef INET
5641223637Sbz		case AF_INET:
5642223637Sbz			if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET))
5643126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5644223637Sbz				    pd->ip_sum,
5645223637Sbz				    nk->addr[pd->sidx].v4.s_addr,
5646126258Smlaier				    0);
5647223637Sbz
5648223637Sbz
5649223637Sbz			if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET))
5650126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5651223637Sbz				    pd->ip_sum,
5652223637Sbz				    nk->addr[pd->didx].v4.s_addr,
5653126258Smlaier				    0);
5654223637Sbz
5655126258Smlaier				break;
5656126258Smlaier#endif /* INET */
5657126258Smlaier#ifdef INET6
5658223637Sbz		case AF_INET6:
5659223637Sbz			if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET))
5660223637Sbz				PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
5661223637Sbz
5662223637Sbz			if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET))
5663223637Sbz				PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
5664126258Smlaier#endif /* INET6 */
5665223637Sbz		}
5666126258Smlaier	}
5667126258Smlaier	return (PF_PASS);
5668126258Smlaier}
5669126258Smlaier
5670126258Smlaier/*
5671126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5672126258Smlaier * h must be at "ipoff" on the mbuf chain.
5673126258Smlaier */
5674126258Smlaiervoid *
5675126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5676126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5677126258Smlaier{
5678126258Smlaier	switch (af) {
5679126258Smlaier#ifdef INET
5680126258Smlaier	case AF_INET: {
5681126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5682126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5683126258Smlaier
5684126258Smlaier		if (fragoff) {
5685126258Smlaier			if (fragoff >= len)
5686126258Smlaier				ACTION_SET(actionp, PF_PASS);
5687126258Smlaier			else {
5688126258Smlaier				ACTION_SET(actionp, PF_DROP);
5689126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5690126258Smlaier			}
5691126258Smlaier			return (NULL);
5692126258Smlaier		}
5693130613Smlaier		if (m->m_pkthdr.len < off + len ||
5694130613Smlaier		    ntohs(h->ip_len) < off + len) {
5695126258Smlaier			ACTION_SET(actionp, PF_DROP);
5696126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5697126258Smlaier			return (NULL);
5698126258Smlaier		}
5699126258Smlaier		break;
5700126258Smlaier	}
5701126258Smlaier#endif /* INET */
5702126258Smlaier#ifdef INET6
5703126258Smlaier	case AF_INET6: {
5704126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5705126258Smlaier
5706126258Smlaier		if (m->m_pkthdr.len < off + len ||
5707126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5708126258Smlaier		    (unsigned)(off + len)) {
5709126258Smlaier			ACTION_SET(actionp, PF_DROP);
5710126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5711126258Smlaier			return (NULL);
5712126258Smlaier		}
5713126258Smlaier		break;
5714126258Smlaier	}
5715126258Smlaier#endif /* INET6 */
5716126258Smlaier	}
5717126258Smlaier	m_copydata(m, off, len, p);
5718126258Smlaier	return (p);
5719126258Smlaier}
5720126258Smlaier
5721126258Smlaierint
5722232292Sbzpf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif,
5723232292Sbz    int rtableid)
5724126258Smlaier{
5725223637Sbz#ifdef __FreeBSD__
5726223637Sbz#ifdef RADIX_MPATH
5727223637Sbz	struct radix_node_head	*rnh;
5728223637Sbz#endif
5729223637Sbz#endif
5730126258Smlaier	struct sockaddr_in	*dst;
5731171168Smlaier	int			 ret = 1;
5732171168Smlaier	int			 check_mpath;
5733171168Smlaier#ifndef __FreeBSD__
5734171168Smlaier	extern int		 ipmultipath;
5735171168Smlaier#endif
5736145836Smlaier#ifdef INET6
5737171168Smlaier#ifndef __FreeBSD__
5738171168Smlaier	extern int		 ip6_multipath;
5739171168Smlaier#endif
5740145836Smlaier	struct sockaddr_in6	*dst6;
5741145836Smlaier	struct route_in6	 ro;
5742145836Smlaier#else
5743126258Smlaier	struct route		 ro;
5744145836Smlaier#endif
5745171168Smlaier	struct radix_node	*rn;
5746171168Smlaier	struct rtentry		*rt;
5747171168Smlaier	struct ifnet		*ifp;
5748126258Smlaier
5749171168Smlaier	check_mpath = 0;
5750223637Sbz#ifdef __FreeBSD__
5751223637Sbz#ifdef RADIX_MPATH
5752223637Sbz	/* XXX: stick to table 0 for now */
5753223637Sbz	rnh = rt_tables_get_rnh(0, af);
5754223637Sbz	if (rnh != NULL && rn_mpath_capable(rnh))
5755223637Sbz		check_mpath = 1;
5756223637Sbz#endif
5757223637Sbz#endif
5758126258Smlaier	bzero(&ro, sizeof(ro));
5759145836Smlaier	switch (af) {
5760145836Smlaier	case AF_INET:
5761145836Smlaier		dst = satosin(&ro.ro_dst);
5762145836Smlaier		dst->sin_family = AF_INET;
5763145836Smlaier		dst->sin_len = sizeof(*dst);
5764145836Smlaier		dst->sin_addr = addr->v4;
5765223637Sbz#ifndef __FreeBSD__
5766171168Smlaier		if (ipmultipath)
5767171168Smlaier			check_mpath = 1;
5768171168Smlaier#endif
5769145836Smlaier		break;
5770145836Smlaier#ifdef INET6
5771145836Smlaier	case AF_INET6:
5772223637Sbz		/*
5773223637Sbz		 * Skip check for addresses with embedded interface scope,
5774223637Sbz		 * as they would always match anyway.
5775223637Sbz		 */
5776223637Sbz		if (IN6_IS_SCOPE_EMBED(&addr->v6))
5777223637Sbz			goto out;
5778145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5779145836Smlaier		dst6->sin6_family = AF_INET6;
5780145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5781145836Smlaier		dst6->sin6_addr = addr->v6;
5782223637Sbz#ifndef __FreeBSD__
5783171168Smlaier		if (ip6_multipath)
5784171168Smlaier			check_mpath = 1;
5785171168Smlaier#endif
5786145836Smlaier		break;
5787145836Smlaier#endif /* INET6 */
5788145836Smlaier	default:
5789145836Smlaier		return (0);
5790145836Smlaier	}
5791145836Smlaier
5792171168Smlaier	/* Skip checks for ipsec interfaces */
5793171168Smlaier	if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
5794171168Smlaier		goto out;
5795171168Smlaier
5796127145Smlaier#ifdef __FreeBSD__
5797232292Sbz	switch (af) {
5798232292Sbz#ifdef INET6
5799232292Sbz	case AF_INET6:
5800232292Sbz		in6_rtalloc_ign(&ro, 0, rtableid);
5801232292Sbz		break;
5802232292Sbz#endif
5803222529Sbz#ifdef INET
5804232292Sbz	case AF_INET:
5805232292Sbz		in_rtalloc_ign((struct route *)&ro, 0, rtableid);
5806232292Sbz		break;
5807222529Sbz#endif
5808232292Sbz	default:
5809232292Sbz		rtalloc_ign((struct route *)&ro, 0);	/* No/default FIB. */
5810232292Sbz		break;
5811232292Sbz	}
5812126261Smlaier#else /* ! __FreeBSD__ */
5813145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5814126261Smlaier#endif
5815126258Smlaier
5816126258Smlaier	if (ro.ro_rt != NULL) {
5817171168Smlaier		/* No interface given, this is a no-route check */
5818171168Smlaier		if (kif == NULL)
5819171168Smlaier			goto out;
5820171168Smlaier
5821171168Smlaier		if (kif->pfik_ifp == NULL) {
5822171168Smlaier			ret = 0;
5823171168Smlaier			goto out;
5824171168Smlaier		}
5825171168Smlaier
5826171168Smlaier		/* Perform uRPF check if passed input interface */
5827171168Smlaier		ret = 0;
5828171168Smlaier		rn = (struct radix_node *)ro.ro_rt;
5829171168Smlaier		do {
5830171168Smlaier			rt = (struct rtentry *)rn;
5831171168Smlaier#ifndef __FreeBSD__ /* CARPDEV */
5832171168Smlaier			if (rt->rt_ifp->if_type == IFT_CARP)
5833171168Smlaier				ifp = rt->rt_ifp->if_carpdev;
5834171168Smlaier			else
5835171168Smlaier#endif
5836171168Smlaier				ifp = rt->rt_ifp;
5837171168Smlaier
5838171168Smlaier			if (kif->pfik_ifp == ifp)
5839171168Smlaier				ret = 1;
5840223637Sbz#ifdef __FreeBSD__
5841223637Sbz#ifdef RADIX_MPATH
5842171168Smlaier			rn = rn_mpath_next(rn);
5843171168Smlaier#endif
5844223637Sbz#else
5845223637Sbz			rn = rn_mpath_next(rn, 0);
5846223637Sbz#endif
5847171168Smlaier		} while (check_mpath == 1 && rn != NULL && ret == 0);
5848171168Smlaier	} else
5849171168Smlaier		ret = 0;
5850171168Smlaierout:
5851171168Smlaier	if (ro.ro_rt != NULL)
5852126258Smlaier		RTFREE(ro.ro_rt);
5853171168Smlaier	return (ret);
5854145836Smlaier}
5855145836Smlaier
5856145836Smlaierint
5857232292Sbzpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw,
5858232292Sbz    int rtableid)
5859145836Smlaier{
5860145836Smlaier	struct sockaddr_in	*dst;
5861145836Smlaier#ifdef INET6
5862145836Smlaier	struct sockaddr_in6	*dst6;
5863145836Smlaier	struct route_in6	 ro;
5864145836Smlaier#else
5865145836Smlaier	struct route		 ro;
5866145836Smlaier#endif
5867145836Smlaier	int			 ret = 0;
5868145836Smlaier
5869145836Smlaier	bzero(&ro, sizeof(ro));
5870145836Smlaier	switch (af) {
5871145836Smlaier	case AF_INET:
5872145836Smlaier		dst = satosin(&ro.ro_dst);
5873145836Smlaier		dst->sin_family = AF_INET;
5874145836Smlaier		dst->sin_len = sizeof(*dst);
5875145836Smlaier		dst->sin_addr = addr->v4;
5876145836Smlaier		break;
5877145836Smlaier#ifdef INET6
5878145836Smlaier	case AF_INET6:
5879145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5880145836Smlaier		dst6->sin6_family = AF_INET6;
5881145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5882145836Smlaier		dst6->sin6_addr = addr->v6;
5883145836Smlaier		break;
5884145836Smlaier#endif /* INET6 */
5885145836Smlaier	default:
5886145836Smlaier		return (0);
5887145836Smlaier	}
5888145836Smlaier
5889145836Smlaier#ifdef __FreeBSD__
5890232292Sbz	switch (af) {
5891232292Sbz#ifdef INET6
5892232292Sbz	case AF_INET6:
5893232292Sbz		in6_rtalloc_ign(&ro, 0, rtableid);
5894232292Sbz		break;
5895232292Sbz#endif
5896222529Sbz#ifdef INET
5897232292Sbz	case AF_INET:
5898232292Sbz		in_rtalloc_ign((struct route *)&ro, 0, rtableid);
5899232292Sbz		break;
5900222529Sbz#endif
5901232292Sbz	default:
5902186119Sqingli		rtalloc_ign((struct route *)&ro, 0);
5903232292Sbz		break;
5904232292Sbz	}
5905145836Smlaier#else /* ! __FreeBSD__ */
5906145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5907145836Smlaier#endif
5908145836Smlaier
5909145836Smlaier	if (ro.ro_rt != NULL) {
5910145836Smlaier#ifdef __FreeBSD__
5911145836Smlaier		/* XXX_IMPORT: later */
5912145836Smlaier#else
5913145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
5914145836Smlaier			ret = 1;
5915145836Smlaier#endif
5916145836Smlaier		RTFREE(ro.ro_rt);
5917145836Smlaier	}
5918145836Smlaier
5919126258Smlaier	return (ret);
5920126258Smlaier}
5921126258Smlaier
5922126258Smlaier#ifdef INET
5923126258Smlaiervoid
5924126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5925171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
5926126258Smlaier{
5927126258Smlaier	struct mbuf		*m0, *m1;
5928126258Smlaier	struct route		 iproute;
5929171168Smlaier	struct route		*ro = NULL;
5930126258Smlaier	struct sockaddr_in	*dst;
5931126258Smlaier	struct ip		*ip;
5932126258Smlaier	struct ifnet		*ifp = NULL;
5933126258Smlaier	struct pf_addr		 naddr;
5934130613Smlaier	struct pf_src_node	*sn = NULL;
5935126258Smlaier	int			 error = 0;
5936127145Smlaier#ifdef __FreeBSD__
5937126261Smlaier	int sw_csum;
5938126261Smlaier#endif
5939171168Smlaier#ifdef IPSEC
5940171168Smlaier	struct m_tag		*mtag;
5941171168Smlaier#endif /* IPSEC */
5942126258Smlaier
5943126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5944126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5945126258Smlaier		panic("pf_route: invalid parameters");
5946126258Smlaier
5947223637Sbz#ifdef __FreeBSD__
5948171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
5949223637Sbz#else
5950223637Sbz	if ((*m)->m_pkthdr.pf.routed++ > 3) {
5951223637Sbz#endif
5952171168Smlaier		m0 = *m;
5953171168Smlaier		*m = NULL;
5954171168Smlaier		goto bad;
5955132303Smlaier	}
5956132303Smlaier
5957126258Smlaier	if (r->rt == PF_DUPTO) {
5958127145Smlaier#ifdef __FreeBSD__
5959132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5960126261Smlaier#else
5961132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5962126261Smlaier#endif
5963126258Smlaier			return;
5964126258Smlaier	} else {
5965126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5966126258Smlaier			return;
5967126258Smlaier		m0 = *m;
5968126258Smlaier	}
5969126258Smlaier
5970145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
5971145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5972145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5973145836Smlaier		goto bad;
5974145836Smlaier	}
5975145836Smlaier
5976126258Smlaier	ip = mtod(m0, struct ip *);
5977126258Smlaier
5978126258Smlaier	ro = &iproute;
5979126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5980126258Smlaier	dst = satosin(&ro->ro_dst);
5981126258Smlaier	dst->sin_family = AF_INET;
5982126258Smlaier	dst->sin_len = sizeof(*dst);
5983126258Smlaier	dst->sin_addr = ip->ip_dst;
5984126258Smlaier
5985126258Smlaier	if (r->rt == PF_FASTROUTE) {
5986223637Sbz#ifdef __FreeBSD__
5987232292Sbz		in_rtalloc_ign(ro, 0, M_GETFIB(m0));
5988223637Sbz#else
5989223637Sbz		rtalloc(ro);
5990223637Sbz#endif
5991126258Smlaier		if (ro->ro_rt == 0) {
5992223637Sbz#ifdef __FreeBSD__
5993196039Srwatson			KMOD_IPSTAT_INC(ips_noroute);
5994223637Sbz#else
5995223637Sbz			ipstat.ips_noroute++;
5996223637Sbz#endif
5997126258Smlaier			goto bad;
5998126258Smlaier		}
5999126258Smlaier
6000126258Smlaier		ifp = ro->ro_rt->rt_ifp;
6001126258Smlaier		ro->ro_rt->rt_use++;
6002126258Smlaier
6003126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
6004126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
6005126258Smlaier	} else {
6006145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
6007145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6008145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
6009145836Smlaier			goto bad;
6010145836Smlaier		}
6011126258Smlaier		if (s == NULL) {
6012130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
6013130613Smlaier			    &naddr, NULL, &sn);
6014126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
6015126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
6016130613Smlaier			ifp = r->rpool.cur->kif ?
6017130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
6018126258Smlaier		} else {
6019126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
6020126258Smlaier				dst->sin_addr.s_addr =
6021126258Smlaier				    s->rt_addr.v4.s_addr;
6022130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6023126258Smlaier		}
6024126258Smlaier	}
6025126258Smlaier	if (ifp == NULL)
6026126258Smlaier		goto bad;
6027126258Smlaier
6028130639Smlaier	if (oifp != ifp) {
6029127145Smlaier#ifdef __FreeBSD__
6030126261Smlaier		PF_UNLOCK();
6031145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6032126261Smlaier			PF_LOCK();
6033126261Smlaier			goto bad;
6034126261Smlaier		} else if (m0 == NULL) {
6035126261Smlaier			PF_LOCK();
6036126261Smlaier			goto done;
6037126261Smlaier		}
6038126261Smlaier		PF_LOCK();
6039126261Smlaier#else
6040145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6041126258Smlaier			goto bad;
6042126258Smlaier		else if (m0 == NULL)
6043126258Smlaier			goto done;
6044126261Smlaier#endif
6045145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
6046145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6047145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6048145836Smlaier			goto bad;
6049145836Smlaier		}
6050126258Smlaier		ip = mtod(m0, struct ip *);
6051126258Smlaier	}
6052126258Smlaier
6053127145Smlaier#ifdef __FreeBSD__
6054126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
6055126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
6056126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
6057126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
6058126261Smlaier		/*
6059126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
6060126261Smlaier		 */
6061126261Smlaier		NTOHS(ip->ip_len);
6062223637Sbz		NTOHS(ip->ip_off);	/* XXX: needed? */
6063126261Smlaier		in_delayed_cksum(m0);
6064126261Smlaier		HTONS(ip->ip_len);
6065126261Smlaier		HTONS(ip->ip_off);
6066126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
6067126261Smlaier	}
6068126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
6069126261Smlaier
6070126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
6071126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
6072223637Sbz	    ((ip->ip_off & htons(IP_DF)) == 0))) {
6073126261Smlaier		/*
6074126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
6075126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
6076126261Smlaier		 */
6077126261Smlaier		ip->ip_sum = 0;
6078126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
6079126261Smlaier			/* From KAME */
6080126261Smlaier			if (ip->ip_v == IPVERSION &&
6081126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
6082126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
6083126261Smlaier			} else {
6084126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6085126261Smlaier			}
6086126261Smlaier		}
6087126261Smlaier		PF_UNLOCK();
6088191148Skmacy		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro);
6089126261Smlaier		PF_LOCK();
6090126261Smlaier		goto done;
6091126261Smlaier	}
6092126261Smlaier#else
6093126258Smlaier	/* Copied from ip_output. */
6094130613Smlaier#ifdef IPSEC
6095130613Smlaier	/*
6096130613Smlaier	 * If deferred crypto processing is needed, check that the
6097130613Smlaier	 * interface supports it.
6098130613Smlaier	 */
6099130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
6100130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
6101130613Smlaier		/* Notify IPsec to do its own crypto. */
6102130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
6103130613Smlaier		goto bad;
6104130613Smlaier	}
6105130613Smlaier#endif /* IPSEC */
6106130613Smlaier
6107130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
6108171168Smlaier	if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
6109130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
6110130613Smlaier		    ifp->if_bridge != NULL) {
6111130613Smlaier			in_delayed_cksum(m0);
6112223637Sbz			m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clr */
6113130613Smlaier		}
6114171168Smlaier	} else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
6115130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
6116130613Smlaier		    ifp->if_bridge != NULL) {
6117130613Smlaier			in_delayed_cksum(m0);
6118223637Sbz			m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clr */
6119130613Smlaier		}
6120130613Smlaier	}
6121130613Smlaier
6122126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
6123223637Sbz		ip->ip_sum = 0;
6124126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
6125126258Smlaier		    ifp->if_bridge == NULL) {
6126171168Smlaier			m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
6127223637Sbz#ifdef __FreeBSD__
6128196039Srwatson			KMOD_IPSTAT_INC(ips_outhwcsum);
6129223637Sbz#else
6130223637Sbz			ipstat.ips_outhwcsum++;
6131223637Sbz#endif
6132223637Sbz		} else
6133126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6134126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
6135171168Smlaier		if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
6136196039Srwatson			KMOD_TCPSTAT_INC(tcps_outhwcsum);
6137171168Smlaier		else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
6138196039Srwatson			KMOD_UDPSTAT_INC(udps_outhwcsum);
6139126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
6140126258Smlaier		goto done;
6141126258Smlaier	}
6142126261Smlaier#endif
6143223637Sbz
6144126258Smlaier	/*
6145126258Smlaier	 * Too large for interface; fragment if possible.
6146126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
6147126258Smlaier	 */
6148223637Sbz	if (ip->ip_off & htons(IP_DF)) {
6149223637Sbz#ifdef __FreeBSD__
6150196039Srwatson		KMOD_IPSTAT_INC(ips_cantfrag);
6151223637Sbz#else
6152223637Sbz		ipstat.ips_cantfrag++;
6153223637Sbz#endif
6154126258Smlaier		if (r->rt != PF_DUPTO) {
6155127145Smlaier#ifdef __FreeBSD__
6156126261Smlaier			/* icmp_error() expects host byte ordering */
6157126261Smlaier			NTOHS(ip->ip_len);
6158126261Smlaier			NTOHS(ip->ip_off);
6159126261Smlaier			PF_UNLOCK();
6160126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6161145886Smlaier			    ifp->if_mtu);
6162145874Smlaier			PF_LOCK();
6163145874Smlaier#else
6164145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6165171168Smlaier			    ifp->if_mtu);
6166126261Smlaier#endif
6167126258Smlaier			goto done;
6168126258Smlaier		} else
6169126258Smlaier			goto bad;
6170126258Smlaier	}
6171126258Smlaier
6172126258Smlaier	m1 = m0;
6173127145Smlaier#ifdef __FreeBSD__
6174126261Smlaier	/*
6175126261Smlaier	 * XXX: is cheaper + less error prone than own function
6176126261Smlaier	 */
6177126261Smlaier	NTOHS(ip->ip_len);
6178126261Smlaier	NTOHS(ip->ip_off);
6179126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
6180126261Smlaier#else
6181126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
6182126261Smlaier#endif
6183127531Smlaier	if (error) {
6184223637Sbz#ifndef __FreeBSD__    /* ip_fragment does not do m_freem() on FreeBSD */
6185127531Smlaier		m0 = NULL;
6186126261Smlaier#endif
6187126258Smlaier		goto bad;
6188127531Smlaier	}
6189126258Smlaier
6190126258Smlaier	for (m0 = m1; m0; m0 = m1) {
6191126258Smlaier		m1 = m0->m_nextpkt;
6192126258Smlaier		m0->m_nextpkt = 0;
6193127145Smlaier#ifdef __FreeBSD__
6194126261Smlaier		if (error == 0) {
6195126261Smlaier			PF_UNLOCK();
6196126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6197126261Smlaier			    NULL);
6198126261Smlaier			PF_LOCK();
6199126261Smlaier		} else
6200126261Smlaier#else
6201126258Smlaier		if (error == 0)
6202126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6203126258Smlaier			    NULL);
6204126258Smlaier		else
6205126261Smlaier#endif
6206126258Smlaier			m_freem(m0);
6207126258Smlaier	}
6208126258Smlaier
6209126258Smlaier	if (error == 0)
6210223637Sbz#ifdef __FreeBSD__
6211196039Srwatson		KMOD_IPSTAT_INC(ips_fragmented);
6212223637Sbz#else
6213223637Sbz		ipstat.ips_fragmented++;
6214223637Sbz#endif
6215126258Smlaier
6216126258Smlaierdone:
6217126258Smlaier	if (r->rt != PF_DUPTO)
6218126258Smlaier		*m = NULL;
6219126258Smlaier	if (ro == &iproute && ro->ro_rt)
6220126258Smlaier		RTFREE(ro->ro_rt);
6221126258Smlaier	return;
6222126258Smlaier
6223126258Smlaierbad:
6224126258Smlaier	m_freem(m0);
6225126258Smlaier	goto done;
6226126258Smlaier}
6227126258Smlaier#endif /* INET */
6228126258Smlaier
6229126258Smlaier#ifdef INET6
6230126258Smlaiervoid
6231126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6232171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6233126258Smlaier{
6234126258Smlaier	struct mbuf		*m0;
6235126258Smlaier	struct route_in6	 ip6route;
6236126258Smlaier	struct route_in6	*ro;
6237126258Smlaier	struct sockaddr_in6	*dst;
6238126258Smlaier	struct ip6_hdr		*ip6;
6239126258Smlaier	struct ifnet		*ifp = NULL;
6240126258Smlaier	struct pf_addr		 naddr;
6241130613Smlaier	struct pf_src_node	*sn = NULL;
6242126258Smlaier
6243126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6244126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6245126258Smlaier		panic("pf_route6: invalid parameters");
6246126258Smlaier
6247223637Sbz#ifdef __FreeBSD__
6248171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6249223637Sbz#else
6250223637Sbz	if ((*m)->m_pkthdr.pf.routed++ > 3) {
6251223637Sbz#endif
6252171168Smlaier		m0 = *m;
6253171168Smlaier		*m = NULL;
6254171168Smlaier		goto bad;
6255132303Smlaier	}
6256132303Smlaier
6257126258Smlaier	if (r->rt == PF_DUPTO) {
6258127145Smlaier#ifdef __FreeBSD__
6259132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6260126261Smlaier#else
6261132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6262126261Smlaier#endif
6263126258Smlaier			return;
6264126258Smlaier	} else {
6265126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6266126258Smlaier			return;
6267126258Smlaier		m0 = *m;
6268126258Smlaier	}
6269126258Smlaier
6270145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
6271145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6272145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6273145836Smlaier		goto bad;
6274145836Smlaier	}
6275126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
6276126258Smlaier
6277126258Smlaier	ro = &ip6route;
6278126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6279126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
6280126258Smlaier	dst->sin6_family = AF_INET6;
6281126258Smlaier	dst->sin6_len = sizeof(*dst);
6282126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
6283126258Smlaier
6284171168Smlaier	/* Cheat. XXX why only in the v6 case??? */
6285126258Smlaier	if (r->rt == PF_FASTROUTE) {
6286127145Smlaier#ifdef __FreeBSD__
6287132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
6288126261Smlaier		PF_UNLOCK();
6289126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
6290126261Smlaier#else
6291223637Sbz		m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
6292223637Sbz		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
6293126261Smlaier#endif
6294126258Smlaier		return;
6295126258Smlaier	}
6296126258Smlaier
6297145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
6298145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6299145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
6300145836Smlaier		goto bad;
6301145836Smlaier	}
6302126258Smlaier	if (s == NULL) {
6303130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
6304130613Smlaier		    &naddr, NULL, &sn);
6305126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
6306126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6307126258Smlaier			    &naddr, AF_INET6);
6308130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
6309126258Smlaier	} else {
6310126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
6311126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6312126258Smlaier			    &s->rt_addr, AF_INET6);
6313130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6314126258Smlaier	}
6315126258Smlaier	if (ifp == NULL)
6316126258Smlaier		goto bad;
6317126258Smlaier
6318126258Smlaier	if (oifp != ifp) {
6319127145Smlaier#ifdef __FreeBSD__
6320132303Smlaier		PF_UNLOCK();
6321145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6322126261Smlaier			PF_LOCK();
6323132303Smlaier			goto bad;
6324132303Smlaier		} else if (m0 == NULL) {
6325132303Smlaier			PF_LOCK();
6326132303Smlaier			goto done;
6327132303Smlaier		}
6328132303Smlaier		PF_LOCK();
6329126261Smlaier#else
6330145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6331132303Smlaier			goto bad;
6332132303Smlaier		else if (m0 == NULL)
6333132303Smlaier			goto done;
6334126261Smlaier#endif
6335145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
6336145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6337145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6338145836Smlaier			goto bad;
6339145836Smlaier		}
6340132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
6341126258Smlaier	}
6342126258Smlaier
6343293896Sglebius	if (m0->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 &
6344293896Sglebius	    ~ifp->if_hwassist) {
6345293896Sglebius		uint32_t plen = m0->m_pkthdr.len - sizeof(*ip6);
6346293896Sglebius		in6_delayed_cksum(m0, plen, sizeof(struct ip6_hdr));
6347293896Sglebius		m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
6348293896Sglebius	}
6349293896Sglebius
6350126258Smlaier	/*
6351126258Smlaier	 * If the packet is too large for the outgoing interface,
6352126258Smlaier	 * send back an icmp6 error.
6353126258Smlaier	 */
6354171168Smlaier	if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
6355126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
6356126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
6357127145Smlaier#ifdef __FreeBSD__
6358126261Smlaier		PF_UNLOCK();
6359126261Smlaier#endif
6360223637Sbz		nd6_output(ifp, ifp, m0, dst, NULL);
6361127145Smlaier#ifdef __FreeBSD__
6362126261Smlaier		PF_LOCK();
6363126261Smlaier#endif
6364126258Smlaier	} else {
6365126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6366127145Smlaier#ifdef __FreeBSD__
6367126261Smlaier		if (r->rt != PF_DUPTO) {
6368126261Smlaier			PF_UNLOCK();
6369126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6370126261Smlaier			PF_LOCK();
6371223637Sbz		} else
6372126261Smlaier#else
6373126258Smlaier		if (r->rt != PF_DUPTO)
6374126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6375126258Smlaier		else
6376126261Smlaier#endif
6377126258Smlaier			goto bad;
6378126258Smlaier	}
6379126258Smlaier
6380126258Smlaierdone:
6381126258Smlaier	if (r->rt != PF_DUPTO)
6382126258Smlaier		*m = NULL;
6383126258Smlaier	return;
6384126258Smlaier
6385126258Smlaierbad:
6386126258Smlaier	m_freem(m0);
6387126258Smlaier	goto done;
6388126258Smlaier}
6389126258Smlaier#endif /* INET6 */
6390126258Smlaier
6391127145Smlaier#ifdef __FreeBSD__
6392126258Smlaier/*
6393132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6394137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6395132566Smlaier *   ti(4), txp(4), xl(4)
6396132566Smlaier *
6397132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6398132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6399132566Smlaier *   csum_data
6400132566Smlaier * CSUM_DATA_VALID :
6401132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6402132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6403132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6404132566Smlaier *
6405132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6406132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6407132566Smlaier * TCP/UDP layer.
6408132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6409126261Smlaier */
6410126261Smlaierint
6411126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6412126261Smlaier{
6413126261Smlaier	u_int16_t sum = 0;
6414126261Smlaier	int hw_assist = 0;
6415126261Smlaier	struct ip *ip;
6416126261Smlaier
6417126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6418126261Smlaier		return (1);
6419126261Smlaier	if (m->m_pkthdr.len < off + len)
6420126261Smlaier		return (1);
6421126261Smlaier
6422126261Smlaier	switch (p) {
6423126261Smlaier	case IPPROTO_TCP:
6424126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6425126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6426126261Smlaier				sum = m->m_pkthdr.csum_data;
6427126261Smlaier			} else {
6428223637Sbz				ip = mtod(m, struct ip *);
6429126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6430223637Sbz				ip->ip_dst.s_addr, htonl((u_short)len +
6431223637Sbz				m->m_pkthdr.csum_data + IPPROTO_TCP));
6432126261Smlaier			}
6433126261Smlaier			sum ^= 0xffff;
6434126261Smlaier			++hw_assist;
6435126261Smlaier		}
6436126261Smlaier		break;
6437126261Smlaier	case IPPROTO_UDP:
6438126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6439126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6440126261Smlaier				sum = m->m_pkthdr.csum_data;
6441126261Smlaier			} else {
6442223637Sbz				ip = mtod(m, struct ip *);
6443126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6444223637Sbz				ip->ip_dst.s_addr, htonl((u_short)len +
6445223637Sbz				m->m_pkthdr.csum_data + IPPROTO_UDP));
6446126261Smlaier			}
6447126261Smlaier			sum ^= 0xffff;
6448126261Smlaier			++hw_assist;
6449223637Sbz		}
6450126261Smlaier		break;
6451126261Smlaier	case IPPROTO_ICMP:
6452126261Smlaier#ifdef INET6
6453126261Smlaier	case IPPROTO_ICMPV6:
6454126261Smlaier#endif /* INET6 */
6455126261Smlaier		break;
6456126261Smlaier	default:
6457126261Smlaier		return (1);
6458126261Smlaier	}
6459126261Smlaier
6460126261Smlaier	if (!hw_assist) {
6461126261Smlaier		switch (af) {
6462126261Smlaier		case AF_INET:
6463126261Smlaier			if (p == IPPROTO_ICMP) {
6464126261Smlaier				if (m->m_len < off)
6465126261Smlaier					return (1);
6466126261Smlaier				m->m_data += off;
6467126261Smlaier				m->m_len -= off;
6468126261Smlaier				sum = in_cksum(m, len);
6469126261Smlaier				m->m_data -= off;
6470126261Smlaier				m->m_len += off;
6471126261Smlaier			} else {
6472126261Smlaier				if (m->m_len < sizeof(struct ip))
6473126261Smlaier					return (1);
6474126261Smlaier				sum = in4_cksum(m, p, off, len);
6475126261Smlaier			}
6476126261Smlaier			break;
6477126261Smlaier#ifdef INET6
6478126261Smlaier		case AF_INET6:
6479126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6480126261Smlaier				return (1);
6481126261Smlaier			sum = in6_cksum(m, p, off, len);
6482126261Smlaier			break;
6483126261Smlaier#endif /* INET6 */
6484126261Smlaier		default:
6485126261Smlaier			return (1);
6486126261Smlaier		}
6487126261Smlaier	}
6488126261Smlaier	if (sum) {
6489126261Smlaier		switch (p) {
6490126261Smlaier		case IPPROTO_TCP:
6491183550Szec		    {
6492196039Srwatson			KMOD_TCPSTAT_INC(tcps_rcvbadsum);
6493126261Smlaier			break;
6494183550Szec		    }
6495126261Smlaier		case IPPROTO_UDP:
6496183550Szec		    {
6497196039Srwatson			KMOD_UDPSTAT_INC(udps_badsum);
6498126261Smlaier			break;
6499183550Szec		    }
6500222529Sbz#ifdef INET
6501126261Smlaier		case IPPROTO_ICMP:
6502183550Szec		    {
6503196039Srwatson			KMOD_ICMPSTAT_INC(icps_checksum);
6504126261Smlaier			break;
6505183550Szec		    }
6506222529Sbz#endif
6507126261Smlaier#ifdef INET6
6508126261Smlaier		case IPPROTO_ICMPV6:
6509183550Szec		    {
6510196039Srwatson			KMOD_ICMP6STAT_INC(icp6s_checksum);
6511126261Smlaier			break;
6512183550Szec		    }
6513126261Smlaier#endif /* INET6 */
6514126261Smlaier		}
6515126261Smlaier		return (1);
6516132566Smlaier	} else {
6517132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6518132566Smlaier			m->m_pkthdr.csum_flags |=
6519132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6520132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6521132566Smlaier		}
6522126261Smlaier	}
6523126261Smlaier	return (0);
6524126261Smlaier}
6525171168Smlaier#else /* !__FreeBSD__ */
6526223637Sbz
6527126261Smlaier/*
6528126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6529126258Smlaier *   off is the offset where the protocol header starts
6530126258Smlaier *   len is the total length of protocol header plus payload
6531126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6532126258Smlaier */
6533126258Smlaierint
6534130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6535130613Smlaier    sa_family_t af)
6536126258Smlaier{
6537126258Smlaier	u_int16_t flag_ok, flag_bad;
6538126258Smlaier	u_int16_t sum;
6539126258Smlaier
6540126258Smlaier	switch (p) {
6541126258Smlaier	case IPPROTO_TCP:
6542126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6543126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6544126258Smlaier		break;
6545126258Smlaier	case IPPROTO_UDP:
6546126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6547126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6548126258Smlaier		break;
6549126258Smlaier	case IPPROTO_ICMP:
6550126258Smlaier#ifdef INET6
6551126258Smlaier	case IPPROTO_ICMPV6:
6552126258Smlaier#endif /* INET6 */
6553126258Smlaier		flag_ok = flag_bad = 0;
6554126258Smlaier		break;
6555126258Smlaier	default:
6556126258Smlaier		return (1);
6557126258Smlaier	}
6558171168Smlaier	if (m->m_pkthdr.csum_flags & flag_ok)
6559126258Smlaier		return (0);
6560171168Smlaier	if (m->m_pkthdr.csum_flags & flag_bad)
6561126258Smlaier		return (1);
6562126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6563126258Smlaier		return (1);
6564126258Smlaier	if (m->m_pkthdr.len < off + len)
6565126258Smlaier		return (1);
6566145836Smlaier	switch (af) {
6567145836Smlaier#ifdef INET
6568126258Smlaier	case AF_INET:
6569126258Smlaier		if (p == IPPROTO_ICMP) {
6570126258Smlaier			if (m->m_len < off)
6571126258Smlaier				return (1);
6572126258Smlaier			m->m_data += off;
6573126258Smlaier			m->m_len -= off;
6574126258Smlaier			sum = in_cksum(m, len);
6575126258Smlaier			m->m_data -= off;
6576126258Smlaier			m->m_len += off;
6577126258Smlaier		} else {
6578126258Smlaier			if (m->m_len < sizeof(struct ip))
6579126258Smlaier				return (1);
6580126258Smlaier			sum = in4_cksum(m, p, off, len);
6581126258Smlaier		}
6582126258Smlaier		break;
6583145836Smlaier#endif /* INET */
6584126258Smlaier#ifdef INET6
6585126258Smlaier	case AF_INET6:
6586126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6587126258Smlaier			return (1);
6588126258Smlaier		sum = in6_cksum(m, p, off, len);
6589126258Smlaier		break;
6590126258Smlaier#endif /* INET6 */
6591126258Smlaier	default:
6592126258Smlaier		return (1);
6593126258Smlaier	}
6594126258Smlaier	if (sum) {
6595171168Smlaier		m->m_pkthdr.csum_flags |= flag_bad;
6596126258Smlaier		switch (p) {
6597126258Smlaier		case IPPROTO_TCP:
6598196039Srwatson			KMOD_TCPSTAT_INC(tcps_rcvbadsum);
6599126258Smlaier			break;
6600126258Smlaier		case IPPROTO_UDP:
6601196039Srwatson			KMOD_UDPSTAT_INC(udps_badsum);
6602126258Smlaier			break;
6603222529Sbz#ifdef INET
6604126258Smlaier		case IPPROTO_ICMP:
6605196039Srwatson			KMOD_ICMPSTAT_INC(icps_checksum);
6606126258Smlaier			break;
6607222529Sbz#endif
6608126258Smlaier#ifdef INET6
6609126258Smlaier		case IPPROTO_ICMPV6:
6610196039Srwatson			KMOD_ICMP6STAT_INC(icp6s_checksum);
6611126258Smlaier			break;
6612126258Smlaier#endif /* INET6 */
6613126258Smlaier		}
6614126258Smlaier		return (1);
6615126258Smlaier	}
6616171168Smlaier	m->m_pkthdr.csum_flags |= flag_ok;
6617126258Smlaier	return (0);
6618126258Smlaier}
6619223637Sbz#endif
6620126258Smlaier
6621223637Sbz#ifndef __FreeBSD__
6622223637Sbzstruct pf_divert *
6623223637Sbzpf_find_divert(struct mbuf *m)
6624223637Sbz{
6625223637Sbz	struct m_tag    *mtag;
6626223637Sbz
6627223637Sbz	if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL)
6628223637Sbz		return (NULL);
6629223637Sbz
6630223637Sbz	return ((struct pf_divert *)(mtag + 1));
6631223637Sbz}
6632223637Sbz
6633223637Sbzstruct pf_divert *
6634223637Sbzpf_get_divert(struct mbuf *m)
6635223637Sbz{
6636223637Sbz	struct m_tag    *mtag;
6637223637Sbz
6638223637Sbz	if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) {
6639223637Sbz		mtag = m_tag_get(PACKET_TAG_PF_DIVERT, sizeof(struct pf_divert),
6640223637Sbz		    M_NOWAIT);
6641223637Sbz		if (mtag == NULL)
6642223637Sbz			return (NULL);
6643223637Sbz		bzero(mtag + 1, sizeof(struct pf_divert));
6644223637Sbz		m_tag_prepend(m, mtag);
6645223637Sbz	}
6646223637Sbz
6647223637Sbz	return ((struct pf_divert *)(mtag + 1));
6648223637Sbz}
6649223637Sbz#endif
6650223637Sbz
6651126258Smlaier#ifdef INET
6652126258Smlaierint
6653135920Smlaier#ifdef __FreeBSD__
6654145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6655145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6656135920Smlaier#else
6657145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6658145836Smlaier    struct ether_header *eh)
6659135920Smlaier#endif
6660126258Smlaier{
6661130613Smlaier	struct pfi_kif		*kif;
6662130613Smlaier	u_short			 action, reason = 0, log = 0;
6663130613Smlaier	struct mbuf		*m = *m0;
6664223637Sbz#ifdef __FreeBSD__
6665223637Sbz	struct ip		*h = NULL;
6666223637Sbz	struct m_tag		*ipfwtag;
6667223637Sbz	struct pf_rule		*a = NULL, *r = &V_pf_default_rule, *tr, *nr;
6668223637Sbz#else
6669223637Sbz	struct ip		*h;
6670130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6671223637Sbz#endif
6672130613Smlaier	struct pf_state		*s = NULL;
6673130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6674130613Smlaier	struct pf_pdesc		 pd;
6675130613Smlaier	int			 off, dirndx, pqid = 0;
6676126258Smlaier
6677127145Smlaier#ifdef __FreeBSD__
6678126261Smlaier	PF_LOCK();
6679223637Sbz	if (!V_pf_status.running)
6680171168Smlaier	{
6681126261Smlaier		PF_UNLOCK();
6682171168Smlaier		return (PF_PASS);
6683126261Smlaier	}
6684223637Sbz#else
6685223637Sbz	if (!pf_status.running)
6686223637Sbz		return (PF_PASS);
6687171168Smlaier#endif
6688126258Smlaier
6689171168Smlaier	memset(&pd, 0, sizeof(pd));
6690223637Sbz#ifdef __FreeBSD__
6691171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
6692171168Smlaier		PF_UNLOCK();
6693171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6694171168Smlaier		    ("pf_test: pf_get_mtag returned NULL\n"));
6695171168Smlaier		return (PF_DROP);
6696171168Smlaier	}
6697171168Smlaier#endif
6698223637Sbz#ifndef __FreeBSD__
6699145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6700223637Sbz		kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
6701223637Sbz	else
6702145836Smlaier#endif
6703223637Sbz		kif = (struct pfi_kif *)ifp->if_pf_kif;
6704145836Smlaier
6705130613Smlaier	if (kif == NULL) {
6706130613Smlaier#ifdef __FreeBSD__
6707130613Smlaier		PF_UNLOCK();
6708130613Smlaier#endif
6709145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6710145836Smlaier		    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
6711130613Smlaier		return (PF_DROP);
6712130613Smlaier	}
6713223637Sbz	if (kif->pfik_flags & PFI_IFLAG_SKIP)
6714145836Smlaier#ifdef __FreeBSD__
6715223637Sbz	{
6716145836Smlaier		PF_UNLOCK();
6717145836Smlaier#endif
6718145836Smlaier		return (PF_PASS);
6719223637Sbz#ifdef __FreeBSD__
6720145836Smlaier	}
6721223637Sbz#endif
6722130613Smlaier
6723130613Smlaier#ifdef __FreeBSD__
6724126261Smlaier	M_ASSERTPKTHDR(m);
6725126261Smlaier#else
6726126258Smlaier#ifdef DIAGNOSTIC
6727126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6728126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6729145836Smlaier#endif /* DIAGNOSTIC */
6730223637Sbz#endif
6731126258Smlaier
6732126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6733126258Smlaier		action = PF_DROP;
6734126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6735126258Smlaier		log = 1;
6736126258Smlaier		goto done;
6737126258Smlaier	}
6738126258Smlaier
6739223637Sbz#ifdef __FreeBSD__
6740223637Sbz	if (m->m_flags & M_SKIP_FIREWALL) {
6741223637Sbz		PF_UNLOCK();
6742223637Sbz		return (PF_PASS);
6743223637Sbz	}
6744223637Sbz#else
6745223637Sbz	if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
6746223637Sbz		return (PF_PASS);
6747223637Sbz#endif
6748223637Sbz
6749223637Sbz#ifdef __FreeBSD__
6750223637Sbz	if (ip_divert_ptr != NULL &&
6751223637Sbz	    ((ipfwtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) {
6752223637Sbz		struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(ipfwtag+1);
6753223637Sbz		if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) {
6754223637Sbz			pd.pf_mtag->flags |= PF_PACKET_LOOPED;
6755223637Sbz			m_tag_delete(m, ipfwtag);
6756223637Sbz		}
6757223637Sbz		if (pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) {
6758223637Sbz			m->m_flags |= M_FASTFWD_OURS;
6759223637Sbz			pd.pf_mtag->flags &= ~PF_FASTFWD_OURS_PRESENT;
6760223637Sbz		}
6761223637Sbz	} else
6762223637Sbz#endif
6763126258Smlaier	/* We do IP header normalization and packet reassembly here */
6764145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6765126258Smlaier		action = PF_DROP;
6766126258Smlaier		goto done;
6767126258Smlaier	}
6768223637Sbz	m = *m0;	/* pf_normalize messes with m0 */
6769126258Smlaier	h = mtod(m, struct ip *);
6770126258Smlaier
6771126258Smlaier	off = h->ip_hl << 2;
6772126258Smlaier	if (off < (int)sizeof(*h)) {
6773126258Smlaier		action = PF_DROP;
6774126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6775126258Smlaier		log = 1;
6776126258Smlaier		goto done;
6777126258Smlaier	}
6778126258Smlaier
6779126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6780126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6781223637Sbz	pd.sport = pd.dport = NULL;
6782126258Smlaier	pd.ip_sum = &h->ip_sum;
6783223637Sbz	pd.proto_sum = NULL;
6784126258Smlaier	pd.proto = h->ip_p;
6785223637Sbz	pd.dir = dir;
6786223637Sbz	pd.sidx = (dir == PF_IN) ? 0 : 1;
6787223637Sbz	pd.didx = (dir == PF_IN) ? 1 : 0;
6788126258Smlaier	pd.af = AF_INET;
6789126258Smlaier	pd.tos = h->ip_tos;
6790126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6791145836Smlaier	pd.eh = eh;
6792126258Smlaier
6793126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6794126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6795130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6796126258Smlaier		    &pd, &a, &ruleset);
6797126258Smlaier		goto done;
6798126258Smlaier	}
6799126258Smlaier
6800126258Smlaier	switch (h->ip_p) {
6801126258Smlaier
6802126258Smlaier	case IPPROTO_TCP: {
6803126258Smlaier		struct tcphdr	th;
6804126258Smlaier
6805126258Smlaier		pd.hdr.tcp = &th;
6806126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6807126258Smlaier		    &action, &reason, AF_INET)) {
6808126258Smlaier			log = action != PF_PASS;
6809126258Smlaier			goto done;
6810126258Smlaier		}
6811126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6812126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6813126258Smlaier			pqid = 1;
6814130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6815126258Smlaier		if (action == PF_DROP)
6816130613Smlaier			goto done;
6817130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6818126258Smlaier		    &reason);
6819126258Smlaier		if (action == PF_PASS) {
6820223637Sbz#if NPFSYNC > 0
6821223637Sbz#ifdef __FreeBSD__
6822223637Sbz			if (pfsync_update_state_ptr != NULL)
6823223637Sbz				pfsync_update_state_ptr(s);
6824223637Sbz#else
6825130613Smlaier			pfsync_update_state(s);
6826223637Sbz#endif
6827145836Smlaier#endif /* NPFSYNC */
6828126258Smlaier			r = s->rule.ptr;
6829130613Smlaier			a = s->anchor.ptr;
6830126258Smlaier			log = s->log;
6831126258Smlaier		} else if (s == NULL)
6832135920Smlaier#ifdef __FreeBSD__
6833223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
6834145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6835135920Smlaier#else
6836223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
6837145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6838135920Smlaier#endif
6839126258Smlaier		break;
6840126258Smlaier	}
6841126258Smlaier
6842126258Smlaier	case IPPROTO_UDP: {
6843126258Smlaier		struct udphdr	uh;
6844126258Smlaier
6845126258Smlaier		pd.hdr.udp = &uh;
6846126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6847126258Smlaier		    &action, &reason, AF_INET)) {
6848126258Smlaier			log = action != PF_PASS;
6849126258Smlaier			goto done;
6850126258Smlaier		}
6851130613Smlaier		if (uh.uh_dport == 0 ||
6852130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6853130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6854130613Smlaier			action = PF_DROP;
6855171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
6856130613Smlaier			goto done;
6857130613Smlaier		}
6858130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6859126258Smlaier		if (action == PF_PASS) {
6860223637Sbz#if NPFSYNC > 0
6861223637Sbz#ifdef __FreeBSD__
6862223637Sbz			if (pfsync_update_state_ptr != NULL)
6863223637Sbz				pfsync_update_state_ptr(s);
6864223637Sbz#else
6865130613Smlaier			pfsync_update_state(s);
6866223637Sbz#endif
6867145836Smlaier#endif /* NPFSYNC */
6868126258Smlaier			r = s->rule.ptr;
6869126258Smlaier			a = s->anchor.ptr;
6870126258Smlaier			log = s->log;
6871126258Smlaier		} else if (s == NULL)
6872135920Smlaier#ifdef __FreeBSD__
6873223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
6874145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6875135920Smlaier#else
6876223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
6877145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6878135920Smlaier#endif
6879126258Smlaier		break;
6880126258Smlaier	}
6881126258Smlaier
6882126258Smlaier	case IPPROTO_ICMP: {
6883126258Smlaier		struct icmp	ih;
6884126258Smlaier
6885126258Smlaier		pd.hdr.icmp = &ih;
6886126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6887126258Smlaier		    &action, &reason, AF_INET)) {
6888126258Smlaier			log = action != PF_PASS;
6889126258Smlaier			goto done;
6890126258Smlaier		}
6891145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
6892145836Smlaier		    &reason);
6893126258Smlaier		if (action == PF_PASS) {
6894223637Sbz#if NPFSYNC > 0
6895223637Sbz#ifdef __FreeBSD__
6896223637Sbz			if (pfsync_update_state_ptr != NULL)
6897223637Sbz				pfsync_update_state_ptr(s);
6898223637Sbz#else
6899130613Smlaier			pfsync_update_state(s);
6900223637Sbz#endif
6901145836Smlaier#endif /* NPFSYNC */
6902126258Smlaier			r = s->rule.ptr;
6903126258Smlaier			a = s->anchor.ptr;
6904126258Smlaier			log = s->log;
6905126258Smlaier		} else if (s == NULL)
6906145836Smlaier#ifdef __FreeBSD__
6907223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
6908223637Sbz			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6909145836Smlaier#else
6910223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
6911145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6912145836Smlaier#endif
6913126258Smlaier		break;
6914126258Smlaier	}
6915126258Smlaier
6916223637Sbz#ifdef INET6
6917223637Sbz	case IPPROTO_ICMPV6: {
6918223637Sbz		action = PF_DROP;
6919223637Sbz		DPFPRINTF(PF_DEBUG_MISC,
6920223637Sbz		    ("pf: dropping IPv4 packet with ICMPv6 payload\n"));
6921223637Sbz		goto done;
6922223637Sbz	}
6923223637Sbz#endif
6924223637Sbz
6925126258Smlaier	default:
6926223637Sbz		action = pf_test_state_other(&s, dir, kif, m, &pd);
6927126258Smlaier		if (action == PF_PASS) {
6928223637Sbz#if NPFSYNC > 0
6929223637Sbz#ifdef __FreeBSD__
6930223637Sbz			if (pfsync_update_state_ptr != NULL)
6931223637Sbz				pfsync_update_state_ptr(s);
6932223637Sbz#else
6933130613Smlaier			pfsync_update_state(s);
6934223637Sbz#endif
6935145836Smlaier#endif /* NPFSYNC */
6936126258Smlaier			r = s->rule.ptr;
6937126258Smlaier			a = s->anchor.ptr;
6938126258Smlaier			log = s->log;
6939126258Smlaier		} else if (s == NULL)
6940145836Smlaier#ifdef __FreeBSD__
6941223637Sbz			action = pf_test_rule(&r, &s, dir, kif, m, off, h,
6942223637Sbz			    &pd, &a, &ruleset, NULL, inp);
6943145836Smlaier#else
6944223637Sbz			action = pf_test_rule(&r, &s, dir, kif, m, off, h,
6945145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
6946145836Smlaier#endif
6947126258Smlaier		break;
6948126258Smlaier	}
6949126258Smlaier
6950126258Smlaierdone:
6951126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
6952200930Sdelphij	    !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
6953126258Smlaier		action = PF_DROP;
6954145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
6955126258Smlaier		log = 1;
6956126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
6957126258Smlaier		    ("pf: dropping packet with ip options\n"));
6958126258Smlaier	}
6959126258Smlaier
6960232292Sbz	if ((s && s->tag) || r->rtableid >= 0)
6961223637Sbz#ifdef __FreeBSD__
6962223637Sbz		pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag);
6963223637Sbz#else
6964223637Sbz		pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
6965223637Sbz#endif
6966145836Smlaier
6967223637Sbz	if (dir == PF_IN && s && s->key[PF_SK_STACK])
6968223637Sbz#ifdef __FreeBSD__
6969223637Sbz		pd.pf_mtag->statekey = s->key[PF_SK_STACK];
6970223637Sbz#else
6971223637Sbz		m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK];
6972223637Sbz#endif
6973223637Sbz
6974126258Smlaier#ifdef ALTQ
6975126258Smlaier	if (action == PF_PASS && r->qid) {
6976223637Sbz#ifdef __FreeBSD__
6977171168Smlaier		if (pqid || (pd.tos & IPTOS_LOWDELAY))
6978171168Smlaier			pd.pf_mtag->qid = r->pqid;
6979171168Smlaier		else
6980171168Smlaier			pd.pf_mtag->qid = r->qid;
6981171168Smlaier		/* add hints for ecn */
6982171168Smlaier		pd.pf_mtag->hdr = h;
6983223637Sbz
6984223637Sbz#else
6985223637Sbz		if (pqid || (pd.tos & IPTOS_LOWDELAY))
6986223637Sbz			m->m_pkthdr.pf.qid = r->pqid;
6987223637Sbz		else
6988223637Sbz			m->m_pkthdr.pf.qid = r->qid;
6989223637Sbz		/* add hints for ecn */
6990223637Sbz		m->m_pkthdr.pf.hdr = h;
6991223637Sbz#endif
6992126258Smlaier	}
6993145836Smlaier#endif /* ALTQ */
6994126258Smlaier
6995130613Smlaier	/*
6996130613Smlaier	 * connections redirected to loopback should not match sockets
6997130613Smlaier	 * bound specifically to loopback due to security implications,
6998130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
6999130613Smlaier	 */
7000130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7001130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7002130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7003130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7004171168Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
7005223637Sbz#ifdef __FreeBSD__
7006223637Sbz		m->m_flags |= M_SKIP_FIREWALL;
7007223637Sbz#else
7008223637Sbz		m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
7009223637Sbz#endif
7010171168Smlaier
7011223637Sbz#ifdef __FreeBSD__
7012223637Sbz	if (action == PF_PASS && r->divert.port &&
7013223637Sbz	    ip_divert_ptr != NULL && !PACKET_LOOPED()) {
7014223637Sbz
7015223637Sbz		ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
7016223637Sbz				sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
7017223637Sbz		if (ipfwtag != NULL) {
7018225171Sbz			((struct ipfw_rule_ref *)(ipfwtag+1))->info =
7019225171Sbz			    ntohs(r->divert.port);
7020223637Sbz			((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
7021223637Sbz
7022223637Sbz			m_tag_prepend(m, ipfwtag);
7023223637Sbz
7024223637Sbz			PF_UNLOCK();
7025223637Sbz
7026223637Sbz			if (m->m_flags & M_FASTFWD_OURS) {
7027223637Sbz				pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT;
7028223637Sbz				m->m_flags &= ~M_FASTFWD_OURS;
7029223637Sbz			}
7030223637Sbz
7031223637Sbz			ip_divert_ptr(*m0,
7032223637Sbz				dir ==  PF_IN ? DIR_IN : DIR_OUT);
7033223637Sbz			*m0 = NULL;
7034223637Sbz			return (action);
7035223637Sbz		} else {
7036223637Sbz			/* XXX: ipfw has the same behaviour! */
7037223637Sbz			action = PF_DROP;
7038223637Sbz			REASON_SET(&reason, PFRES_MEMORY);
7039223637Sbz			log = 1;
7040223637Sbz			DPFPRINTF(PF_DEBUG_MISC,
7041223637Sbz			    ("pf: failed to allocate divert tag\n"));
7042223637Sbz		}
7043223637Sbz	}
7044223637Sbz#else
7045223637Sbz	if (dir == PF_IN && action == PF_PASS && r->divert.port) {
7046223637Sbz		struct pf_divert *divert;
7047223637Sbz
7048223637Sbz		if ((divert = pf_get_divert(m))) {
7049223637Sbz			m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED;
7050223637Sbz			divert->port = r->divert.port;
7051223637Sbz			divert->addr.ipv4 = r->divert.addr.v4;
7052223637Sbz		}
7053223637Sbz	}
7054223637Sbz#endif
7055223637Sbz
7056171168Smlaier	if (log) {
7057171168Smlaier		struct pf_rule *lr;
7058171168Smlaier
7059171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7060171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7061171168Smlaier			lr = s->nat_rule.ptr;
7062171168Smlaier		else
7063171168Smlaier			lr = r;
7064171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
7065171168Smlaier		    &pd);
7066130613Smlaier	}
7067130613Smlaier
7068130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7069130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
7070130613Smlaier
7071130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7072171168Smlaier		dirndx = (dir == PF_OUT);
7073171168Smlaier		r->packets[dirndx]++;
7074171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7075130613Smlaier		if (a != NULL) {
7076171168Smlaier			a->packets[dirndx]++;
7077171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7078130613Smlaier		}
7079130613Smlaier		if (s != NULL) {
7080130613Smlaier			if (s->nat_rule.ptr != NULL) {
7081171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7082171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7083130613Smlaier			}
7084130613Smlaier			if (s->src_node != NULL) {
7085171168Smlaier				s->src_node->packets[dirndx]++;
7086171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7087130613Smlaier			}
7088130613Smlaier			if (s->nat_src_node != NULL) {
7089171168Smlaier				s->nat_src_node->packets[dirndx]++;
7090171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7091130613Smlaier			}
7092171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7093171168Smlaier			s->packets[dirndx]++;
7094171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7095130613Smlaier		}
7096130613Smlaier		tr = r;
7097130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7098223637Sbz#ifdef __FreeBSD__
7099223637Sbz		if (nr != NULL && r == &V_pf_default_rule)
7100223637Sbz#else
7101223637Sbz		if (nr != NULL && r == &pf_default_rule)
7102223637Sbz#endif
7103223637Sbz			tr = nr;
7104130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7105223637Sbz			pfr_update_stats(tr->src.addr.p.tbl,
7106223637Sbz			    (s == NULL) ? pd.src :
7107223637Sbz			    &s->key[(s->direction == PF_IN)]->
7108223637Sbz				addr[(s->direction == PF_OUT)],
7109223637Sbz			    pd.af, pd.tot_len, dir == PF_OUT,
7110223637Sbz			    r->action == PF_PASS, tr->src.neg);
7111130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7112223637Sbz			pfr_update_stats(tr->dst.addr.p.tbl,
7113223637Sbz			    (s == NULL) ? pd.dst :
7114223637Sbz			    &s->key[(s->direction == PF_IN)]->
7115223637Sbz				addr[(s->direction == PF_IN)],
7116223637Sbz			    pd.af, pd.tot_len, dir == PF_OUT,
7117223637Sbz			    r->action == PF_PASS, tr->dst.neg);
7118130613Smlaier	}
7119130613Smlaier
7120223637Sbz	switch (action) {
7121223637Sbz	case PF_SYNPROXY_DROP:
7122126258Smlaier		m_freem(*m0);
7123223637Sbz	case PF_DEFER:
7124126258Smlaier		*m0 = NULL;
7125126258Smlaier		action = PF_PASS;
7126223637Sbz		break;
7127223637Sbz	default:
7128126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
7129223637Sbz		if (r->rt)
7130223637Sbz			pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
7131223637Sbz		break;
7132223637Sbz	}
7133127145Smlaier#ifdef __FreeBSD__
7134126261Smlaier	PF_UNLOCK();
7135126261Smlaier#endif
7136126258Smlaier	return (action);
7137126258Smlaier}
7138126258Smlaier#endif /* INET */
7139126258Smlaier
7140126258Smlaier#ifdef INET6
7141126258Smlaierint
7142135920Smlaier#ifdef __FreeBSD__
7143145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7144145836Smlaier    struct ether_header *eh, struct inpcb *inp)
7145135920Smlaier#else
7146145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7147145836Smlaier    struct ether_header *eh)
7148135920Smlaier#endif
7149126258Smlaier{
7150130613Smlaier	struct pfi_kif		*kif;
7151130613Smlaier	u_short			 action, reason = 0, log = 0;
7152171168Smlaier	struct mbuf		*m = *m0, *n = NULL;
7153223637Sbz#ifdef __FreeBSD__
7154223637Sbz	struct ip6_hdr		*h = NULL;
7155223637Sbz	struct pf_rule		*a = NULL, *r = &V_pf_default_rule, *tr, *nr;
7156223637Sbz#else
7157171168Smlaier	struct ip6_hdr		*h;
7158130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
7159223637Sbz#endif
7160130613Smlaier	struct pf_state		*s = NULL;
7161130613Smlaier	struct pf_ruleset	*ruleset = NULL;
7162130613Smlaier	struct pf_pdesc		 pd;
7163169843Sdhartmei	int			 off, terminal = 0, dirndx, rh_cnt = 0;
7164126258Smlaier
7165127145Smlaier#ifdef __FreeBSD__
7166126261Smlaier	PF_LOCK();
7167223637Sbz	if (!V_pf_status.running) {
7168126261Smlaier		PF_UNLOCK();
7169126258Smlaier		return (PF_PASS);
7170126261Smlaier	}
7171223637Sbz#else
7172223637Sbz	if (!pf_status.running)
7173223637Sbz		return (PF_PASS);
7174171168Smlaier#endif
7175126258Smlaier
7176171168Smlaier	memset(&pd, 0, sizeof(pd));
7177223637Sbz#ifdef __FreeBSD__
7178171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
7179171168Smlaier		PF_UNLOCK();
7180171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7181223637Sbz		    ("pf_test: pf_get_mtag returned NULL\n"));
7182171168Smlaier		return (PF_DROP);
7183171168Smlaier	}
7184223637Sbz#endif
7185223637Sbz#ifndef __FreeBSD__
7186145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
7187223637Sbz		kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
7188223637Sbz	else
7189145836Smlaier#endif
7190223637Sbz		kif = (struct pfi_kif *)ifp->if_pf_kif;
7191145836Smlaier
7192130613Smlaier	if (kif == NULL) {
7193130613Smlaier#ifdef __FreeBSD__
7194130613Smlaier		PF_UNLOCK();
7195130613Smlaier#endif
7196145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7197145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
7198130613Smlaier		return (PF_DROP);
7199130613Smlaier	}
7200223637Sbz	if (kif->pfik_flags & PFI_IFLAG_SKIP)
7201145836Smlaier#ifdef __FreeBSD__
7202223637Sbz	{
7203145836Smlaier		PF_UNLOCK();
7204145836Smlaier#endif
7205145836Smlaier		return (PF_PASS);
7206223637Sbz#ifdef __FreeBSD__
7207145836Smlaier	}
7208223637Sbz#endif
7209130613Smlaier
7210130613Smlaier#ifdef __FreeBSD__
7211126261Smlaier	M_ASSERTPKTHDR(m);
7212126261Smlaier#else
7213126258Smlaier#ifdef DIAGNOSTIC
7214126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
7215145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
7216145836Smlaier#endif /* DIAGNOSTIC */
7217126258Smlaier#endif
7218126258Smlaier
7219126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
7220126258Smlaier		action = PF_DROP;
7221126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
7222126258Smlaier		log = 1;
7223126258Smlaier		goto done;
7224126258Smlaier	}
7225126258Smlaier
7226223637Sbz#ifdef __FreeBSD__
7227227898Sbz	if (pd.pf_mtag->flags & PF_TAG_GENERATED) {
7228227898Sbz		PF_UNLOCK();
7229223637Sbz#else
7230223637Sbz	if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
7231223637Sbz#endif
7232223637Sbz		return (PF_PASS);
7233227898Sbz#ifdef __FreeBSD__
7234227898Sbz	}
7235227898Sbz#endif
7236223637Sbz
7237126258Smlaier	/* We do IP header normalization and packet reassembly here */
7238145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
7239126258Smlaier		action = PF_DROP;
7240126258Smlaier		goto done;
7241126258Smlaier	}
7242223637Sbz	m = *m0;	/* pf_normalize messes with m0 */
7243126258Smlaier	h = mtod(m, struct ip6_hdr *);
7244126258Smlaier
7245169843Sdhartmei#if 1
7246169843Sdhartmei	/*
7247169843Sdhartmei	 * we do not support jumbogram yet.  if we keep going, zero ip6_plen
7248169843Sdhartmei	 * will do something bad, so drop the packet for now.
7249169843Sdhartmei	 */
7250169843Sdhartmei	if (htons(h->ip6_plen) == 0) {
7251169843Sdhartmei		action = PF_DROP;
7252169843Sdhartmei		REASON_SET(&reason, PFRES_NORM);	/*XXX*/
7253169843Sdhartmei		goto done;
7254169843Sdhartmei	}
7255169843Sdhartmei#endif
7256169843Sdhartmei
7257126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
7258126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
7259223637Sbz	pd.sport = pd.dport = NULL;
7260126258Smlaier	pd.ip_sum = NULL;
7261223637Sbz	pd.proto_sum = NULL;
7262223637Sbz	pd.dir = dir;
7263223637Sbz	pd.sidx = (dir == PF_IN) ? 0 : 1;
7264223637Sbz	pd.didx = (dir == PF_IN) ? 1 : 0;
7265126258Smlaier	pd.af = AF_INET6;
7266126258Smlaier	pd.tos = 0;
7267126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
7268145836Smlaier	pd.eh = eh;
7269126258Smlaier
7270126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
7271126258Smlaier	pd.proto = h->ip6_nxt;
7272126258Smlaier	do {
7273126258Smlaier		switch (pd.proto) {
7274126258Smlaier		case IPPROTO_FRAGMENT:
7275130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
7276126258Smlaier			    &pd, &a, &ruleset);
7277126258Smlaier			if (action == PF_DROP)
7278126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
7279126258Smlaier			goto done;
7280169843Sdhartmei		case IPPROTO_ROUTING: {
7281169843Sdhartmei			struct ip6_rthdr rthdr;
7282169843Sdhartmei
7283169843Sdhartmei			if (rh_cnt++) {
7284169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7285169843Sdhartmei				    ("pf: IPv6 more than one rthdr\n"));
7286169843Sdhartmei				action = PF_DROP;
7287169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7288169843Sdhartmei				log = 1;
7289169843Sdhartmei				goto done;
7290169843Sdhartmei			}
7291169843Sdhartmei			if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
7292169843Sdhartmei			    &reason, pd.af)) {
7293169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7294169843Sdhartmei				    ("pf: IPv6 short rthdr\n"));
7295169843Sdhartmei				action = PF_DROP;
7296169843Sdhartmei				REASON_SET(&reason, PFRES_SHORT);
7297169843Sdhartmei				log = 1;
7298169843Sdhartmei				goto done;
7299169843Sdhartmei			}
7300169843Sdhartmei			if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
7301169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7302169843Sdhartmei				    ("pf: IPv6 rthdr0\n"));
7303169843Sdhartmei				action = PF_DROP;
7304169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7305169843Sdhartmei				log = 1;
7306169843Sdhartmei				goto done;
7307169843Sdhartmei			}
7308223637Sbz			/* FALLTHROUGH */
7309169843Sdhartmei		}
7310126258Smlaier		case IPPROTO_AH:
7311126258Smlaier		case IPPROTO_HOPOPTS:
7312126258Smlaier		case IPPROTO_DSTOPTS: {
7313126258Smlaier			/* get next header and header length */
7314126258Smlaier			struct ip6_ext	opt6;
7315126258Smlaier
7316126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
7317145836Smlaier			    NULL, &reason, pd.af)) {
7318126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
7319126258Smlaier				    ("pf: IPv6 short opt\n"));
7320126258Smlaier				action = PF_DROP;
7321126258Smlaier				log = 1;
7322126258Smlaier				goto done;
7323126258Smlaier			}
7324126258Smlaier			if (pd.proto == IPPROTO_AH)
7325126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
7326126258Smlaier			else
7327126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
7328126258Smlaier			pd.proto = opt6.ip6e_nxt;
7329126258Smlaier			/* goto the next header */
7330126258Smlaier			break;
7331126258Smlaier		}
7332126258Smlaier		default:
7333126258Smlaier			terminal++;
7334126258Smlaier			break;
7335126258Smlaier		}
7336126258Smlaier	} while (!terminal);
7337126258Smlaier
7338171168Smlaier	/* if there's no routing header, use unmodified mbuf for checksumming */
7339171168Smlaier	if (!n)
7340171168Smlaier		n = m;
7341171168Smlaier
7342126258Smlaier	switch (pd.proto) {
7343126258Smlaier
7344126258Smlaier	case IPPROTO_TCP: {
7345126258Smlaier		struct tcphdr	th;
7346126258Smlaier
7347126258Smlaier		pd.hdr.tcp = &th;
7348126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
7349126258Smlaier		    &action, &reason, AF_INET6)) {
7350126258Smlaier			log = action != PF_PASS;
7351126258Smlaier			goto done;
7352126258Smlaier		}
7353126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
7354130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
7355126258Smlaier		if (action == PF_DROP)
7356130613Smlaier			goto done;
7357130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
7358126258Smlaier		    &reason);
7359126258Smlaier		if (action == PF_PASS) {
7360223637Sbz#if NPFSYNC > 0
7361223637Sbz#ifdef __FreeBSD__
7362223637Sbz			if (pfsync_update_state_ptr != NULL)
7363223637Sbz				pfsync_update_state_ptr(s);
7364223637Sbz#else
7365130613Smlaier			pfsync_update_state(s);
7366223637Sbz#endif
7367145836Smlaier#endif /* NPFSYNC */
7368126258Smlaier			r = s->rule.ptr;
7369130613Smlaier			a = s->anchor.ptr;
7370126258Smlaier			log = s->log;
7371126258Smlaier		} else if (s == NULL)
7372135920Smlaier#ifdef __FreeBSD__
7373223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
7374145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7375135920Smlaier#else
7376223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
7377145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7378135920Smlaier#endif
7379126258Smlaier		break;
7380126258Smlaier	}
7381126258Smlaier
7382126258Smlaier	case IPPROTO_UDP: {
7383126258Smlaier		struct udphdr	uh;
7384126258Smlaier
7385126258Smlaier		pd.hdr.udp = &uh;
7386126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
7387126258Smlaier		    &action, &reason, AF_INET6)) {
7388126258Smlaier			log = action != PF_PASS;
7389126258Smlaier			goto done;
7390126258Smlaier		}
7391130613Smlaier		if (uh.uh_dport == 0 ||
7392130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
7393130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
7394130613Smlaier			action = PF_DROP;
7395171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
7396130613Smlaier			goto done;
7397130613Smlaier		}
7398130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
7399126258Smlaier		if (action == PF_PASS) {
7400223637Sbz#if NPFSYNC > 0
7401223637Sbz#ifdef __FreeBSD__
7402223637Sbz			if (pfsync_update_state_ptr != NULL)
7403223637Sbz				pfsync_update_state_ptr(s);
7404223637Sbz#else
7405130613Smlaier			pfsync_update_state(s);
7406223637Sbz#endif
7407145836Smlaier#endif /* NPFSYNC */
7408126258Smlaier			r = s->rule.ptr;
7409130613Smlaier			a = s->anchor.ptr;
7410126258Smlaier			log = s->log;
7411126258Smlaier		} else if (s == NULL)
7412135920Smlaier#ifdef __FreeBSD__
7413223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
7414145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7415135920Smlaier#else
7416223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
7417145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7418135920Smlaier#endif
7419126258Smlaier		break;
7420126258Smlaier	}
7421126258Smlaier
7422223637Sbz	case IPPROTO_ICMP: {
7423223637Sbz		action = PF_DROP;
7424223637Sbz		DPFPRINTF(PF_DEBUG_MISC,
7425223637Sbz		    ("pf: dropping IPv6 packet with ICMPv4 payload\n"));
7426223637Sbz		goto done;
7427223637Sbz	}
7428223637Sbz
7429126258Smlaier	case IPPROTO_ICMPV6: {
7430126258Smlaier		struct icmp6_hdr	ih;
7431126258Smlaier
7432126258Smlaier		pd.hdr.icmp6 = &ih;
7433126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
7434126258Smlaier		    &action, &reason, AF_INET6)) {
7435126258Smlaier			log = action != PF_PASS;
7436126258Smlaier			goto done;
7437126258Smlaier		}
7438130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
7439145836Smlaier		    m, off, h, &pd, &reason);
7440126258Smlaier		if (action == PF_PASS) {
7441223637Sbz#if NPFSYNC > 0
7442223637Sbz#ifdef __FreeBSD__
7443223637Sbz			if (pfsync_update_state_ptr != NULL)
7444223637Sbz				pfsync_update_state_ptr(s);
7445223637Sbz#else
7446130613Smlaier			pfsync_update_state(s);
7447223637Sbz#endif
7448145836Smlaier#endif /* NPFSYNC */
7449126258Smlaier			r = s->rule.ptr;
7450130613Smlaier			a = s->anchor.ptr;
7451126258Smlaier			log = s->log;
7452126258Smlaier		} else if (s == NULL)
7453145836Smlaier#ifdef __FreeBSD__
7454223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
7455223637Sbz			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7456145836Smlaier#else
7457223637Sbz			action = pf_test_rule(&r, &s, dir, kif,
7458145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7459145836Smlaier#endif
7460126258Smlaier		break;
7461126258Smlaier	}
7462126258Smlaier
7463126258Smlaier	default:
7464223637Sbz		action = pf_test_state_other(&s, dir, kif, m, &pd);
7465130613Smlaier		if (action == PF_PASS) {
7466223637Sbz#if NPFSYNC > 0
7467223637Sbz#ifdef __FreeBSD__
7468223637Sbz			if (pfsync_update_state_ptr != NULL)
7469223637Sbz				pfsync_update_state_ptr(s);
7470223637Sbz#else
7471145836Smlaier			pfsync_update_state(s);
7472223637Sbz#endif
7473145836Smlaier#endif /* NPFSYNC */
7474130613Smlaier			r = s->rule.ptr;
7475130613Smlaier			a = s->anchor.ptr;
7476130613Smlaier			log = s->log;
7477130613Smlaier		} else if (s == NULL)
7478145836Smlaier#ifdef __FreeBSD__
7479223637Sbz			action = pf_test_rule(&r, &s, dir, kif, m, off, h,
7480223637Sbz			    &pd, &a, &ruleset, NULL, inp);
7481145836Smlaier#else
7482223637Sbz			action = pf_test_rule(&r, &s, dir, kif, m, off, h,
7483145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
7484145836Smlaier#endif
7485126258Smlaier		break;
7486126258Smlaier	}
7487126258Smlaier
7488126258Smlaierdone:
7489223637Sbz	if (n != m) {
7490223637Sbz		m_freem(n);
7491223637Sbz		n = NULL;
7492223637Sbz	}
7493223637Sbz
7494169843Sdhartmei	/* handle dangerous IPv6 extension headers. */
7495169843Sdhartmei	if (action == PF_PASS && rh_cnt &&
7496200930Sdelphij	    !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
7497169843Sdhartmei		action = PF_DROP;
7498169843Sdhartmei		REASON_SET(&reason, PFRES_IPOPTIONS);
7499169843Sdhartmei		log = 1;
7500169843Sdhartmei		DPFPRINTF(PF_DEBUG_MISC,
7501169843Sdhartmei		    ("pf: dropping packet with dangerous v6 headers\n"));
7502169843Sdhartmei	}
7503126258Smlaier
7504232292Sbz	if ((s && s->tag) || r->rtableid >= 0)
7505223637Sbz#ifdef __FreeBSD__
7506223637Sbz		pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag);
7507223637Sbz#else
7508223637Sbz		pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
7509223637Sbz#endif
7510145836Smlaier
7511223637Sbz	if (dir == PF_IN && s && s->key[PF_SK_STACK])
7512223637Sbz#ifdef __FreeBSD__
7513223637Sbz		pd.pf_mtag->statekey = s->key[PF_SK_STACK];
7514223637Sbz#else
7515223637Sbz		m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK];
7516223637Sbz#endif
7517223637Sbz
7518126258Smlaier#ifdef ALTQ
7519126258Smlaier	if (action == PF_PASS && r->qid) {
7520223637Sbz#ifdef __FreeBSD__
7521171168Smlaier		if (pd.tos & IPTOS_LOWDELAY)
7522171168Smlaier			pd.pf_mtag->qid = r->pqid;
7523171168Smlaier		else
7524171168Smlaier			pd.pf_mtag->qid = r->qid;
7525171168Smlaier		/* add hints for ecn */
7526171168Smlaier		pd.pf_mtag->hdr = h;
7527223637Sbz#else
7528223637Sbz		if (pd.tos & IPTOS_LOWDELAY)
7529223637Sbz			m->m_pkthdr.pf.qid = r->pqid;
7530223637Sbz		else
7531223637Sbz			m->m_pkthdr.pf.qid = r->qid;
7532223637Sbz		/* add hints for ecn */
7533223637Sbz		m->m_pkthdr.pf.hdr = h;
7534223637Sbz#endif
7535126258Smlaier	}
7536145836Smlaier#endif /* ALTQ */
7537126258Smlaier
7538130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7539130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7540130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7541130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7542171168Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
7543223637Sbz#ifdef __FreeBSD__
7544223637Sbz		m->m_flags |= M_SKIP_FIREWALL;
7545223637Sbz#else
7546223637Sbz		m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
7547223637Sbz#endif
7548171168Smlaier
7549223637Sbz#ifdef __FreeBSD__
7550223637Sbz	/* XXX: Anybody working on it?! */
7551223637Sbz	if (r->divert.port)
7552223637Sbz		printf("pf: divert(9) is not supported for IPv6\n");
7553223637Sbz#else
7554223637Sbz	if (dir == PF_IN && action == PF_PASS && r->divert.port) {
7555223637Sbz		struct pf_divert *divert;
7556223637Sbz
7557223637Sbz		if ((divert = pf_get_divert(m))) {
7558223637Sbz			m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED;
7559223637Sbz			divert->port = r->divert.port;
7560223637Sbz			divert->addr.ipv6 = r->divert.addr.v6;
7561223637Sbz		}
7562223637Sbz	}
7563223637Sbz#endif
7564223637Sbz
7565171168Smlaier	if (log) {
7566171168Smlaier		struct pf_rule *lr;
7567171168Smlaier
7568171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7569171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7570171168Smlaier			lr = s->nat_rule.ptr;
7571171168Smlaier		else
7572171168Smlaier			lr = r;
7573171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
7574171168Smlaier		    &pd);
7575130613Smlaier	}
7576130613Smlaier
7577130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7578130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
7579130613Smlaier
7580130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7581171168Smlaier		dirndx = (dir == PF_OUT);
7582171168Smlaier		r->packets[dirndx]++;
7583171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7584130613Smlaier		if (a != NULL) {
7585171168Smlaier			a->packets[dirndx]++;
7586171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7587130613Smlaier		}
7588130613Smlaier		if (s != NULL) {
7589130613Smlaier			if (s->nat_rule.ptr != NULL) {
7590171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7591171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7592130613Smlaier			}
7593130613Smlaier			if (s->src_node != NULL) {
7594171168Smlaier				s->src_node->packets[dirndx]++;
7595171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7596130613Smlaier			}
7597130613Smlaier			if (s->nat_src_node != NULL) {
7598171168Smlaier				s->nat_src_node->packets[dirndx]++;
7599171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7600130613Smlaier			}
7601171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7602171168Smlaier			s->packets[dirndx]++;
7603171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7604130613Smlaier		}
7605130613Smlaier		tr = r;
7606130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7607223637Sbz#ifdef __FreeBSD__
7608223637Sbz		if (nr != NULL && r == &V_pf_default_rule)
7609223637Sbz#else
7610223637Sbz		if (nr != NULL && r == &pf_default_rule)
7611223637Sbz#endif
7612223637Sbz			tr = nr;
7613130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7614223637Sbz			pfr_update_stats(tr->src.addr.p.tbl,
7615223637Sbz			    (s == NULL) ? pd.src :
7616223637Sbz			    &s->key[(s->direction == PF_IN)]->addr[0],
7617223637Sbz			    pd.af, pd.tot_len, dir == PF_OUT,
7618223637Sbz			    r->action == PF_PASS, tr->src.neg);
7619130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7620223637Sbz			pfr_update_stats(tr->dst.addr.p.tbl,
7621223637Sbz			    (s == NULL) ? pd.dst :
7622223637Sbz			    &s->key[(s->direction == PF_IN)]->addr[1],
7623223637Sbz			    pd.af, pd.tot_len, dir == PF_OUT,
7624223637Sbz			    r->action == PF_PASS, tr->dst.neg);
7625130613Smlaier	}
7626130613Smlaier
7627223637Sbz	switch (action) {
7628223637Sbz	case PF_SYNPROXY_DROP:
7629126258Smlaier		m_freem(*m0);
7630223637Sbz	case PF_DEFER:
7631126258Smlaier		*m0 = NULL;
7632126258Smlaier		action = PF_PASS;
7633223637Sbz		break;
7634223637Sbz	default:
7635126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7636223637Sbz		if (r->rt)
7637223637Sbz			pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
7638223637Sbz		break;
7639223637Sbz	}
7640126258Smlaier
7641127145Smlaier#ifdef __FreeBSD__
7642126261Smlaier	PF_UNLOCK();
7643126261Smlaier#endif
7644126258Smlaier	return (action);
7645126258Smlaier}
7646126258Smlaier#endif /* INET6 */
7647145836Smlaier
7648145836Smlaierint
7649145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7650145836Smlaier{
7651145836Smlaier#ifdef __FreeBSD__
7652145836Smlaier	/* XXX_IMPORT: later */
7653145836Smlaier	return (0);
7654145836Smlaier#else
7655145836Smlaier	if (ifq->ifq_congestion)
7656145836Smlaier		return (1);
7657145836Smlaier	else
7658145836Smlaier		return (0);
7659145836Smlaier#endif
7660145836Smlaier}
7661223637Sbz
7662223637Sbz/*
7663223637Sbz * must be called whenever any addressing information such as
7664223637Sbz * address, port, protocol has changed
7665223637Sbz */
7666223637Sbzvoid
7667223637Sbzpf_pkt_addr_changed(struct mbuf *m)
7668223637Sbz{
7669223637Sbz#ifdef __FreeBSD__
7670223637Sbz	struct pf_mtag	*pf_tag;
7671223637Sbz
7672223637Sbz	if ((pf_tag = pf_find_mtag(m)) != NULL)
7673223637Sbz		pf_tag->statekey = NULL;
7674223637Sbz#else
7675223637Sbz	m->m_pkthdr.pf.statekey = NULL;
7676223637Sbz#endif
7677223637Sbz}
7678