]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c
netpfil: Use accessor functions and named constants for all tcphdr flags
[FreeBSD/FreeBSD.git] / sys / netpfil / ipfilter / netinet / ip_fil_freebsd.c
1
2 /*
3  * Copyright (C) 2012 by Darren Reed.
4  *
5  * See the IPFILTER.LICENCE file for details on licencing.
6  */
7
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL  1
12 # define        _KERNEL 1
13 #endif
14 #if defined(__FreeBSD__) && \
15     !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
16 # include "opt_inet6.h"
17 #endif
18 #include <sys/param.h>
19 #include <sys/eventhandler.h>
20 #include <sys/conf.h>
21 #include <sys/errno.h>
22 #include <sys/types.h>
23 #include <sys/file.h>
24 #include <sys/fcntl.h>
25 #include <sys/filio.h>
26 #include <sys/time.h>
27 #include <sys/systm.h>
28 #include <sys/dirent.h>
29 #if defined(__FreeBSD__)
30 # include <sys/jail.h>
31 #endif
32 #include <sys/malloc.h>
33 #include <sys/mbuf.h>
34 #include <sys/sockopt.h>
35 #include <sys/socket.h>
36 #include <sys/selinfo.h>
37 #include <net/if.h>
38 #include <net/if_var.h>
39 #include <net/netisr.h>
40 #include <net/route.h>
41 #include <net/route/nhop.h>
42 #include <netinet/in.h>
43 #include <netinet/in_fib.h>
44 #include <netinet/in_pcb.h>
45 #include <netinet/in_var.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
48 #include <netinet/ip_var.h>
49 #include <netinet/tcp.h>
50 #include <netinet/tcp_var.h>
51 #include <net/vnet.h>
52 #include <netinet/udp.h>
53 #include <netinet/tcpip.h>
54 #include <netinet/ip_icmp.h>
55 #include "netinet/ip_compat.h"
56 #ifdef USE_INET6
57 # include <netinet/icmp6.h>
58 #endif
59 #include "netinet/ip_fil.h"
60 #include "netinet/ip_nat.h"
61 #include "netinet/ip_frag.h"
62 #include "netinet/ip_state.h"
63 #include "netinet/ip_proxy.h"
64 #include "netinet/ip_auth.h"
65 #include "netinet/ip_sync.h"
66 #include "netinet/ip_lookup.h"
67 #include "netinet/ip_dstlist.h"
68 #ifdef  IPFILTER_SCAN
69 # include "netinet/ip_scan.h"
70 #endif
71 #include "netinet/ip_pool.h"
72 #include <sys/malloc.h>
73 #include <sys/kernel.h>
74 #ifdef CSUM_DATA_VALID
75 # include <machine/in_cksum.h>
76 #endif
77 extern  int     ip_optcopy(struct ip *, struct ip *);
78
79 #ifdef IPFILTER_M_IPFILTER
80 MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
81 #endif
82
83
84 static  int     ipf_send_ip(fr_info_t *, mb_t *);
85 static void     ipf_timer_func(void *arg);
86
87 VNET_DEFINE(ipf_main_softc_t, ipfmain) = {
88         .ipf_running            = -2,
89 };
90 #define V_ipfmain               VNET(ipfmain)
91
92 #include <sys/conf.h>
93 #include <net/pfil.h>
94
95 VNET_DEFINE_STATIC(eventhandler_tag, ipf_arrivetag);
96 VNET_DEFINE_STATIC(eventhandler_tag, ipf_departtag);
97 #define V_ipf_arrivetag         VNET(ipf_arrivetag)
98 #define V_ipf_departtag         VNET(ipf_departtag)
99 #if 0
100 /*
101  * Disable the "cloner" event handler;  we are getting interface
102  * events before the firewall is fully initiallized and also no vnet
103  * information thus leading to uninitialised memory accesses.
104  * In addition it is unclear why we need it in first place.
105  * If it turns out to be needed, well need a dedicated event handler
106  * for it to deal with the ifc and the correct vnet.
107  */
108 VNET_DEFINE_STATIC(eventhandler_tag, ipf_clonetag);
109 #define V_ipf_clonetag          VNET(ipf_clonetag)
110 #endif
111
112 static void ipf_ifevent(void *arg, struct ifnet *ifp);
113
114 static void ipf_ifevent(void *arg, struct ifnet *ifp)
115 {
116
117         CURVNET_SET(ifp->if_vnet);
118         if (V_ipfmain.ipf_running > 0)
119                 ipf_sync(&V_ipfmain, NULL);
120         CURVNET_RESTORE();
121 }
122
123
124
125 static pfil_return_t
126 ipf_check_wrapper(struct mbuf **mp, struct ifnet *ifp, int flags,
127     void *ruleset __unused, struct inpcb *inp)
128 {
129         struct ip *ip = mtod(*mp, struct ip *);
130         pfil_return_t rv;
131
132         CURVNET_SET(ifp->if_vnet);
133         rv = ipf_check(&V_ipfmain, ip, ip->ip_hl << 2, ifp,
134             !!(flags & PFIL_OUT), mp);
135         CURVNET_RESTORE();
136         return (rv == 0 ? PFIL_PASS : PFIL_DROPPED);
137 }
138
139 #ifdef USE_INET6
140 static pfil_return_t
141 ipf_check_wrapper6(struct mbuf **mp, struct ifnet *ifp, int flags,
142     void *ruleset __unused, struct inpcb *inp)
143 {
144         pfil_return_t rv;
145
146         CURVNET_SET(ifp->if_vnet);
147         rv = ipf_check(&V_ipfmain, mtod(*mp, struct ip *),
148             sizeof(struct ip6_hdr), ifp, !!(flags & PFIL_OUT), mp);
149         CURVNET_RESTORE();
150
151         return (rv == 0 ? PFIL_PASS : PFIL_DROPPED);
152 }
153 # endif
154 #if     defined(IPFILTER_LKM)
155 int ipf_identify(char *s)
156 {
157         if (strcmp(s, "ipl") == 0)
158                 return (1);
159         return (0);
160 }
161 #endif /* IPFILTER_LKM */
162
163
164 static void
165 ipf_timer_func(void *arg)
166 {
167         ipf_main_softc_t *softc = arg;
168         SPL_INT(s);
169
170         SPL_NET(s);
171         READ_ENTER(&softc->ipf_global);
172
173         if (softc->ipf_running > 0)
174                 ipf_slowtimer(softc);
175
176         if (softc->ipf_running == -1 || softc->ipf_running == 1) {
177 #if 0
178                 softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
179 #endif
180                 callout_init(&softc->ipf_slow_ch, 1);
181                 callout_reset(&softc->ipf_slow_ch,
182                         (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
183                         ipf_timer_func, softc);
184         }
185         RWLOCK_EXIT(&softc->ipf_global);
186         SPL_X(s);
187 }
188
189
190 int
191 ipfattach(ipf_main_softc_t *softc)
192 {
193 #ifdef USE_SPL
194         int s;
195 #endif
196
197         SPL_NET(s);
198         if (softc->ipf_running > 0) {
199                 SPL_X(s);
200                 return (EBUSY);
201         }
202
203         if (ipf_init_all(softc) < 0) {
204                 SPL_X(s);
205                 return (EIO);
206         }
207
208
209         bzero((char *)V_ipfmain.ipf_selwait, sizeof(V_ipfmain.ipf_selwait));
210         softc->ipf_running = 1;
211
212         if (softc->ipf_control_forwarding & 1)
213                 V_ipforwarding = 1;
214
215         SPL_X(s);
216 #if 0
217         softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
218                                      (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
219 #endif
220         callout_init(&softc->ipf_slow_ch, 1);
221         callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
222                 ipf_timer_func, softc);
223         return (0);
224 }
225
226
227 /*
228  * Disable the filter by removing the hooks from the IP input/output
229  * stream.
230  */
231 int
232 ipfdetach(ipf_main_softc_t *softc)
233 {
234 #ifdef USE_SPL
235         int s;
236 #endif
237
238         if (softc->ipf_control_forwarding & 2)
239                 V_ipforwarding = 0;
240
241         SPL_NET(s);
242
243 #if 0
244         if (softc->ipf_slow_ch.callout != NULL)
245                 untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
246         bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
247 #endif
248         callout_drain(&softc->ipf_slow_ch);
249
250         ipf_fini_all(softc);
251
252         softc->ipf_running = -2;
253
254         SPL_X(s);
255
256         return (0);
257 }
258
259
260 /*
261  * Filter ioctl interface.
262  */
263 int
264 ipfioctl(struct cdev *dev, ioctlcmd_t cmd, caddr_t data,
265         int mode, struct thread *p)
266 #define p_cred  td_ucred
267 #define p_uid   td_ucred->cr_ruid
268 {
269         int error = 0, unit = 0;
270         SPL_INT(s);
271
272         CURVNET_SET(TD_TO_VNET(p));
273         if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
274         {
275                 V_ipfmain.ipf_interror = 130001;
276                 CURVNET_RESTORE();
277                 return (EPERM);
278         }
279
280         if (jailed_without_vnet(p->p_cred)) {
281                 V_ipfmain.ipf_interror = 130018;
282                 CURVNET_RESTORE();
283                 return (EOPNOTSUPP);
284         }
285
286         unit = GET_MINOR(dev);
287         if ((IPL_LOGMAX < unit) || (unit < 0)) {
288                 V_ipfmain.ipf_interror = 130002;
289                 CURVNET_RESTORE();
290                 return (ENXIO);
291         }
292
293         if (V_ipfmain.ipf_running <= 0) {
294                 if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
295                         V_ipfmain.ipf_interror = 130003;
296                         CURVNET_RESTORE();
297                         return (EIO);
298                 }
299                 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
300                     cmd != SIOCIPFSET && cmd != SIOCFRENB &&
301                     cmd != SIOCGETFS && cmd != SIOCGETFF &&
302                     cmd != SIOCIPFINTERROR) {
303                         V_ipfmain.ipf_interror = 130004;
304                         CURVNET_RESTORE();
305                         return (EIO);
306                 }
307         }
308
309         SPL_NET(s);
310
311         error = ipf_ioctlswitch(&V_ipfmain, unit, data, cmd, mode, p->p_uid, p);
312         CURVNET_RESTORE();
313         if (error != -1) {
314                 SPL_X(s);
315                 return (error);
316         }
317
318         SPL_X(s);
319
320         return (error);
321 }
322
323
324 /*
325  * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
326  * requires a large amount of setting up and isn't any more efficient.
327  */
328 int
329 ipf_send_reset(fr_info_t *fin)
330 {
331         struct tcphdr *tcp, *tcp2;
332         int tlen = 0, hlen;
333         struct mbuf *m;
334 #ifdef USE_INET6
335         ip6_t *ip6;
336 #endif
337         ip_t *ip;
338
339         tcp = fin->fin_dp;
340         if (tcp->th_flags & TH_RST)
341                 return (-1);            /* feedback loop */
342
343         if (ipf_checkl4sum(fin) == -1)
344                 return (-1);
345
346         tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
347                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
348                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
349
350 #ifdef USE_INET6
351         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
352 #else
353         hlen = sizeof(ip_t);
354 #endif
355 #ifdef MGETHDR
356         MGETHDR(m, M_NOWAIT, MT_HEADER);
357 #else
358         MGET(m, M_NOWAIT, MT_HEADER);
359 #endif
360         if (m == NULL)
361                 return (-1);
362         if (sizeof(*tcp2) + hlen > MLEN) {
363                 if (!(MCLGET(m, M_NOWAIT))) {
364                         FREE_MB_T(m);
365                         return (-1);
366                 }
367         }
368
369         m->m_len = sizeof(*tcp2) + hlen;
370         m->m_data += max_linkhdr;
371         m->m_pkthdr.len = m->m_len;
372         m->m_pkthdr.rcvif = (struct ifnet *)0;
373         ip = mtod(m, struct ip *);
374         bzero((char *)ip, hlen);
375 #ifdef USE_INET6
376         ip6 = (ip6_t *)ip;
377 #endif
378         tcp2 = (struct tcphdr *)((char *)ip + hlen);
379         tcp2->th_sport = tcp->th_dport;
380         tcp2->th_dport = tcp->th_sport;
381
382         if (tcp_get_flags(tcp) & TH_ACK) {
383                 tcp2->th_seq = tcp->th_ack;
384                 tcp_set_flags(tcp2, TH_RST);
385                 tcp2->th_ack = 0;
386         } else {
387                 tcp2->th_seq = 0;
388                 tcp2->th_ack = ntohl(tcp->th_seq);
389                 tcp2->th_ack += tlen;
390                 tcp2->th_ack = htonl(tcp2->th_ack);
391                 tcp_set_flags(tcp2, TH_RST|TH_ACK);
392         }
393         TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
394         tcp2->th_win = tcp->th_win;
395         tcp2->th_sum = 0;
396         tcp2->th_urp = 0;
397
398 #ifdef USE_INET6
399         if (fin->fin_v == 6) {
400                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
401                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
402                 ip6->ip6_nxt = IPPROTO_TCP;
403                 ip6->ip6_hlim = 0;
404                 ip6->ip6_src = fin->fin_dst6.in6;
405                 ip6->ip6_dst = fin->fin_src6.in6;
406                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
407                                          sizeof(*ip6), sizeof(*tcp2));
408                 return (ipf_send_ip(fin, m));
409         }
410 #endif
411         ip->ip_p = IPPROTO_TCP;
412         ip->ip_len = htons(sizeof(struct tcphdr));
413         ip->ip_src.s_addr = fin->fin_daddr;
414         ip->ip_dst.s_addr = fin->fin_saddr;
415         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
416         ip->ip_len = htons(hlen + sizeof(*tcp2));
417         return (ipf_send_ip(fin, m));
418 }
419
420
421 /*
422  * ip_len must be in network byte order when called.
423  */
424 static int
425 ipf_send_ip(fr_info_t *fin, mb_t *m)
426 {
427         fr_info_t fnew;
428         ip_t *ip, *oip;
429         int hlen;
430
431         ip = mtod(m, ip_t *);
432         bzero((char *)&fnew, sizeof(fnew));
433         fnew.fin_main_soft = fin->fin_main_soft;
434
435         IP_V_A(ip, fin->fin_v);
436         switch (fin->fin_v)
437         {
438         case 4 :
439                 oip = fin->fin_ip;
440                 hlen = sizeof(*oip);
441                 fnew.fin_v = 4;
442                 fnew.fin_p = ip->ip_p;
443                 fnew.fin_plen = ntohs(ip->ip_len);
444                 IP_HL_A(ip, sizeof(*oip) >> 2);
445                 ip->ip_tos = oip->ip_tos;
446                 ip->ip_id = fin->fin_ip->ip_id;
447                 ip->ip_off = htons(V_path_mtu_discovery ? IP_DF : 0);
448                 ip->ip_ttl = V_ip_defttl;
449                 ip->ip_sum = 0;
450                 break;
451 #ifdef USE_INET6
452         case 6 :
453         {
454                 ip6_t *ip6 = (ip6_t *)ip;
455
456                 ip6->ip6_vfc = 0x60;
457                 ip6->ip6_hlim = IPDEFTTL;
458
459                 hlen = sizeof(*ip6);
460                 fnew.fin_p = ip6->ip6_nxt;
461                 fnew.fin_v = 6;
462                 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
463                 break;
464         }
465 #endif
466         default :
467                 return (EINVAL);
468         }
469 #ifdef IPSEC_SUPPORT
470         m->m_pkthdr.rcvif = NULL;
471 #endif
472
473         fnew.fin_ifp = fin->fin_ifp;
474         fnew.fin_flx = FI_NOCKSUM;
475         fnew.fin_m = m;
476         fnew.fin_ip = ip;
477         fnew.fin_mp = &m;
478         fnew.fin_hlen = hlen;
479         fnew.fin_dp = (char *)ip + hlen;
480         (void) ipf_makefrip(hlen, ip, &fnew);
481
482         return (ipf_fastroute(m, &m, &fnew, NULL));
483 }
484
485
486 int
487 ipf_send_icmp_err(int type, fr_info_t *fin, int dst)
488 {
489         int err, hlen, xtra, iclen, ohlen, avail, code;
490         struct in_addr dst4;
491         struct icmp *icmp;
492         struct mbuf *m;
493         i6addr_t dst6;
494         void *ifp;
495 #ifdef USE_INET6
496         ip6_t *ip6;
497 #endif
498         ip_t *ip, *ip2;
499
500         if ((type < 0) || (type >= ICMP_MAXTYPE))
501                 return (-1);
502
503         code = fin->fin_icode;
504 #ifdef USE_INET6
505         /* See NetBSD ip_fil_netbsd.c r1.4: */
506         if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
507                 return (-1);
508 #endif
509
510         if (ipf_checkl4sum(fin) == -1)
511                 return (-1);
512 #ifdef MGETHDR
513         MGETHDR(m, M_NOWAIT, MT_HEADER);
514 #else
515         MGET(m, M_NOWAIT, MT_HEADER);
516 #endif
517         if (m == NULL)
518                 return (-1);
519         avail = MHLEN;
520
521         xtra = 0;
522         hlen = 0;
523         ohlen = 0;
524         dst4.s_addr = 0;
525         ifp = fin->fin_ifp;
526         if (fin->fin_v == 4) {
527                 if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
528                         switch (ntohs(fin->fin_data[0]) >> 8)
529                         {
530                         case ICMP_ECHO :
531                         case ICMP_TSTAMP :
532                         case ICMP_IREQ :
533                         case ICMP_MASKREQ :
534                                 break;
535                         default :
536                                 FREE_MB_T(m);
537                                 return (0);
538                         }
539
540                 if (dst == 0) {
541                         if (ipf_ifpaddr(&V_ipfmain, 4, FRI_NORMAL, ifp,
542                                         &dst6, NULL) == -1) {
543                                 FREE_MB_T(m);
544                                 return (-1);
545                         }
546                         dst4 = dst6.in4;
547                 } else
548                         dst4.s_addr = fin->fin_daddr;
549
550                 hlen = sizeof(ip_t);
551                 ohlen = fin->fin_hlen;
552                 iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
553                 if (fin->fin_hlen < fin->fin_plen)
554                         xtra = MIN(fin->fin_dlen, 8);
555                 else
556                         xtra = 0;
557         }
558
559 #ifdef USE_INET6
560         else if (fin->fin_v == 6) {
561                 hlen = sizeof(ip6_t);
562                 ohlen = sizeof(ip6_t);
563                 iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
564                 type = icmptoicmp6types[type];
565                 if (type == ICMP6_DST_UNREACH)
566                         code = icmptoicmp6unreach[code];
567
568                 if (iclen + max_linkhdr + fin->fin_plen > avail) {
569                         if (!(MCLGET(m, M_NOWAIT))) {
570                                 FREE_MB_T(m);
571                                 return (-1);
572                         }
573                         avail = MCLBYTES;
574                 }
575                 xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
576                 xtra = MIN(xtra, IPV6_MMTU - iclen);
577                 if (dst == 0) {
578                         if (ipf_ifpaddr(&V_ipfmain, 6, FRI_NORMAL, ifp,
579                                         &dst6, NULL) == -1) {
580                                 FREE_MB_T(m);
581                                 return (-1);
582                         }
583                 } else
584                         dst6 = fin->fin_dst6;
585         }
586 #endif
587         else {
588                 FREE_MB_T(m);
589                 return (-1);
590         }
591
592         avail -= (max_linkhdr + iclen);
593         if (avail < 0) {
594                 FREE_MB_T(m);
595                 return (-1);
596         }
597         if (xtra > avail)
598                 xtra = avail;
599         iclen += xtra;
600         m->m_data += max_linkhdr;
601         m->m_pkthdr.rcvif = (struct ifnet *)0;
602         m->m_pkthdr.len = iclen;
603         m->m_len = iclen;
604         ip = mtod(m, ip_t *);
605         icmp = (struct icmp *)((char *)ip + hlen);
606         ip2 = (ip_t *)&icmp->icmp_ip;
607
608         icmp->icmp_type = type;
609         icmp->icmp_code = fin->fin_icode;
610         icmp->icmp_cksum = 0;
611 #ifdef icmp_nextmtu
612         if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
613                 if (fin->fin_mtu != 0) {
614                         icmp->icmp_nextmtu = htons(fin->fin_mtu);
615
616                 } else if (ifp != NULL) {
617                         icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
618
619                 } else {        /* make up a number... */
620                         icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
621                 }
622         }
623 #endif
624
625         bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
626
627 #ifdef USE_INET6
628         ip6 = (ip6_t *)ip;
629         if (fin->fin_v == 6) {
630                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
631                 ip6->ip6_plen = htons(iclen - hlen);
632                 ip6->ip6_nxt = IPPROTO_ICMPV6;
633                 ip6->ip6_hlim = 0;
634                 ip6->ip6_src = dst6.in6;
635                 ip6->ip6_dst = fin->fin_src6.in6;
636                 if (xtra > 0)
637                         bcopy((char *)fin->fin_ip + ohlen,
638                               (char *)&icmp->icmp_ip + ohlen, xtra);
639                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
640                                              sizeof(*ip6), iclen - hlen);
641         } else
642 #endif
643         {
644                 ip->ip_p = IPPROTO_ICMP;
645                 ip->ip_src.s_addr = dst4.s_addr;
646                 ip->ip_dst.s_addr = fin->fin_saddr;
647
648                 if (xtra > 0)
649                         bcopy((char *)fin->fin_ip + ohlen,
650                               (char *)&icmp->icmp_ip + ohlen, xtra);
651                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
652                                              sizeof(*icmp) + 8);
653                 ip->ip_len = htons(iclen);
654                 ip->ip_p = IPPROTO_ICMP;
655         }
656         err = ipf_send_ip(fin, m);
657         return (err);
658 }
659
660
661
662
663 /*
664  * m0 - pointer to mbuf where the IP packet starts
665  * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
666  */
667 int
668 ipf_fastroute(mb_t *m0, mb_t **mpp, fr_info_t *fin, frdest_t *fdp)
669 {
670         register struct ip *ip, *mhip;
671         register struct mbuf *m = *mpp;
672         int len, off, error = 0, hlen, code;
673         struct ifnet *ifp, *sifp;
674         struct route ro;
675         struct sockaddr_in *dst;
676         const struct sockaddr *gw;
677         struct nhop_object *nh;
678         u_long fibnum = 0;
679         u_short ip_off;
680         frdest_t node;
681         frentry_t *fr;
682
683 #ifdef M_WRITABLE
684         /*
685         * HOT FIX/KLUDGE:
686         *
687         * If the mbuf we're about to send is not writable (because of
688         * a cluster reference, for example) we'll need to make a copy
689         * of it since this routine modifies the contents.
690         *
691         * If you have non-crappy network hardware that can transmit data
692         * from the mbuf, rather than making a copy, this is gonna be a
693         * problem.
694         */
695         if (M_WRITABLE(m) == 0) {
696                 m0 = m_dup(m, M_NOWAIT);
697                 if (m0 != NULL) {
698                         FREE_MB_T(m);
699                         m = m0;
700                         *mpp = m;
701                 } else {
702                         error = ENOBUFS;
703                         FREE_MB_T(m);
704                         goto done;
705                 }
706         }
707 #endif
708
709 #ifdef USE_INET6
710         if (fin->fin_v == 6) {
711                 /*
712                  * currently "to <if>" and "to <if>:ip#" are not supported
713                  * for IPv6
714                  */
715                 return (ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL));
716         }
717 #endif
718
719         hlen = fin->fin_hlen;
720         ip = mtod(m0, struct ip *);
721         ifp = NULL;
722
723         /*
724          * Route packet.
725          */
726         bzero(&ro, sizeof (ro));
727         dst = (struct sockaddr_in *)&ro.ro_dst;
728         dst->sin_family = AF_INET;
729         dst->sin_addr = ip->ip_dst;
730         dst->sin_len = sizeof(dst);
731         gw = (const struct sockaddr *)dst;
732
733         fr = fin->fin_fr;
734         if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
735             (fdp->fd_type == FRD_DSTLIST)) {
736                 if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
737                         fdp = &node;
738         }
739
740         if (fdp != NULL)
741                 ifp = fdp->fd_ptr;
742         else
743                 ifp = fin->fin_ifp;
744
745         if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
746                 error = -2;
747                 goto bad;
748         }
749
750         if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
751                 dst->sin_addr = fdp->fd_ip;
752
753         fibnum = M_GETFIB(m0);
754         NET_EPOCH_ASSERT();
755         nh = fib4_lookup(fibnum, dst->sin_addr, 0, NHR_NONE, 0);
756         if (nh == NULL) {
757                 if (in_localaddr(ip->ip_dst))
758                         error = EHOSTUNREACH;
759                 else
760                         error = ENETUNREACH;
761                 goto bad;
762         }
763
764         if (ifp == NULL)
765                 ifp = nh->nh_ifp;
766         if (nh->nh_flags & NHF_GATEWAY) {
767                 gw = &nh->gw_sa;
768                 ro.ro_flags |= RT_HAS_GW;
769         }
770
771         /*
772          * For input packets which are being "fastrouted", they won't
773          * go back through output filtering and miss their chance to get
774          * NAT'd and counted.  Duplicated packets aren't considered to be
775          * part of the normal packet stream, so do not NAT them or pass
776          * them through stateful checking, etc.
777          */
778         if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
779                 sifp = fin->fin_ifp;
780                 fin->fin_ifp = ifp;
781                 fin->fin_out = 1;
782                 (void) ipf_acctpkt(fin, NULL);
783                 fin->fin_fr = NULL;
784                 if (!fr || !(fr->fr_flags & FR_RETMASK)) {
785                         u_32_t pass;
786
787                         (void) ipf_state_check(fin, &pass);
788                 }
789
790                 switch (ipf_nat_checkout(fin, NULL))
791                 {
792                 case 0 :
793                         break;
794                 case 1 :
795                         ip->ip_sum = 0;
796                         break;
797                 case -1 :
798                         error = -1;
799                         goto bad;
800                         break;
801                 }
802
803                 fin->fin_ifp = sifp;
804                 fin->fin_out = 0;
805         } else
806                 ip->ip_sum = 0;
807         /*
808          * If small enough for interface, can just send directly.
809          */
810         if (ntohs(ip->ip_len) <= ifp->if_mtu) {
811                 if (!ip->ip_sum)
812                         ip->ip_sum = in_cksum(m, hlen);
813                 error = (*ifp->if_output)(ifp, m, gw, &ro);
814                 goto done;
815         }
816         /*
817          * Too large for interface; fragment if possible.
818          * Must be able to put at least 8 bytes per fragment.
819          */
820         ip_off = ntohs(ip->ip_off);
821         if (ip_off & IP_DF) {
822                 error = EMSGSIZE;
823                 goto bad;
824         }
825         len = (ifp->if_mtu - hlen) &~ 7;
826         if (len < 8) {
827                 error = EMSGSIZE;
828                 goto bad;
829         }
830
831     {
832         int mhlen, firstlen = len;
833         struct mbuf **mnext = &m->m_act;
834
835         /*
836          * Loop through length of segment after first fragment,
837          * make new header and copy data of each part and link onto chain.
838          */
839         m0 = m;
840         mhlen = sizeof (struct ip);
841         for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
842 #ifdef MGETHDR
843                 MGETHDR(m, M_NOWAIT, MT_HEADER);
844 #else
845                 MGET(m, M_NOWAIT, MT_HEADER);
846 #endif
847                 if (m == NULL) {
848                         m = m0;
849                         error = ENOBUFS;
850                         goto bad;
851                 }
852                 m->m_data += max_linkhdr;
853                 mhip = mtod(m, struct ip *);
854                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
855                 if (hlen > sizeof (struct ip)) {
856                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
857                         IP_HL_A(mhip, mhlen >> 2);
858                 }
859                 m->m_len = mhlen;
860                 mhip->ip_off = ((off - hlen) >> 3) + ip_off;
861                 if (off + len >= ntohs(ip->ip_len))
862                         len = ntohs(ip->ip_len) - off;
863                 else
864                         mhip->ip_off |= IP_MF;
865                 mhip->ip_len = htons((u_short)(len + mhlen));
866                 *mnext = m;
867                 m->m_next = m_copym(m0, off, len, M_NOWAIT);
868                 if (m->m_next == 0) {
869                         error = ENOBUFS;        /* ??? */
870                         goto sendorfree;
871                 }
872                 m->m_pkthdr.len = mhlen + len;
873                 m->m_pkthdr.rcvif = NULL;
874                 mhip->ip_off = htons((u_short)mhip->ip_off);
875                 mhip->ip_sum = 0;
876                 mhip->ip_sum = in_cksum(m, mhlen);
877                 mnext = &m->m_act;
878         }
879         /*
880          * Update first fragment by trimming what's been copied out
881          * and updating header, then send each fragment (in order).
882          */
883         m_adj(m0, hlen + firstlen - ip->ip_len);
884         ip->ip_len = htons((u_short)(hlen + firstlen));
885         ip->ip_off = htons((u_short)IP_MF);
886         ip->ip_sum = 0;
887         ip->ip_sum = in_cksum(m0, hlen);
888 sendorfree:
889         for (m = m0; m; m = m0) {
890                 m0 = m->m_act;
891                 m->m_act = 0;
892                 if (error == 0)
893                         error = (*ifp->if_output)(ifp, m, gw, &ro);
894                 else
895                         FREE_MB_T(m);
896         }
897     }
898 done:
899         if (!error)
900                 V_ipfmain.ipf_frouteok[0]++;
901         else
902                 V_ipfmain.ipf_frouteok[1]++;
903
904         return (0);
905 bad:
906         if (error == EMSGSIZE) {
907                 sifp = fin->fin_ifp;
908                 code = fin->fin_icode;
909                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
910                 fin->fin_ifp = ifp;
911                 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
912                 fin->fin_ifp = sifp;
913                 fin->fin_icode = code;
914         }
915         FREE_MB_T(m);
916         goto done;
917 }
918
919
920 int
921 ipf_verifysrc(fr_info_t *fin)
922 {
923         struct nhop_object *nh;
924
925         NET_EPOCH_ASSERT();
926         nh = fib4_lookup(RT_DEFAULT_FIB, fin->fin_src, 0, NHR_NONE, 0);
927         if (nh == NULL)
928                 return (0);
929         return (fin->fin_ifp == nh->nh_ifp);
930 }
931
932
933 /*
934  * return the first IP Address associated with an interface
935  */
936 int
937 ipf_ifpaddr(ipf_main_softc_t *softc, int v, int atype, void *ifptr,
938         i6addr_t *inp, i6addr_t *inpmask)
939 {
940 #ifdef USE_INET6
941         struct in6_addr *ia6 = NULL;
942 #endif
943         struct sockaddr *sock, *mask;
944         struct sockaddr_in *sin;
945         struct ifaddr *ifa;
946         struct ifnet *ifp;
947
948         if ((ifptr == NULL) || (ifptr == (void *)-1))
949                 return (-1);
950
951         sin = NULL;
952         ifp = ifptr;
953
954         if (v == 4)
955                 inp->in4.s_addr = 0;
956 #ifdef USE_INET6
957         else if (v == 6)
958                 bzero((char *)inp, sizeof(*inp));
959 #endif
960         ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
961
962         sock = ifa->ifa_addr;
963         while (sock != NULL && ifa != NULL) {
964                 sin = (struct sockaddr_in *)sock;
965                 if ((v == 4) && (sin->sin_family == AF_INET))
966                         break;
967 #ifdef USE_INET6
968                 if ((v == 6) && (sin->sin_family == AF_INET6)) {
969                         ia6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
970                         if (!IN6_IS_ADDR_LINKLOCAL(ia6) &&
971                             !IN6_IS_ADDR_LOOPBACK(ia6))
972                                 break;
973                 }
974 #endif
975                 ifa = CK_STAILQ_NEXT(ifa, ifa_link);
976                 if (ifa != NULL)
977                         sock = ifa->ifa_addr;
978         }
979
980         if (ifa == NULL || sin == NULL)
981                 return (-1);
982
983         mask = ifa->ifa_netmask;
984         if (atype == FRI_BROADCAST)
985                 sock = ifa->ifa_broadaddr;
986         else if (atype == FRI_PEERADDR)
987                 sock = ifa->ifa_dstaddr;
988
989         if (sock == NULL)
990                 return (-1);
991
992 #ifdef USE_INET6
993         if (v == 6) {
994                 return (ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
995                                          (struct sockaddr_in6 *)mask,
996                                          inp, inpmask));
997         }
998 #endif
999         return (ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1000                                  (struct sockaddr_in *)mask,
1001                                  &inp->in4, &inpmask->in4));
1002 }
1003
1004
1005 u_32_t
1006 ipf_newisn(fr_info_t *fin)
1007 {
1008         u_32_t newiss;
1009         newiss = arc4random();
1010         return (newiss);
1011 }
1012
1013
1014 int
1015 ipf_checkv4sum(fr_info_t *fin)
1016 {
1017 #ifdef CSUM_DATA_VALID
1018         int manual = 0;
1019         u_short sum;
1020         ip_t *ip;
1021         mb_t *m;
1022
1023         if ((fin->fin_flx & FI_NOCKSUM) != 0)
1024                 return (0);
1025
1026         if ((fin->fin_flx & FI_SHORT) != 0)
1027                 return (1);
1028
1029         if (fin->fin_cksum != FI_CK_NEEDED)
1030                 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1031
1032         m = fin->fin_m;
1033         if (m == NULL) {
1034                 manual = 1;
1035                 goto skipauto;
1036         }
1037         ip = fin->fin_ip;
1038
1039         if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
1040             CSUM_IP_CHECKED) {
1041                 fin->fin_cksum = FI_CK_BAD;
1042                 fin->fin_flx |= FI_BAD;
1043                 DT2(ipf_fi_bad_checkv4sum_csum_ip_checked, fr_info_t *, fin, u_int, m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID));
1044                 return (-1);
1045         }
1046         if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1047                 /* Depending on the driver, UDP may have zero checksum */
1048                 if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
1049                     (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
1050                         udphdr_t *udp = fin->fin_dp;
1051                         if (udp->uh_sum == 0) {
1052                                 /*
1053                                  * we're good no matter what the hardware
1054                                  * checksum flags and csum_data say (handling
1055                                  * of csum_data for zero UDP checksum is not
1056                                  * consistent across all drivers)
1057                                  */
1058                                 fin->fin_cksum = 1;
1059                                 return (0);
1060                         }
1061                 }
1062
1063                 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1064                         sum = m->m_pkthdr.csum_data;
1065                 else
1066                         sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1067                                         htonl(m->m_pkthdr.csum_data +
1068                                         fin->fin_dlen + fin->fin_p));
1069                 sum ^= 0xffff;
1070                 if (sum != 0) {
1071                         fin->fin_cksum = FI_CK_BAD;
1072                         fin->fin_flx |= FI_BAD;
1073                         DT2(ipf_fi_bad_checkv4sum_sum, fr_info_t *, fin, u_int, sum);
1074                 } else {
1075                         fin->fin_cksum = FI_CK_SUMOK;
1076                         return (0);
1077                 }
1078         } else {
1079                 if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
1080                         fin->fin_cksum = FI_CK_L4FULL;
1081                         return (0);
1082                 } else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
1083                            m->m_pkthdr.csum_flags == CSUM_UDP ||
1084                            m->m_pkthdr.csum_flags == CSUM_IP) {
1085                         fin->fin_cksum = FI_CK_L4PART;
1086                         return (0);
1087                 } else {
1088                         manual = 1;
1089                 }
1090         }
1091 skipauto:
1092         if (manual != 0) {
1093                 if (ipf_checkl4sum(fin) == -1) {
1094                         fin->fin_flx |= FI_BAD;
1095                         DT2(ipf_fi_bad_checkv4sum_manual, fr_info_t *, fin, u_int, manual);
1096                         return (-1);
1097                 }
1098         }
1099 #else
1100         if (ipf_checkl4sum(fin) == -1) {
1101                 fin->fin_flx |= FI_BAD;
1102                 DT2(ipf_fi_bad_checkv4sum_checkl4sum, fr_info_t *, fin, u_int, -1);
1103                 return (-1);
1104         }
1105 #endif
1106         return (0);
1107 }
1108
1109
1110 #ifdef USE_INET6
1111 int
1112 ipf_checkv6sum(fr_info_t *fin)
1113 {
1114         if ((fin->fin_flx & FI_NOCKSUM) != 0) {
1115                 DT(ipf_checkv6sum_fi_nocksum);
1116                 return (0);
1117         }
1118
1119         if ((fin->fin_flx & FI_SHORT) != 0) {
1120                 DT(ipf_checkv6sum_fi_short);
1121                 return (1);
1122         }
1123
1124         if (fin->fin_cksum != FI_CK_NEEDED) {
1125                 DT(ipf_checkv6sum_fi_ck_needed);
1126                 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1127         }
1128
1129         if (ipf_checkl4sum(fin) == -1) {
1130                 fin->fin_flx |= FI_BAD;
1131                 DT2(ipf_fi_bad_checkv6sum_checkl4sum, fr_info_t *, fin, u_int, -1);
1132                 return (-1);
1133         }
1134         return (0);
1135 }
1136 #endif /* USE_INET6 */
1137
1138
1139 size_t
1140 mbufchainlen(struct mbuf *m0)
1141 {
1142         size_t len;
1143
1144         if ((m0->m_flags & M_PKTHDR) != 0) {
1145                 len = m0->m_pkthdr.len;
1146         } else {
1147                 struct mbuf *m;
1148
1149                 for (m = m0, len = 0; m != NULL; m = m->m_next)
1150                         len += m->m_len;
1151         }
1152         return (len);
1153 }
1154
1155
1156 /* ------------------------------------------------------------------------ */
1157 /* Function:    ipf_pullup                                                  */
1158 /* Returns:     NULL == pullup failed, else pointer to protocol header      */
1159 /* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
1160 /*              fin(I) - pointer to packet information                      */
1161 /*              len(I) - number of bytes to pullup                          */
1162 /*                                                                          */
1163 /* Attempt to move at least len bytes (from the start of the buffer) into a */
1164 /* single buffer for ease of access.  Operating system native functions are */
1165 /* used to manage buffers - if necessary.  If the entire packet ends up in  */
1166 /* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
1167 /* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1168 /* and ONLY if the pullup succeeds.                                         */
1169 /*                                                                          */
1170 /* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
1171 /* of buffers that starts at *fin->fin_mp.                                  */
1172 /* ------------------------------------------------------------------------ */
1173 ip_t *
1174 ipf_pullup(mb_t *xmin, fr_info_t *fin, int len)
1175 {
1176         int dpoff, ipoff;
1177         mb_t *m = xmin;
1178         ip_t *ip;
1179
1180         if (m == NULL)
1181                 return (NULL);
1182
1183         ip = fin->fin_ip;
1184         if ((fin->fin_flx & FI_COALESCE) != 0)
1185                 return (ip);
1186
1187         ipoff = fin->fin_ipoff;
1188         if (fin->fin_dp != NULL)
1189                 dpoff = (char *)fin->fin_dp - (char *)ip;
1190         else
1191                 dpoff = 0;
1192
1193         if (M_LEN(m) < len) {
1194                 mb_t *n = *fin->fin_mp;
1195                 /*
1196                  * Assume that M_PKTHDR is set and just work with what is left
1197                  * rather than check..
1198                  * Should not make any real difference, anyway.
1199                  */
1200                 if (m != n) {
1201                         /*
1202                          * Record the mbuf that points to the mbuf that we're
1203                          * about to go to work on so that we can update the
1204                          * m_next appropriately later.
1205                          */
1206                         for (; n->m_next != m; n = n->m_next)
1207                                 ;
1208                 } else {
1209                         n = NULL;
1210                 }
1211
1212 #ifdef MHLEN
1213                 if (len > MHLEN)
1214 #else
1215                 if (len > MLEN)
1216 #endif
1217                 {
1218 #ifdef HAVE_M_PULLDOWN
1219                         if (m_pulldown(m, 0, len, NULL) == NULL)
1220                                 m = NULL;
1221 #else
1222                         FREE_MB_T(*fin->fin_mp);
1223                         m = NULL;
1224                         n = NULL;
1225 #endif
1226                 } else
1227                 {
1228
1229                         m = m_pullup(m, len);
1230                 }
1231                 if (n != NULL)
1232                         n->m_next = m;
1233                 if (m == NULL) {
1234                         /*
1235                          * When n is non-NULL, it indicates that m pointed to
1236                          * a sub-chain (tail) of the mbuf and that the head
1237                          * of this chain has not yet been free'd.
1238                          */
1239                         if (n != NULL) {
1240                                 FREE_MB_T(*fin->fin_mp);
1241                         }
1242
1243                         *fin->fin_mp = NULL;
1244                         fin->fin_m = NULL;
1245                         return (NULL);
1246                 }
1247
1248                 if (n == NULL)
1249                         *fin->fin_mp = m;
1250
1251                 while (M_LEN(m) == 0) {
1252                         m = m->m_next;
1253                 }
1254                 fin->fin_m = m;
1255                 ip = MTOD(m, ip_t *) + ipoff;
1256
1257                 fin->fin_ip = ip;
1258                 if (fin->fin_dp != NULL)
1259                         fin->fin_dp = (char *)fin->fin_ip + dpoff;
1260                 if (fin->fin_fraghdr != NULL)
1261                         fin->fin_fraghdr = (char *)ip +
1262                                            ((char *)fin->fin_fraghdr -
1263                                             (char *)fin->fin_ip);
1264         }
1265
1266         if (len == fin->fin_plen)
1267                 fin->fin_flx |= FI_COALESCE;
1268         return (ip);
1269 }
1270
1271
1272 int
1273 ipf_inject(fr_info_t *fin, mb_t *m)
1274 {
1275         struct epoch_tracker et;
1276         int error = 0;
1277
1278         NET_EPOCH_ENTER(et);
1279         if (fin->fin_out == 0) {
1280                 netisr_dispatch(NETISR_IP, m);
1281         } else {
1282                 fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1283                 fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1284                 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1285         }
1286         NET_EPOCH_EXIT(et);
1287
1288         return (error);
1289 }
1290
1291 VNET_DEFINE_STATIC(pfil_hook_t, ipf_inet_hook);
1292 VNET_DEFINE_STATIC(pfil_hook_t, ipf_inet6_hook);
1293 #define V_ipf_inet_hook         VNET(ipf_inet_hook)
1294 #define V_ipf_inet6_hook        VNET(ipf_inet6_hook)
1295
1296 int ipf_pfil_unhook(void) {
1297
1298         pfil_remove_hook(V_ipf_inet_hook);
1299
1300 #ifdef USE_INET6
1301         pfil_remove_hook(V_ipf_inet6_hook);
1302 #endif
1303
1304         return (0);
1305 }
1306
1307 int ipf_pfil_hook(void) {
1308         int error, error6;
1309
1310         struct pfil_hook_args pha = {
1311                 .pa_version = PFIL_VERSION,
1312                 .pa_flags = PFIL_IN | PFIL_OUT,
1313                 .pa_modname = "ipfilter",
1314                 .pa_rulname = "default-ip4",
1315                 .pa_mbuf_chk = ipf_check_wrapper,
1316                 .pa_type = PFIL_TYPE_IP4,
1317         };
1318         V_ipf_inet_hook = pfil_add_hook(&pha);
1319
1320 #ifdef USE_INET6
1321         pha.pa_rulname = "default-ip6";
1322         pha.pa_mbuf_chk = ipf_check_wrapper6;
1323         pha.pa_type = PFIL_TYPE_IP6;
1324         V_ipf_inet6_hook = pfil_add_hook(&pha);
1325 #endif
1326
1327         struct pfil_link_args pla = {
1328                 .pa_version = PFIL_VERSION,
1329                 .pa_flags = PFIL_IN | PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR,
1330                 .pa_head = V_inet_pfil_head,
1331                 .pa_hook = V_ipf_inet_hook,
1332         };
1333         error = pfil_link(&pla);
1334
1335         error6 = 0;
1336 #ifdef USE_INET6
1337         pla.pa_head = V_inet6_pfil_head;
1338         pla.pa_hook = V_ipf_inet6_hook;
1339         error6 = pfil_link(&pla);
1340 #endif
1341
1342         if (error || error6)
1343                 error = ENODEV;
1344         else
1345                 error = 0;
1346
1347         return (error);
1348 }
1349
1350 void
1351 ipf_event_reg(void)
1352 {
1353         V_ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1354                                                ipf_ifevent, NULL, \
1355                                                EVENTHANDLER_PRI_ANY);
1356         V_ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
1357                                                ipf_ifevent, NULL, \
1358                                                EVENTHANDLER_PRI_ANY);
1359 #if 0
1360         V_ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1361                                                NULL, EVENTHANDLER_PRI_ANY);
1362 #endif
1363 }
1364
1365 void
1366 ipf_event_dereg(void)
1367 {
1368         if (V_ipf_arrivetag != NULL) {
1369                 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, V_ipf_arrivetag);
1370         }
1371         if (V_ipf_departtag != NULL) {
1372                 EVENTHANDLER_DEREGISTER(ifnet_departure_event, V_ipf_departtag);
1373         }
1374 #if 0
1375         if (V_ipf_clonetag != NULL) {
1376                 EVENTHANDLER_DEREGISTER(if_clone_event, V_ipf_clonetag);
1377         }
1378 #endif
1379 }
1380
1381
1382 u_32_t
1383 ipf_random(void)
1384 {
1385         return (arc4random());
1386 }
1387
1388
1389 u_int
1390 ipf_pcksum(fr_info_t *fin, int hlen, u_int sum)
1391 {
1392         struct mbuf *m;
1393         u_int sum2;
1394         int off;
1395
1396         m = fin->fin_m;
1397         off = (char *)fin->fin_dp - (char *)fin->fin_ip;
1398         m->m_data += hlen;
1399         m->m_len -= hlen;
1400         sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
1401         m->m_len += hlen;
1402         m->m_data -= hlen;
1403
1404         /*
1405          * Both sum and sum2 are partial sums, so combine them together.
1406          */
1407         sum += ~sum2 & 0xffff;
1408         while (sum > 0xffff)
1409                 sum = (sum & 0xffff) + (sum >> 16);
1410         sum2 = ~sum & 0xffff;
1411         return (sum2);
1412 }
1413
1414 #ifdef  USE_INET6
1415 u_int
1416 ipf_pcksum6(struct mbuf *m, ip6_t *ip6, u_int32_t off, u_int32_t len)
1417 {
1418 #ifdef  _KERNEL
1419         int sum;
1420
1421         if (m->m_len < sizeof(struct ip6_hdr)) {
1422                 return (0xffff);
1423         }
1424
1425         sum = in6_cksum(m, ip6->ip6_nxt, off, len);
1426         return (sum);
1427 #else
1428         u_short *sp;
1429         u_int sum;
1430
1431         sp = (u_short *)&ip6->ip6_src;
1432         sum = *sp++;   /* ip6_src */
1433         sum += *sp++;
1434         sum += *sp++;
1435         sum += *sp++;
1436         sum += *sp++;
1437         sum += *sp++;
1438         sum += *sp++;
1439         sum += *sp++;
1440         sum += *sp++;   /* ip6_dst */
1441         sum += *sp++;
1442         sum += *sp++;
1443         sum += *sp++;
1444         sum += *sp++;
1445         sum += *sp++;
1446         sum += *sp++;
1447         sum += *sp++;
1448         return (ipf_pcksum(fin, off, sum));
1449 #endif
1450 }
1451 #endif
1452
1453 void
1454 ipf_fbsd_kenv_get(ipf_main_softc_t *softc)
1455 {
1456         TUNABLE_INT_FETCH("net.inet.ipf.large_nat",
1457                 &softc->ipf_large_nat);
1458 }