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