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