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