]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/ip_fil.c
This commit was generated by cvs2svn to compensate for changes in r99179,
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / ip_fil.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6
7 #ifndef SOLARIS
8 #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
9 #endif
10
11 #if defined(KERNEL) && !defined(_KERNEL)
12 # define        _KERNEL
13 #endif
14 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
15     (__FreeBSD_version >= 400000) && !defined(KLD_MODULE)
16 #include "opt_inet6.h"
17 #endif
18 #include <sys/param.h>
19 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
20     defined(_KERNEL)  && !defined(_LKM)
21 # include "opt_ipfilter_log.h"
22 #endif
23 #if defined(__FreeBSD__) && !defined(__FreeBSD_version)
24 # if !defined(_KERNEL) || defined(IPFILTER_LKM)
25 #  include <osreldate.h>
26 # endif
27 #endif
28 #ifdef __sgi
29 # define _KMEMUSER
30 # include <sys/ptimers.h>
31 #endif
32 #ifndef _KERNEL
33 # include <stdio.h>
34 # include <string.h>
35 # include <stdlib.h>
36 # include <ctype.h>
37 # include <fcntl.h>
38 #endif
39 #include <sys/errno.h>
40 #include <sys/types.h>
41 #include <sys/file.h>
42 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
43 # include <sys/fcntl.h>
44 # include <sys/filio.h>
45 #else
46 # include <sys/ioctl.h>
47 #endif
48 #include <sys/time.h>
49 #ifdef  _KERNEL
50 # include <sys/systm.h>
51 #endif
52 #if !SOLARIS
53 # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
54 #  include <sys/dirent.h>
55 # else
56 #  include <sys/dir.h>
57 # endif
58 # include <sys/mbuf.h>
59 #else
60 # include <sys/filio.h>
61 #endif
62 #include <sys/protosw.h>
63 #include <sys/socket.h>
64
65 #include <net/if.h>
66 #ifdef sun
67 # include <net/af.h>
68 #endif
69 #if __FreeBSD_version >= 300000
70 # include <net/if_var.h>
71 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
72 #  include "opt_ipfilter.h"
73 # endif
74 #endif
75 #ifdef __sgi
76 #include <sys/debug.h>
77 # ifdef IFF_DRVRLOCK /* IRIX6 */
78 #include <sys/hashing.h>
79 # endif
80 #endif
81 #include <net/route.h>
82 #include <netinet/in.h>
83 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */
84 # include <netinet/in_var.h>
85 #endif
86 #include <netinet/in_systm.h>
87 #include <netinet/ip.h>
88 #include <netinet/ip_var.h>
89 #include <netinet/tcp.h>
90 #include <netinet/udp.h>
91 #include <netinet/tcpip.h>
92 #include <netinet/ip_icmp.h>
93 #ifndef _KERNEL
94 # include <unistd.h>
95 # include <syslog.h>
96 #endif
97 #include "netinet/ip_compat.h"
98 #ifdef USE_INET6
99 # include <netinet/icmp6.h>
100 # if !SOLARIS
101 #  include <netinet6/ip6protosw.h>
102 #  include <netinet6/nd6.h>
103 # endif
104 #endif
105 #include "netinet/ip_fil.h"
106 #include "netinet/ip_nat.h"
107 #include "netinet/ip_frag.h"
108 #include "netinet/ip_state.h"
109 #include "netinet/ip_proxy.h"
110 #include "netinet/ip_auth.h"
111 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
112 # include <sys/malloc.h>
113 #endif
114 #ifndef MIN
115 # define        MIN(a,b)        (((a)<(b))?(a):(b))
116 #endif
117 #if !SOLARIS && defined(_KERNEL) && !defined(__sgi)
118 # include <sys/kernel.h>
119 extern  int     ip_optcopy __P((struct ip *, struct ip *));
120 #endif
121
122 #include <machine/in_cksum.h>
123
124 #if !defined(lint)
125 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
126 /* static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.34 2001/07/23 13:49:57 darrenr Exp $"; */
127 static const char rcsid[] = "@(#)$FreeBSD$";
128 #endif
129
130 extern  struct  protosw inetsw[];
131
132 #ifndef _KERNEL
133 # include "ipt.h"
134 static  struct  ifnet **ifneta = NULL;
135 static  int     nifs = 0;
136 #else
137 # if    (BSD < 199306) || defined(__sgi)
138 extern  int     tcp_ttl;
139 # endif
140 #endif
141
142 #ifdef  ICMP_UNREACH_FILTER_PROHIB
143 int     ipl_unreach = ICMP_UNREACH_FILTER_PROHIB;
144 #else
145 int     ipl_unreach = ICMP_UNREACH_FILTER;
146 #endif
147 u_long  ipl_frouteok[2] = {0, 0};
148
149 static  int     frzerostats __P((caddr_t));
150 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
151 static  int     frrequest __P((int, u_long, caddr_t, int));
152 #else
153 static  int     frrequest __P((int, int, caddr_t, int));
154 #endif
155 #ifdef  _KERNEL
156 static  int     (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
157 static  int     send_ip __P((ip_t *, fr_info_t *, struct mbuf **));
158 # ifdef USE_INET6
159 static  int     ipfr_fastroute6 __P((struct mbuf *, struct mbuf **,
160                                      fr_info_t *, frdest_t *));
161 # endif
162 # ifdef __sgi
163 extern  kmutex_t        ipf_rw;
164 extern  KRWLOCK_T       ipf_mutex;
165 # endif
166 #else
167 void    init_ifp __P((void));
168 # if defined(__sgi) && (IRIX < 605)
169 static int      no_output __P((struct ifnet *, struct mbuf *,
170                                struct sockaddr *));
171 static int      write_output __P((struct ifnet *, struct mbuf *,
172                                   struct sockaddr *));
173 # else
174 static int      no_output __P((struct ifnet *, struct mbuf *,
175                                struct sockaddr *, struct rtentry *));
176 static int      write_output __P((struct ifnet *, struct mbuf *,
177                                   struct sockaddr *, struct rtentry *));
178 # endif
179 #endif
180 int     fr_running = 0;
181
182 #if (__FreeBSD_version >= 300000) && defined(_KERNEL)
183 struct callout_handle ipfr_slowtimer_ch;
184 #endif
185 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
186 # include <sys/callout.h>
187 struct callout ipfr_slowtimer_ch;
188 #endif
189 #if defined(__OpenBSD__)
190 # include <sys/timeout.h>
191 struct timeout ipfr_slowtimer_ch;
192 #endif
193 #if defined(__sgi) && defined(_KERNEL)
194 toid_t ipfr_slowtimer_ch;
195 #endif
196
197 #if (_BSDI_VERSION >= 199510) && defined(_KERNEL)
198 # include <sys/device.h>
199 # include <sys/conf.h>
200
201 struct cfdriver iplcd = {
202         NULL, "ipl", NULL, NULL, DV_DULL, 0
203 };
204
205 struct devsw iplsw = {
206         &iplcd,
207         iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap,
208         nostrat, nodump, nopsize, 0,
209         nostop
210 };
211 #endif /* _BSDI_VERSION >= 199510  && _KERNEL */
212
213 #if defined(__NetBSD__) || defined(__OpenBSD__)  || \
214     (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 500011)
215 # include <sys/conf.h>
216 # if defined(NETBSD_PF)
217 #  include <net/pfil.h>
218 /*
219  * We provide the fr_checkp name just to minimize changes later.
220  */
221 int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
222 # endif /* NETBSD_PF */
223 #endif /* __NetBSD__ */
224
225
226 #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) && \
227     defined(_KERNEL)
228 # include <net/pfil.h>
229
230 static int fr_check_wrapper(void *, struct mbuf **, struct ifnet *, int );
231
232 static int fr_check_wrapper(arg, mp, ifp, dir)
233 void *arg;
234 struct mbuf **mp;
235 struct ifnet *ifp;
236 int dir;
237 {
238         struct ip *ip = mtod(*mp, struct ip *);
239         int rv, hlen = ip->ip_hl << 2;
240
241 #if defined(M_CSUM_TCPv4)
242         /*
243          * If the packet is out-bound, we can't delay checksums
244          * here.  For in-bound, the checksum has already been
245          * validated.
246          */
247         if (dir == PFIL_OUT) {
248                 if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
249                         in_delayed_cksum(*mp);
250                         (*mp)->m_pkthdr.csum_flags &=
251                             ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
252                 }
253         }
254 #endif /* M_CSUM_TCPv4 */
255
256         /*
257          * We get the packet with all fields in network byte
258          * order.  We expect ip_len and ip_off to be in host
259          * order.  We frob them, call the filter, then frob
260          * them back.
261          *
262          * Note, we don't need to update the checksum, because
263          * it has already been verified.
264          */
265         NTOHS(ip->ip_len);
266         NTOHS(ip->ip_off);
267
268         rv = fr_check(ip, hlen, ifp, (dir == PFIL_OUT), mp);
269
270         if (rv == 0 && *mp != NULL) {
271                 ip = mtod(*mp, struct ip *);
272                 HTONS(ip->ip_len);
273                 HTONS(ip->ip_off);
274         }
275
276         return (rv);
277 }
278
279 # ifdef USE_INET6
280 #  include <netinet/ip6.h>
281
282 static int fr_check_wrapper6(void *, struct mbuf **, struct ifnet *, int );
283
284 static int fr_check_wrapper6(arg, mp, ifp, dir)
285 void *arg;
286 struct mbuf **mp;
287 struct ifnet *ifp;
288 int dir;
289 {
290         
291         return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
292             ifp, (dir == PFIL_OUT), mp));
293 }
294 # endif
295 #endif /* __NetBSD_Version >= 105110000 && _KERNEL */
296 #ifdef  _KERNEL
297 # if    defined(IPFILTER_LKM) && !defined(__sgi)
298 int iplidentify(s)
299 char *s;
300 {
301         if (strcmp(s, "ipl") == 0)
302                 return 1;
303         return 0;
304 }
305 # endif /* IPFILTER_LKM */
306
307
308 /*
309  * Try to detect the case when compiling for NetBSD with pseudo-device
310  */
311 # if defined(__NetBSD__) && defined(PFIL_HOOKS)
312 void
313 ipfilterattach(count)
314 int count;
315 {
316
317         /*
318          * Do nothing here, really.  The filter will be enabled
319          * by the SIOCFRENB ioctl.
320          */
321 }
322 # endif
323
324
325 # if defined(__NetBSD__)
326 int ipl_enable()
327 # else
328 int iplattach()
329 # endif
330 {
331         char *defpass;
332         int s;
333 # if defined(__sgi) || (defined(NETBSD_PF) && \
334   ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)))
335         int error = 0;
336 # endif
337 #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)
338         struct pfil_head *ph_inet;
339 # ifdef USE_INET6
340         struct pfil_head *ph_inet6;
341 # endif
342 #endif
343
344         SPL_NET(s);
345         if (fr_running || (fr_checkp == fr_check)) {
346                 printf("IP Filter: already initialized\n");
347                 SPL_X(s);
348                 return EBUSY;
349         }
350
351 # ifdef IPFILTER_LOG
352         ipflog_init();
353 # endif
354         if (nat_init() == -1) {
355                 SPL_X(s);
356                 return EIO;
357         }
358         if (fr_stateinit() == -1) {
359                 SPL_X(s);
360                 return EIO;
361         }
362         if (appr_init() == -1) {
363                 SPL_X(s);
364                 return EIO;
365         }
366
367 # ifdef NETBSD_PF
368 #  if (__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)
369 #   if __NetBSD_Version__ >= 105110000
370         if (
371             !(ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET))
372 #    ifdef USE_INET6
373             && !(ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6))
374 #    endif
375            )
376                 return ENODEV;
377
378         if (ph_inet != NULL)
379                 error = pfil_add_hook((void *)fr_check_wrapper, NULL,
380                                       PFIL_IN|PFIL_OUT, ph_inet);
381         else
382                 error = 0;
383 #  else
384         error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
385                               &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
386 #  endif
387         if (error) {
388 #   ifdef USE_INET6
389                 goto pfil_error;
390 #   else
391                 SPL_X(s);
392                 appr_unload();
393                 ip_natunload();
394                 fr_stateunload();
395                 return error;
396 #   endif
397         }
398 #  else
399         pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
400 #  endif
401 #  ifdef USE_INET6
402 #   if __NetBSD_Version__ >= 105110000
403         if (ph_inet6 != NULL)
404                 error = pfil_add_hook((void *)fr_check_wrapper6, NULL,
405                                       PFIL_IN|PFIL_OUT, ph_inet6);
406         else
407                 error = 0;
408         if (error) {
409                 pfil_remove_hook((void *)fr_check_wrapper6, NULL,
410                                  PFIL_IN|PFIL_OUT, ph_inet6);
411 #   else
412         error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
413                               &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
414         if (error) {
415                 pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
416                                  &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
417 #   endif
418 pfil_error:
419                 SPL_X(s);
420                 appr_unload();
421                 ip_natunload();
422                 fr_stateunload();
423                 return error;
424         }
425 #  endif
426 # endif
427
428 # ifdef __sgi
429         error = ipfilter_sgi_attach();
430         if (error) {
431                 SPL_X(s);
432                 appr_unload();
433                 ip_natunload();
434                 fr_stateunload();
435                 return error;
436         }
437 # endif
438
439         bzero((char *)frcache, sizeof(frcache));
440         fr_savep = fr_checkp;
441         fr_checkp = fr_check;
442         fr_running = 1;
443
444         SPL_X(s);
445         if (fr_pass & FR_PASS)
446                 defpass = "pass";
447         else if (fr_pass & FR_BLOCK)
448                 defpass = "block";
449         else
450                 defpass = "no-match -> block";
451
452         printf("%s initialized.  Default = %s all, Logging = %s\n",
453                 ipfilter_version, defpass,
454 # ifdef IPFILTER_LOG
455                 "enabled");
456 # else
457                 "disabled");
458 # endif
459 #ifdef  _KERNEL
460 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
461         callout_init(&ipfr_slowtimer_ch);
462         callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL);
463 # else
464 #  if defined(__OpenBSD__)
465         timeout_set(&ipfr_slowtimer_ch, ipfr_slowtimer, NULL);
466         timeout_add(&ipfr_slowtimer_ch, hz/2);
467 #  else
468 #   if (__FreeBSD_version >= 300000) || defined(__sgi)
469         ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
470 #   else
471         timeout(ipfr_slowtimer, NULL, hz/2);
472 #   endif
473 #  endif
474 # endif
475 #endif
476         return 0;
477 }
478
479
480 /*
481  * Disable the filter by removing the hooks from the IP input/output
482  * stream.
483  */
484 # if defined(__NetBSD__)
485 int ipl_disable()
486 # else
487 int ipldetach()
488 # endif
489 {
490         int s, i = FR_INQUE|FR_OUTQUE;
491 #if defined(NETBSD_PF) && \
492     ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011))
493         int error = 0;
494 # if __NetBSD_Version__ >= 105150000
495         struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
496 #  ifdef USE_INET6
497         struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
498 #  endif
499 # endif
500 #endif
501
502 #ifdef  _KERNEL
503 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
504         callout_stop(&ipfr_slowtimer_ch);
505 # else
506 #  if (__FreeBSD_version >= 300000)
507         untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch);
508 #  else
509 #  ifdef __sgi
510         untimeout(ipfr_slowtimer_ch);
511 #   else
512 #    if defined(__OpenBSD__)
513         timeout_del(&ipfr_slowtimer_ch);
514 #    else
515         untimeout(ipfr_slowtimer, NULL);
516 #    endif /* OpenBSD */
517 #   endif /* __sgi */
518 #  endif /* FreeBSD */
519 # endif /* NetBSD */
520 #endif
521         SPL_NET(s);
522         if (!fr_running)
523         {
524                 printf("IP Filter: not initialized\n");
525                 SPL_X(s);
526                 return 0;
527         }
528
529         printf("%s unloaded\n", ipfilter_version);
530
531         fr_checkp = fr_savep;
532         i = frflush(IPL_LOGIPF, i);
533         fr_running = 0;
534
535 # ifdef NETBSD_PF
536 #  if ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011))
537 #   if __NetBSD_Version__ >= 105110000
538         if (ph_inet != NULL)
539                 error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
540                                          PFIL_IN|PFIL_OUT, ph_inet);
541         else
542                 error = 0;
543 #   else
544         error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
545                                  &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
546 #   endif
547         if (error) {
548                 SPL_X(s);
549                 return error;
550         }
551 #  else
552         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
553 #  endif
554 #  ifdef USE_INET6
555 #   if __NetBSD_Version__ >= 105110000
556         if (ph_inet6 != NULL)
557                 error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
558                                          PFIL_IN|PFIL_OUT, ph_inet6);
559         else
560                 error = 0;
561 #   else
562         error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
563                                  &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
564 #   endif
565         if (error) {
566                 SPL_X(s);
567                 return error;
568         }
569 #  endif
570 # endif
571
572 # ifdef __sgi
573         ipfilter_sgi_detach();
574 # endif
575
576         appr_unload();
577         ipfr_unload();
578         ip_natunload();
579         fr_stateunload();
580         fr_authunload();
581
582         SPL_X(s);
583         return 0;
584 }
585 #endif /* _KERNEL */
586
587
588 static  int     frzerostats(data)
589 caddr_t data;
590 {
591         friostat_t fio;
592         int error;
593
594         fr_getstat(&fio);
595         error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio));
596         if (error)
597                 return EFAULT;
598
599         bzero((char *)frstats, sizeof(*frstats) * 2);
600
601         return 0;
602 }
603
604
605 /*
606  * Filter ioctl interface.
607  */
608 #ifdef __sgi
609 int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode
610 # ifdef _KERNEL
611         , cred_t *cp, int *rp
612 # endif
613 )
614 #else
615 int IPL_EXTERN(ioctl)(dev, cmd, data, mode
616 # if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \
617        (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \
618        defined(__OpenBSD__)))
619 , td)
620 struct thread *td;
621 # else
622 )
623 # endif
624 dev_t dev;
625 # if defined(__NetBSD__) || defined(__OpenBSD__) || \
626         (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000)
627 u_long cmd;
628 # else
629 int cmd;
630 # endif
631 caddr_t data;
632 int mode;
633 #endif /* __sgi */
634 {
635 #if defined(_KERNEL) && !SOLARIS
636         int s;
637 #endif
638         int error = 0, unit = 0, tmp;
639
640 #if (BSD >= 199306) && defined(_KERNEL)
641         if ((securelevel >= 3) && (mode & FWRITE))
642                 return EPERM;
643 #endif
644 #ifdef  _KERNEL
645         unit = GET_MINOR(dev);
646         if ((IPL_LOGMAX < unit) || (unit < 0))
647                 return ENXIO;
648 #else
649         unit = dev;
650 #endif
651
652         if (fr_running == 0 && (cmd != SIOCFRENB || unit != IPL_LOGIPF))
653                 return ENODEV;
654
655         SPL_NET(s);
656
657         if (unit == IPL_LOGNAT) {
658                 if (fr_running)
659                         error = nat_ioctl(data, cmd, mode);
660                 else
661                         error = EIO;
662                 SPL_X(s);
663                 return error;
664         }
665         if (unit == IPL_LOGSTATE) {
666                 if (fr_running)
667                         error = fr_state_ioctl(data, cmd, mode);
668                 else
669                         error = EIO;
670                 SPL_X(s);
671                 return error;
672         }
673         if (unit == IPL_LOGAUTH) {
674                 if (!fr_running)
675                         error = EIO;
676                 else
677                         error = fr_auth_ioctl(data, mode, cmd, NULL, NULL);
678                 SPL_X(s);
679                 return error;
680         }
681
682         switch (cmd) {
683         case FIONREAD :
684 #ifdef IPFILTER_LOG
685                 error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data,
686                                sizeof(iplused[IPL_LOGIPF]));
687 #endif
688                 break;
689 #if (!defined(IPFILTER_LKM) || defined(__NetBSD__)) && defined(_KERNEL)
690         case SIOCFRENB :
691         {
692                 u_int   enable;
693
694                 if (!(mode & FWRITE))
695                         error = EPERM;
696                 else {
697                         error = IRCOPY(data, (caddr_t)&enable, sizeof(enable));
698                         if (error)
699                                 break;
700                         if (enable)
701 # if defined(__NetBSD__)
702                                 error = ipl_enable();
703 # else
704                                 error = iplattach();
705 # endif
706                         else
707 # if defined(__NetBSD__)
708                                 error = ipl_disable();
709 # else
710                                 error = ipldetach();
711 # endif
712                 }
713                 break;
714         }
715 #endif
716         case SIOCSETFF :
717                 if (!(mode & FWRITE))
718                         error = EPERM;
719                 else
720                         error = IRCOPY(data, (caddr_t)&fr_flags,
721                                        sizeof(fr_flags));
722                 break;
723         case SIOCGETFF :
724                 error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
725                 break;
726         case SIOCINAFR :
727         case SIOCRMAFR :
728         case SIOCADAFR :
729         case SIOCZRLST :
730                 if (!(mode & FWRITE))
731                         error = EPERM;
732                 else
733                         error = frrequest(unit, cmd, data, fr_active);
734                 break;
735         case SIOCINIFR :
736         case SIOCRMIFR :
737         case SIOCADIFR :
738                 if (!(mode & FWRITE))
739                         error = EPERM;
740                 else
741                         error = frrequest(unit, cmd, data, 1 - fr_active);
742                 break;
743         case SIOCSWAPA :
744                 if (!(mode & FWRITE))
745                         error = EPERM;
746                 else {
747                         bzero((char *)frcache, sizeof(frcache[0]) * 2);
748                         *(u_int *)data = fr_active;
749                         fr_active = 1 - fr_active;
750                 }
751                 break;
752         case SIOCGETFS :
753         {
754                 friostat_t      fio;
755
756                 fr_getstat(&fio);
757                 error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio));
758                 if (error)
759                         error = EFAULT;
760                 break;
761         }
762         case    SIOCFRZST :
763                 if (!(mode & FWRITE))
764                         error = EPERM;
765                 else
766                         error = frzerostats(data);
767                 break;
768         case    SIOCIPFFL :
769                 if (!(mode & FWRITE))
770                         error = EPERM;
771                 else {
772                         error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
773                         if (!error) {
774                                 tmp = frflush(unit, tmp);
775                                 error = IWCOPY((caddr_t)&tmp, data,
776                                                sizeof(tmp));
777                         }
778                 }
779                 break;
780         case SIOCSTLCK :
781                 error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
782                 if (!error) {
783                         fr_state_lock = tmp;
784                         fr_nat_lock = tmp;
785                         fr_frag_lock = tmp;
786                         fr_auth_lock = tmp;
787                 } else
788                         error = EFAULT;
789                 break;
790 #ifdef  IPFILTER_LOG
791         case    SIOCIPFFB :
792                 if (!(mode & FWRITE))
793                         error = EPERM;
794                 else
795                         *(int *)data = ipflog_clear(unit);
796                 break;
797 #endif /* IPFILTER_LOG */
798         case SIOCGFRST :
799                 error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data,
800                                   sizeof(ipfrstat_t));
801                 if (error)
802                         error = EFAULT;
803                 break;
804         case SIOCAUTHW :
805         case SIOCAUTHR :
806                 if (!(mode & FWRITE)) {
807                         error = EPERM;
808                         break;
809                 }
810         case SIOCFRSYN :
811                 if (!(mode & FWRITE))
812                         error = EPERM;
813                 else {
814 #if defined(_KERNEL) && defined(__sgi)
815                         ipfsync();
816 #endif
817                         frsync();
818                 }
819                 break;
820         default :
821                 error = EINVAL;
822                 break;
823         }
824         SPL_X(s);
825         return error;
826 }
827
828
829 void fr_forgetifp(ifp)
830 void *ifp;
831 {
832         register frentry_t *f;
833
834         WRITE_ENTER(&ipf_mutex);
835         for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
836                 if (f->fr_ifa == ifp)
837                         f->fr_ifa = (void *)-1;
838         for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
839                 if (f->fr_ifa == ifp)
840                         f->fr_ifa = (void *)-1;
841         for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
842                 if (f->fr_ifa == ifp)
843                         f->fr_ifa = (void *)-1;
844         for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
845                 if (f->fr_ifa == ifp)
846                         f->fr_ifa = (void *)-1;
847 #ifdef  USE_INET6
848         for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
849                 if (f->fr_ifa == ifp)
850                         f->fr_ifa = (void *)-1;
851         for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
852                 if (f->fr_ifa == ifp)
853                         f->fr_ifa = (void *)-1;
854         for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
855                 if (f->fr_ifa == ifp)
856                         f->fr_ifa = (void *)-1;
857         for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
858                 if (f->fr_ifa == ifp)
859                         f->fr_ifa = (void *)-1;
860 #endif
861         RWLOCK_EXIT(&ipf_mutex);
862         ip_natsync(ifp);
863 }
864
865
866 static int frrequest(unit, req, data, set)
867 int unit;
868 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
869 u_long req;
870 #else
871 int req;
872 #endif
873 int set;
874 caddr_t data;
875 {
876         register frentry_t *fp, *f, **fprev;
877         register frentry_t **ftail;
878         frgroup_t *fg = NULL;
879         int error = 0, in, i;
880         u_int   *p, *pp;
881         frentry_t frd;
882         frdest_t *fdp;
883         u_int group;
884
885         fp = &frd;
886         error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp));
887         if (error)
888                 return EFAULT;
889         fp->fr_ref = 0;
890 #if (BSD >= 199306) && defined(_KERNEL)
891         if ((securelevel > 0) && (fp->fr_func != NULL))
892                 return EPERM;
893 #endif
894
895         /*
896          * Check that the group number does exist and that if a head group
897          * has been specified, doesn't exist.
898          */
899         if ((req != SIOCZRLST) && ((req == SIOCINAFR) || (req == SIOCINIFR) ||
900              (req == SIOCADAFR) || (req == SIOCADIFR)) && fp->fr_grhead &&
901             fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL))
902                 return EEXIST;
903         if ((req != SIOCZRLST) && fp->fr_group &&
904             !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL))
905                 return ESRCH;
906
907         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
908
909         if (unit == IPL_LOGAUTH)
910                 ftail = fprev = &ipauth;
911         else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4))
912                 ftail = fprev = &ipacct[in][set];
913         else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4))
914                 ftail = fprev = &ipfilter[in][set];
915 #ifdef  USE_INET6
916         else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6))
917                 ftail = fprev = &ipacct6[in][set];
918         else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6))
919                 ftail = fprev = &ipfilter6[in][set];
920 #endif
921         else
922                 return ESRCH;
923
924         if ((group = fp->fr_group)) {
925                 if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL)))
926                         return ESRCH;
927                 ftail = fprev = fg->fg_start;
928         }
929
930         bzero((char *)frcache, sizeof(frcache[0]) * 2);
931
932         for (i = 0; i < 4; i++) {
933                 if ((fp->fr_ifnames[i][1] == '\0') &&
934                     ((fp->fr_ifnames[i][0] == '-') ||
935                      (fp->fr_ifnames[i][0] == '*'))) {
936                         fp->fr_ifas[i] = NULL;
937                 } else if (*fp->fr_ifnames[i]) {
938                         fp->fr_ifas[i] = GETUNIT(fp->fr_ifnames[i], fp->fr_v);
939                         if (!fp->fr_ifas[i])
940                                 fp->fr_ifas[i] = (void *)-1;
941                 }
942         }
943
944         fdp = &fp->fr_dif;
945         fp->fr_flags &= ~FR_DUP;
946         if (*fdp->fd_ifname) {
947                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v);
948                 if (!fdp->fd_ifp)
949                         fdp->fd_ifp = (struct ifnet *)-1;
950                 else
951                         fp->fr_flags |= FR_DUP;
952         }
953
954         fdp = &fp->fr_tif;
955         if (*fdp->fd_ifname) {
956                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v);
957                 if (!fdp->fd_ifp)
958                         fdp->fd_ifp = (struct ifnet *)-1;
959         }
960
961         /*
962          * Look for a matching filter rule, but don't include the next or
963          * interface pointer in the comparison (fr_next, fr_ifa).
964          */
965         for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum;
966              p < pp; p++)
967                 fp->fr_cksum += *p;
968
969         for (; (f = *ftail); ftail = &f->fr_next)
970                 if ((fp->fr_cksum == f->fr_cksum) &&
971                     !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ))
972                         break;
973
974         /*
975          * If zero'ing statistics, copy current to caller and zero.
976          */
977         if (req == SIOCZRLST) {
978                 if (!f)
979                         return ESRCH;
980                 error = IWCOPYPTR((caddr_t)f, data, sizeof(*f));
981                 if (error)
982                         return EFAULT;
983                 f->fr_hits = 0;
984                 f->fr_bytes = 0;
985                 return 0;
986         }
987
988         if (!f) {
989                 if (req != SIOCINAFR && req != SIOCINIFR)
990                         while ((f = *ftail))
991                                 ftail = &f->fr_next;
992                 else {
993                         if (fp->fr_hits) {
994                                 ftail = fprev;
995                                 while (--fp->fr_hits && (f = *ftail))
996                                         ftail = &f->fr_next;
997                         }
998                         f = NULL;
999                 }
1000         }
1001
1002         if (req == SIOCRMAFR || req == SIOCRMIFR) {
1003                 if (!f)
1004                         error = ESRCH;
1005                 else {
1006                         /*
1007                          * Only return EBUSY if there is a group list, else
1008                          * it's probably just state information referencing
1009                          * the rule.
1010                          */
1011                         if ((f->fr_ref > 1) && f->fr_grp)
1012                                 return EBUSY;
1013                         if (fg && fg->fg_head)
1014                                 fg->fg_head->fr_ref--;
1015                         if (f->fr_grhead)
1016                                 fr_delgroup((u_int)f->fr_grhead, fp->fr_flags,
1017                                             unit, set);
1018                         fixskip(fprev, f, -1);
1019                         *ftail = f->fr_next;
1020                         f->fr_next = NULL;
1021                         f->fr_ref--;
1022                         if (f->fr_ref == 0)
1023                                 KFREE(f);
1024                 }
1025         } else {
1026                 if (f)
1027                         error = EEXIST;
1028                 else {
1029                         KMALLOC(f, frentry_t *);
1030                         if (f != NULL) {
1031                                 if (fg && fg->fg_head)
1032                                         fg->fg_head->fr_ref++;
1033                                 bcopy((char *)fp, (char *)f, sizeof(*f));
1034                                 f->fr_ref = 1;
1035                                 f->fr_hits = 0;
1036                                 f->fr_next = *ftail;
1037                                 *ftail = f;
1038                                 if (req == SIOCINIFR || req == SIOCINAFR)
1039                                         fixskip(fprev, f, 1);
1040                                 f->fr_grp = NULL;
1041                                 if ((group = f->fr_grhead))
1042                                         fg = fr_addgroup(group, f, unit, set);
1043                         } else
1044                                 error = ENOMEM;
1045                 }
1046         }
1047         return (error);
1048 }
1049
1050
1051 #ifdef  _KERNEL
1052 /*
1053  * routines below for saving IP headers to buffer
1054  */
1055 # ifdef __sgi
1056 #  ifdef _KERNEL
1057 int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp)
1058 #  else
1059 int IPL_EXTERN(open)(dev_t dev, int flags)
1060 #  endif
1061 # else
1062 int IPL_EXTERN(open)(dev, flags
1063 #  if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
1064      (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
1065 , devtype, td)
1066 int devtype;
1067 struct thread *td;
1068 #  else
1069 )
1070 #  endif
1071 dev_t dev;
1072 int flags;
1073 # endif /* __sgi */
1074 {
1075 # if defined(__sgi) && defined(_KERNEL)
1076         u_int min = geteminor(*pdev);
1077 # else
1078         u_int min = GET_MINOR(dev);
1079 # endif
1080
1081         if (IPL_LOGMAX < min)
1082                 min = ENXIO;
1083         else
1084                 min = 0;
1085         return min;
1086 }
1087
1088
1089 # ifdef __sgi
1090 int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp)
1091 #else
1092 int IPL_EXTERN(close)(dev, flags
1093 #  if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
1094      (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
1095 , devtype, td)
1096 int devtype;
1097 struct thread *td;
1098 #  else
1099 )
1100 #  endif
1101 dev_t dev;
1102 int flags;
1103 # endif /* __sgi */
1104 {
1105         u_int   min = GET_MINOR(dev);
1106
1107         if (IPL_LOGMAX < min)
1108                 min = ENXIO;
1109         else
1110                 min = 0;
1111         return min;
1112 }
1113
1114 /*
1115  * iplread/ipllog
1116  * both of these must operate with at least splnet() lest they be
1117  * called during packet processing and cause an inconsistancy to appear in
1118  * the filter lists.
1119  */
1120 # ifdef __sgi
1121 int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp)
1122 # else
1123 #  if BSD >= 199306
1124 int IPL_EXTERN(read)(dev, uio, ioflag)
1125 int ioflag;
1126 #  else
1127 int IPL_EXTERN(read)(dev, uio)
1128 #  endif
1129 dev_t dev;
1130 register struct uio *uio;
1131 # endif /* __sgi */
1132 {
1133 # ifdef IPFILTER_LOG
1134         return ipflog_read(GET_MINOR(dev), uio);
1135 # else
1136         return ENXIO;
1137 # endif
1138 }
1139
1140
1141 /*
1142  * send_reset - this could conceivably be a call to tcp_respond(), but that
1143  * requires a large amount of setting up and isn't any more efficient.
1144  */
1145 int send_reset(oip, fin)
1146 struct ip *oip;
1147 fr_info_t *fin;
1148 {
1149         struct tcphdr *tcp, *tcp2;
1150         int tlen = 0, hlen;
1151         struct mbuf *m;
1152 #ifdef  USE_INET6
1153         ip6_t *ip6, *oip6 = (ip6_t *)oip;
1154 #endif
1155         ip_t *ip;
1156
1157         tcp = (struct tcphdr *)fin->fin_dp;
1158         if (tcp->th_flags & TH_RST)
1159                 return -1;              /* feedback loop */
1160 # if    (BSD < 199306) || defined(__sgi)
1161         m = m_get(M_DONTWAIT, MT_HEADER);
1162 # else
1163         m = m_gethdr(M_DONTWAIT, MT_HEADER);
1164 # endif
1165         if (m == NULL)
1166                 return ENOBUFS;
1167         if (m == NULL)
1168                 return -1;
1169
1170         tlen = fin->fin_dlen - (tcp->th_off << 2) +
1171                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
1172                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
1173
1174 #ifdef  USE_INET6
1175         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
1176 #else
1177         hlen = sizeof(ip_t);
1178 #endif
1179         m->m_len = sizeof(*tcp2) + hlen;
1180 # if    BSD >= 199306
1181         m->m_data += max_linkhdr;
1182         m->m_pkthdr.len = m->m_len;
1183         m->m_pkthdr.rcvif = (struct ifnet *)0;
1184 # endif
1185         ip = mtod(m, struct ip *);
1186 # ifdef USE_INET6
1187         ip6 = (ip6_t *)ip;
1188 # endif
1189         bzero((char *)ip, sizeof(*tcp2) + hlen);
1190         tcp2 = (struct tcphdr *)((char *)ip + hlen);
1191
1192         tcp2->th_sport = tcp->th_dport;
1193         tcp2->th_dport = tcp->th_sport;
1194         if (tcp->th_flags & TH_ACK) {
1195                 tcp2->th_seq = tcp->th_ack;
1196                 tcp2->th_flags = TH_RST;
1197         } else {
1198                 tcp2->th_ack = ntohl(tcp->th_seq);
1199                 tcp2->th_ack += tlen;
1200                 tcp2->th_ack = htonl(tcp2->th_ack);
1201                 tcp2->th_flags = TH_RST|TH_ACK;
1202         }
1203         tcp2->th_off = sizeof(*tcp2) >> 2;
1204 # ifdef USE_INET6
1205         if (fin->fin_v == 6) {
1206                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
1207                 ip6->ip6_nxt = IPPROTO_TCP;
1208                 ip6->ip6_src = oip6->ip6_dst;
1209                 ip6->ip6_dst = oip6->ip6_src;
1210                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
1211                                          sizeof(*ip6), sizeof(*tcp2));
1212                 return send_ip(oip, fin, &m);
1213         }
1214 # endif
1215         ip->ip_p = IPPROTO_TCP;
1216         ip->ip_len = htons(sizeof(struct tcphdr));
1217         ip->ip_src.s_addr = oip->ip_dst.s_addr;
1218         ip->ip_dst.s_addr = oip->ip_src.s_addr;
1219         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
1220         ip->ip_len = hlen + sizeof(*tcp2);
1221         return send_ip(oip, fin, &m);
1222 }
1223
1224
1225 /*
1226  * Send an IP(v4/v6) datagram out into the network
1227  */
1228 static int send_ip(oip, fin, mp)
1229 ip_t *oip;
1230 fr_info_t *fin;
1231 struct mbuf **mp;
1232 {
1233         struct mbuf *m = *mp;
1234         int error, hlen;
1235         fr_info_t frn;
1236         ip_t *ip;
1237
1238         bzero((char *)&frn, sizeof(frn));
1239         frn.fin_ifp = fin->fin_ifp;
1240         frn.fin_v = fin->fin_v;
1241         frn.fin_out = fin->fin_out;
1242         frn.fin_mp = fin->fin_mp;
1243
1244         ip = mtod(m, ip_t *);
1245         hlen = sizeof(*ip);
1246
1247         ip->ip_v = fin->fin_v;
1248         if (ip->ip_v == 4) {
1249                 ip->ip_hl = (sizeof(*oip) >> 2);
1250                 ip->ip_v = IPVERSION;
1251                 ip->ip_tos = oip->ip_tos;
1252                 ip->ip_id = oip->ip_id;
1253                 ip->ip_off = 0;
1254 # if (BSD < 199306) || defined(__sgi)
1255                 ip->ip_ttl = tcp_ttl;
1256 # else
1257                 ip->ip_ttl = ip_defttl;
1258 # endif
1259                 ip->ip_sum = 0;
1260                 frn.fin_dp = (char *)(ip + 1);
1261         }
1262 # ifdef USE_INET6
1263         else if (ip->ip_v == 6) {
1264                 ip6_t *ip6 = (ip6_t *)ip;
1265
1266                 hlen = sizeof(*ip6);
1267                 ip6->ip6_hlim = 127;
1268                 frn.fin_dp = (char *)(ip6 + 1);
1269         }
1270 # endif
1271 # ifdef IPSEC
1272         m->m_pkthdr.rcvif = NULL;
1273 # endif
1274
1275         fr_makefrip(hlen, ip, &frn);
1276
1277         error = ipfr_fastroute(m, mp, &frn, NULL);
1278         return error;
1279 }
1280
1281
1282 int send_icmp_err(oip, type, fin, dst)
1283 ip_t *oip;
1284 int type;
1285 fr_info_t *fin;
1286 int dst;
1287 {
1288         int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code;
1289         u_short shlen, slen = 0, soff = 0;
1290         struct in_addr dst4;
1291         struct icmp *icmp;
1292         struct mbuf *m;
1293         void *ifp;
1294 #ifdef USE_INET6
1295         ip6_t *ip6, *oip6 = (ip6_t *)oip;
1296         struct in6_addr dst6;
1297 #endif
1298         ip_t *ip;
1299
1300         if ((type < 0) || (type > ICMP_MAXTYPE))
1301                 return -1;
1302
1303         code = fin->fin_icode;
1304 #ifdef USE_INET6
1305         if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
1306                 return -1;
1307 #endif
1308
1309         avail = 0;
1310         m = NULL;
1311         ifp = fin->fin_ifp;
1312         if (fin->fin_v == 4) {
1313                 if ((oip->ip_p == IPPROTO_ICMP) &&
1314                     !(fin->fin_fi.fi_fl & FI_SHORT))
1315                         switch (ntohs(fin->fin_data[0]) >> 8)
1316                         {
1317                         case ICMP_ECHO :
1318                         case ICMP_TSTAMP :
1319                         case ICMP_IREQ :
1320                         case ICMP_MASKREQ :
1321                                 break;
1322                         default :
1323                                 return 0;
1324                         }
1325
1326 # if    (BSD < 199306) || defined(__sgi)
1327                 avail = MLEN;
1328                 m = m_get(M_DONTWAIT, MT_HEADER);
1329 # else
1330                 avail = MHLEN;
1331                 m = m_gethdr(M_DONTWAIT, MT_HEADER);
1332 # endif
1333                 if (m == NULL)
1334                         return ENOBUFS;
1335
1336                 if (dst == 0) {
1337                         if (fr_ifpaddr(4, ifp, &dst4) == -1)
1338                                 return -1;
1339                 } else
1340                         dst4.s_addr = oip->ip_dst.s_addr;
1341
1342                 hlen = sizeof(ip_t);
1343                 ohlen = oip->ip_hl << 2;
1344                 xtra = 8;
1345         }
1346
1347 #ifdef  USE_INET6
1348         else if (fin->fin_v == 6) {
1349                 hlen = sizeof(ip6_t);
1350                 ohlen = sizeof(ip6_t);
1351                 type = icmptoicmp6types[type];
1352                 if (type == ICMP6_DST_UNREACH)
1353                         code = icmptoicmp6unreach[code];
1354
1355                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1356                 if (!m)
1357                         return ENOBUFS;
1358
1359                 MCLGET(m, M_DONTWAIT);
1360                 if ((m->m_flags & M_EXT) == 0) {
1361                         m_freem(m);
1362                         return ENOBUFS;
1363                 }
1364 # ifdef M_TRAILINGSPACE
1365                 m->m_len = 0;
1366                 avail = M_TRAILINGSPACE(m);
1367 # else
1368                 avail = MCLBYTES;
1369 # endif
1370                 xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t),
1371                            avail - hlen - sizeof(*icmp) - max_linkhdr);
1372                 if (dst == 0) {
1373                         if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1)
1374                                 return -1;
1375                 } else
1376                         dst6 = oip6->ip6_dst;
1377         }
1378 #endif
1379
1380         iclen = hlen + sizeof(*icmp);
1381 # if    BSD >= 199306
1382         avail -= (max_linkhdr + iclen);
1383         m->m_data += max_linkhdr;
1384         m->m_pkthdr.rcvif = (struct ifnet *)0;
1385         if (xtra > avail)
1386                 xtra = avail;
1387         iclen += xtra;
1388         m->m_pkthdr.len = iclen;
1389 #else
1390         avail -= (m->m_off + iclen);
1391         if (xtra > avail)
1392                 xtra = avail;
1393         iclen += xtra;
1394 #endif
1395         m->m_len = iclen;
1396         ip = mtod(m, ip_t *);
1397         icmp = (struct icmp *)((char *)ip + hlen);
1398         bzero((char *)ip, iclen);
1399
1400         icmp->icmp_type = type;
1401         icmp->icmp_code = fin->fin_icode;
1402         icmp->icmp_cksum = 0;
1403 #ifdef  icmp_nextmtu
1404         if (type == ICMP_UNREACH &&
1405             fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
1406                 icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu);
1407 #endif
1408
1409         if (avail) {
1410                 bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
1411                 avail -= MIN(ohlen, avail);
1412         }
1413
1414 #ifdef  USE_INET6
1415         ip6 = (ip6_t *)ip;
1416         if (fin->fin_v == 6) {
1417                 ip6->ip6_flow = 0;
1418                 ip6->ip6_plen = htons(iclen - hlen);
1419                 ip6->ip6_nxt = IPPROTO_ICMPV6;
1420                 ip6->ip6_hlim = 0;
1421                 ip6->ip6_src = dst6;
1422                 ip6->ip6_dst = oip6->ip6_src;
1423                 if (avail)
1424                         bcopy((char *)oip + ohlen,
1425                               (char *)&icmp->icmp_ip + ohlen, avail);
1426                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1427                                              sizeof(*ip6), iclen - hlen);
1428         } else
1429 #endif
1430         {
1431                 slen = oip->ip_len;
1432                 oip->ip_len = htons(oip->ip_len);
1433                 soff = oip->ip_off;
1434                 oip->ip_off = htons(ip->ip_off);
1435
1436                 ip->ip_src.s_addr = dst4.s_addr;
1437                 ip->ip_dst.s_addr = oip->ip_src.s_addr;
1438
1439                 if (avail > 8)
1440                         avail = 8;
1441                 if (avail)
1442                         bcopy((char *)oip + ohlen,
1443                               (char *)&icmp->icmp_ip + ohlen, avail);
1444                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
1445                                              sizeof(*icmp) + 8);
1446                 ip->ip_len = iclen;
1447                 ip->ip_p = IPPROTO_ICMP;
1448         }
1449
1450         shlen = fin->fin_hlen;
1451         fin->fin_hlen = hlen;
1452         err = send_ip(oip, fin, &m);
1453         fin->fin_hlen = shlen;
1454 #ifdef  USE_INET6
1455         if (fin->fin_v == 4)
1456 #endif
1457         {
1458                 oip->ip_len = slen;
1459                 oip->ip_off = soff;
1460         }
1461         return err;
1462 }
1463
1464
1465 # if !defined(IPFILTER_LKM) && !defined(__sgi) && \
1466      (!defined(__FreeBSD_version) || (__FreeBSD_version < 300000))
1467 #  if   (BSD < 199306)
1468 int iplinit __P((void));
1469
1470 int
1471 #  else
1472 void iplinit __P((void));
1473
1474 void
1475 #  endif
1476 iplinit()
1477 {
1478
1479 #  if defined(__NetBSD__)
1480         if (ipl_enable() != 0)
1481 #  else
1482         if (iplattach() != 0)
1483 #  endif
1484         {
1485                 printf("IP Filter failed to attach\n");
1486         }
1487         ip_init();
1488 }
1489 # endif /* ! __NetBSD__ */
1490
1491
1492 /*
1493  * Return the length of the entire mbuf.
1494  */
1495 size_t mbufchainlen(m0)
1496 register struct mbuf *m0;
1497 {
1498 #if BSD >= 199306
1499         return m0->m_pkthdr.len;
1500 #else
1501         register size_t len = 0;
1502
1503         for (; m0; m0 = m0->m_next)
1504                 len += m0->m_len;
1505         return len;
1506 #endif
1507 }
1508
1509
1510 int ipfr_fastroute(m0, mpp, fin, fdp)
1511 struct mbuf *m0, **mpp;
1512 fr_info_t *fin;
1513 frdest_t *fdp;
1514 {
1515         register struct ip *ip, *mhip;
1516         register struct mbuf *m = m0;
1517         register struct route *ro;
1518         int len, off, error = 0, hlen, code;
1519         struct ifnet *ifp, *sifp;
1520         struct sockaddr_in *dst;
1521         struct route iproute;
1522         frentry_t *fr;
1523
1524         ip = NULL;
1525         ro = NULL;
1526         ifp = NULL;
1527         ro = &iproute;
1528         ro->ro_rt = NULL;
1529
1530 #ifdef  USE_INET6
1531         if (fin->fin_v == 6) {
1532                 error = ipfr_fastroute6(m0, mpp, fin, fdp);
1533                 if (error != 0)
1534                         goto bad;
1535                 goto done;
1536         }
1537 #else
1538         if (fin->fin_v == 6)
1539                 goto bad;
1540 #endif
1541
1542 #ifdef  M_WRITABLE
1543         /*
1544          * HOT FIX/KLUDGE:
1545          *
1546          * If the mbuf we're about to send is not writable (because of
1547          * a cluster reference, for example) we'll need to make a copy
1548          * of it since this routine modifies the contents.
1549          *
1550          * If you have non-crappy network hardware that can transmit data
1551          * from the mbuf, rather than making a copy, this is gonna be a
1552          * problem.
1553          */
1554         if (M_WRITABLE(m) == 0) {
1555                 if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) {
1556                         m_freem(*mpp);
1557                         *mpp = m0;
1558                         m = m0;
1559                 } else {
1560                         error = ENOBUFS;
1561                         m_freem(*mpp);
1562                         goto done;
1563                 }
1564         }
1565 #endif
1566
1567         hlen = fin->fin_hlen;
1568         ip = mtod(m0, struct ip *);
1569
1570 #if defined(__NetBSD__) && defined(M_CSUM_IPv4)
1571         /*
1572          * Clear any in-bound checksum flags for this packet.
1573          */
1574 # if (__NetBSD_Version__ > 105009999)
1575         m0->m_pkthdr.csum_flags = 0;
1576 # else
1577         m0->m_pkthdr.csuminfo = 0;
1578 # endif
1579 #endif /* __NetBSD__ && M_CSUM_IPv4 */
1580
1581         /*
1582          * Route packet.
1583          */
1584 #ifdef  __sgi
1585         ROUTE_RDLOCK();
1586 #endif
1587         bzero((caddr_t)ro, sizeof (*ro));
1588         dst = (struct sockaddr_in *)&ro->ro_dst;
1589         dst->sin_family = AF_INET;
1590         dst->sin_addr = ip->ip_dst;
1591
1592         fr = fin->fin_fr;
1593         if (fdp != NULL)
1594                 ifp = fdp->fd_ifp;
1595         else
1596                 ifp = fin->fin_ifp;
1597
1598         /*
1599          * In case we're here due to "to <if>" being used with "keep state",
1600          * check that we're going in the correct direction.
1601          */
1602         if ((fr != NULL) && (fin->fin_rev != 0)) {
1603                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
1604                         return 0;
1605         } else if (fdp != NULL) {
1606                 if (fdp->fd_ip.s_addr != 0)
1607                         dst->sin_addr = fdp->fd_ip;
1608         }
1609
1610 # if BSD >= 199306
1611         dst->sin_len = sizeof(*dst);
1612 # endif
1613 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1614         !defined(__OpenBSD__)
1615 #  ifdef        RTF_CLONING
1616         rtalloc_ign(ro, RTF_CLONING);
1617 #  else
1618         rtalloc_ign(ro, RTF_PRCLONING);
1619 #  endif
1620 # else
1621         rtalloc(ro);
1622 # endif
1623
1624 #ifdef  __sgi
1625         ROUTE_UNLOCK();
1626 #endif
1627
1628         if (!ifp) {
1629                 if (!fr || !(fr->fr_flags & FR_FASTROUTE)) {
1630                         error = -2;
1631                         goto bad;
1632                 }
1633         }
1634
1635         if ((ifp == NULL) && (ro->ro_rt != NULL))
1636                 ifp = ro->ro_rt->rt_ifp;
1637
1638         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
1639                 if (in_localaddr(ip->ip_dst))
1640                         error = EHOSTUNREACH;
1641                 else
1642                         error = ENETUNREACH;
1643                 goto bad;
1644         }
1645
1646         if (ro->ro_rt->rt_flags & RTF_GATEWAY) {
1647 #if BSD >= 199306
1648                 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
1649 #else
1650                 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
1651 #endif
1652         }
1653         ro->ro_rt->rt_use++;
1654
1655         /*
1656          * For input packets which are being "fastrouted", they won't
1657          * go back through output filtering and miss their chance to get
1658          * NAT'd and counted.
1659          */
1660         if (fin->fin_out == 0) {
1661                 sifp = fin->fin_ifp;
1662                 fin->fin_ifp = ifp;
1663                 fin->fin_out = 1;
1664                 if ((fin->fin_fr = ipacct[1][fr_active]) &&
1665                     (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
1666                         ATOMIC_INCL(frstats[1].fr_acct);
1667                 }
1668                 fin->fin_fr = NULL;
1669                 if (!fr || !(fr->fr_flags & FR_RETMASK))
1670                         (void) fr_checkstate(ip, fin);
1671                 (void) ip_natout(ip, fin);
1672                 fin->fin_ifp = sifp;
1673         } else
1674                 ip->ip_sum = 0;
1675         /*
1676          * If small enough for interface, can just send directly.
1677          */
1678         if (ip->ip_len <= ifp->if_mtu) {
1679 # ifndef sparc
1680 #  if (!defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510))
1681                 ip->ip_id = htons(ip->ip_id);
1682 #  endif
1683                 ip->ip_len = htons(ip->ip_len);
1684                 ip->ip_off = htons(ip->ip_off);
1685 # endif
1686 # if defined(__NetBSD__) && defined(M_CSUM_IPv4)
1687 #  if (__NetBSD_Version__ > 105009999)
1688                 if (ifp->if_csum_flags_tx & IFCAP_CSUM_IPv4)
1689                         m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
1690                 else if (ip->ip_sum == 0)
1691                         ip->ip_sum = in_cksum(m, hlen);
1692 #  else
1693                 if (ifp->if_capabilities & IFCAP_CSUM_IPv4)
1694                         m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
1695                 else if (ip->ip_sum == 0)
1696                         ip->ip_sum = in_cksum(m, hlen);
1697 #  endif
1698 # else
1699                 if (!ip->ip_sum)
1700                         ip->ip_sum = in_cksum(m, hlen);
1701 # endif /* __NetBSD__ && M_CSUM_IPv4 */
1702 # if    (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
1703                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1704                                           ro->ro_rt);
1705 # else
1706                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
1707 # endif
1708                 goto done;
1709         }
1710
1711         /*
1712          * Too large for interface; fragment if possible.
1713          * Must be able to put at least 8 bytes per fragment.
1714          */
1715         if (ip->ip_off & IP_DF) {
1716                 error = EMSGSIZE;
1717                 goto bad;
1718         }
1719         len = (ifp->if_mtu - hlen) &~ 7;
1720         if (len < 8) {
1721                 error = EMSGSIZE;
1722                 goto bad;
1723         }
1724
1725     {
1726         int mhlen, firstlen = len;
1727         struct mbuf **mnext = &m->m_act;
1728
1729         /*
1730          * Loop through length of segment after first fragment,
1731          * make new header and copy data of each part and link onto chain.
1732          */
1733         m0 = m;
1734         mhlen = sizeof (struct ip);
1735         for (off = hlen + len; off < ip->ip_len; off += len) {
1736 # ifdef MGETHDR
1737                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1738 # else
1739                 MGET(m, M_DONTWAIT, MT_HEADER);
1740 # endif
1741                 if (m == 0) {
1742                         error = ENOBUFS;
1743                         goto bad;
1744                 }
1745 # if BSD >= 199306
1746                 m->m_data += max_linkhdr;
1747 # else
1748                 m->m_off = MMAXOFF - hlen;
1749 # endif
1750                 mhip = mtod(m, struct ip *);
1751                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1752                 if (hlen > sizeof (struct ip)) {
1753                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1754                         mhip->ip_hl = mhlen >> 2;
1755                 }
1756                 m->m_len = mhlen;
1757                 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
1758                 if (ip->ip_off & IP_MF)
1759                         mhip->ip_off |= IP_MF;
1760                 if (off + len >= ip->ip_len)
1761                         len = ip->ip_len - off;
1762                 else
1763                         mhip->ip_off |= IP_MF;
1764                 mhip->ip_len = htons((u_short)(len + mhlen));
1765                 m->m_next = m_copy(m0, off, len);
1766                 if (m->m_next == 0) {
1767                         error = ENOBUFS;        /* ??? */
1768                         goto sendorfree;
1769                 }
1770 # if BSD >= 199306
1771                 m->m_pkthdr.len = mhlen + len;
1772                 m->m_pkthdr.rcvif = NULL;
1773 # endif
1774                 mhip->ip_off = htons((u_short)mhip->ip_off);
1775                 mhip->ip_sum = 0;
1776                 mhip->ip_sum = in_cksum(m, mhlen);
1777                 *mnext = m;
1778                 mnext = &m->m_act;
1779         }
1780         /*
1781          * Update first fragment by trimming what's been copied out
1782          * and updating header, then send each fragment (in order).
1783          */
1784         m_adj(m0, hlen + firstlen - ip->ip_len);
1785         ip->ip_len = htons((u_short)(hlen + firstlen));
1786         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1787         ip->ip_sum = 0;
1788         ip->ip_sum = in_cksum(m0, hlen);
1789 sendorfree:
1790         for (m = m0; m; m = m0) {
1791                 m0 = m->m_act;
1792                 m->m_act = 0;
1793                 if (error == 0)
1794 # if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
1795                         error = (*ifp->if_output)(ifp, m,
1796                             (struct sockaddr *)dst, ro->ro_rt);
1797 # else
1798                         error = (*ifp->if_output)(ifp, m,
1799                             (struct sockaddr *)dst);
1800 # endif
1801                 else
1802                         m_freem(m);
1803         }
1804     }   
1805 done:
1806         if (!error)
1807                 ipl_frouteok[0]++;
1808         else
1809                 ipl_frouteok[1]++;
1810
1811         if (ro->ro_rt != NULL) {
1812                 RTFREE(ro->ro_rt);
1813         }
1814         *mpp = NULL;
1815         return error;
1816 bad:
1817         if ((error == EMSGSIZE) && (fin->fin_v == 4)) {
1818                 sifp = fin->fin_ifp;
1819                 code = fin->fin_icode;
1820                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1821                 fin->fin_ifp = ifp;
1822                 (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1);
1823                 fin->fin_ifp = sifp;
1824                 fin->fin_icode = code;
1825         }
1826         m_freem(m);
1827         goto done;
1828 }
1829
1830
1831 /*
1832  * Return true or false depending on whether the route to the
1833  * given IP address uses the same interface as the one passed.
1834  */
1835 int fr_verifysrc(ipa, ifp)
1836 struct in_addr ipa;
1837 void *ifp;
1838 {
1839         struct sockaddr_in *dst;
1840         struct route iproute;
1841
1842         bzero((char *)&iproute, sizeof(iproute));
1843         dst = (struct sockaddr_in *)&iproute.ro_dst;
1844 # if    (BSD >= 199306)
1845         dst->sin_len = sizeof(*dst);
1846 # endif
1847         dst->sin_family = AF_INET;
1848         dst->sin_addr = ipa;
1849 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1850         !defined(__OpenBSD__)
1851 #  ifdef        RTF_CLONING
1852         rtalloc_ign(&iproute, RTF_CLONING);
1853 #  else
1854         rtalloc_ign(&iproute, RTF_PRCLONING);
1855 #  endif
1856 # else
1857         rtalloc(&iproute);
1858 # endif
1859         if (iproute.ro_rt == NULL)
1860                 return 0;
1861         return (ifp == iproute.ro_rt->rt_ifp);
1862 }
1863
1864
1865 # ifdef USE_GETIFNAME
1866 char *
1867 get_ifname(ifp)
1868 struct ifnet *ifp;
1869 {
1870         static char workbuf[64];
1871
1872         sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit);
1873         return workbuf;
1874 }
1875 # endif
1876
1877
1878 # if defined(USE_INET6)
1879 /*
1880  * This is the IPv6 specific fastroute code.  It doesn't clean up the mbuf's
1881  * or ensure that it is an IPv6 packet that is being forwarded, those are
1882  * expected to be done by the called (ipfr_fastroute).
1883  */
1884 static int ipfr_fastroute6(m0, mpp, fin, fdp)
1885 struct mbuf *m0, **mpp;
1886 fr_info_t *fin;
1887 frdest_t *fdp;
1888 {
1889         struct route_in6 ip6route;
1890         struct sockaddr_in6 *dst6;
1891         struct route_in6 *ro;
1892         struct ifnet *ifp;
1893         frentry_t *fr;
1894         int error;
1895
1896         ifp = NULL;
1897         ro = &ip6route;
1898         fr = fin->fin_fr;
1899         bzero((caddr_t)ro, sizeof(*ro));
1900         dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
1901         dst6->sin6_family = AF_INET6;
1902         dst6->sin6_len = sizeof(struct sockaddr_in6);
1903         dst6->sin6_addr = fin->fin_fi.fi_src.in6;
1904
1905         if (fdp != NULL)
1906                 ifp = fdp->fd_ifp;
1907
1908         if ((fr != NULL) && (fin->fin_rev != 0)) {
1909                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
1910                         return 0;
1911         } else if (fdp != NULL) {
1912                 if (IP6_NOTZERO(&fdp->fd_ip6))
1913                         dst6->sin6_addr = fdp->fd_ip6.in6;
1914         }
1915         if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE)))
1916                 return -2;
1917
1918         rtalloc((struct route *)ro);
1919
1920         if ((ifp == NULL) && (ro->ro_rt != NULL))
1921                 ifp = ro->ro_rt->rt_ifp;
1922
1923         if ((ro->ro_rt == NULL) || (ifp == NULL) ||
1924             (ifp != ro->ro_rt->rt_ifp)) {
1925                 error = EHOSTUNREACH;
1926         } else {
1927                 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
1928                         dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway;
1929                 ro->ro_rt->rt_use++;
1930
1931                 if (m0->m_pkthdr.len <= nd_ifinfo[ifp->if_index].linkmtu)
1932                         error = nd6_output(ifp, fin->fin_ifp, m0, dst6,
1933                                            ro->ro_rt);
1934                 else
1935                         error = EMSGSIZE;
1936         }
1937
1938         if (ro->ro_rt != NULL) {
1939                 RTFREE(ro->ro_rt);
1940         }
1941         return error;
1942 }
1943 # endif
1944 #else /* #ifdef _KERNEL */
1945
1946
1947 # if defined(__sgi) && (IRIX < 605)
1948 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1949                            struct sockaddr *s))
1950 # else
1951 static int no_output __P((struct ifnet *ifp, struct mbuf *m,
1952                            struct sockaddr *s, struct rtentry *rt))
1953 # endif
1954 {
1955         return 0;
1956 }
1957
1958
1959 # ifdef __STDC__
1960 #  if defined(__sgi) && (IRIX < 605)
1961 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1962                              struct sockaddr *s))
1963 #  else
1964 static int write_output __P((struct ifnet *ifp, struct mbuf *m,
1965                              struct sockaddr *s, struct rtentry *rt))
1966 #  endif
1967 {
1968         ip_t *ip = (ip_t *)m;
1969 # else
1970 static int write_output(ifp, ip)
1971 struct ifnet *ifp;
1972 ip_t *ip;
1973 {
1974 # endif
1975         char fname[32];
1976         int fd;
1977
1978 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1979         (defined(OpenBSD) && (OpenBSD >= 199603))
1980         sprintf(fname, "%s", ifp->if_xname);
1981 # else
1982         sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit);
1983 # endif
1984         fd = open(fname, O_WRONLY|O_APPEND);
1985         if (fd == -1) {
1986                 perror("open");
1987                 return -1;
1988         }
1989         write(fd, (char *)ip, ntohs(ip->ip_len));
1990         close(fd);
1991         return 0;
1992 }
1993
1994
1995 char *get_ifname(ifp)
1996 struct ifnet *ifp;
1997 {
1998 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
1999      (defined(OpenBSD) && (OpenBSD >= 199603))
2000         return ifp->if_xname;
2001 # else
2002         static char fullifname[LIFNAMSIZ];
2003
2004         sprintf(fullifname, "%s%d", ifp->if_name, ifp->if_unit);
2005         return fullifname;
2006 # endif
2007 }
2008
2009
2010 struct ifnet *get_unit(ifname, v)
2011 char *ifname;
2012 int v;
2013 {
2014         struct ifnet *ifp, **ifa, **old_ifneta;
2015
2016         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2017 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2018      (defined(OpenBSD) && (OpenBSD >= 199603))
2019                 if (!strncmp(ifname, ifp->if_xname, sizeof(ifp->if_xname)))
2020 # else
2021                 char fullname[LIFNAMSIZ];
2022
2023                 sprintf(fullname, "%s%d", ifp->if_name, ifp->if_unit);
2024                 if (!strcmp(ifname, fullname))
2025 # endif
2026                         return ifp;
2027         }
2028
2029         if (!ifneta) {
2030                 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
2031                 if (!ifneta)
2032                         return NULL;
2033                 ifneta[1] = NULL;
2034                 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
2035                 if (!ifneta[0]) {
2036                         free(ifneta);
2037                         return NULL;
2038                 }
2039                 nifs = 1;
2040         } else {
2041                 old_ifneta = ifneta;
2042                 nifs++;
2043                 ifneta = (struct ifnet **)realloc(ifneta,
2044                                                   (nifs + 1) * sizeof(*ifa));
2045                 if (!ifneta) {
2046                         free(old_ifneta);
2047                         nifs = 0;
2048                         return NULL;
2049                 }
2050                 ifneta[nifs] = NULL;
2051                 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
2052                 if (!ifneta[nifs - 1]) {
2053                         nifs--;
2054                         return NULL;
2055                 }
2056         }
2057         ifp = ifneta[nifs - 1];
2058
2059 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2060      (defined(OpenBSD) && (OpenBSD >= 199603))
2061         strncpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
2062 # else
2063         ifp->if_name = strdup(ifname);
2064
2065         ifname = ifp->if_name;
2066         while (*ifname && !isdigit(*ifname))
2067                 ifname++;
2068         if (*ifname && isdigit(*ifname)) {
2069                 ifp->if_unit = atoi(ifname);
2070                 *ifname = '\0';
2071         } else
2072                 ifp->if_unit = -1;
2073 # endif
2074         ifp->if_output = no_output;
2075         return ifp;
2076 }
2077
2078
2079
2080 void init_ifp()
2081 {
2082         struct ifnet *ifp, **ifa;
2083         char fname[32];
2084         int fd;
2085
2086 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2087         (defined(OpenBSD) && (OpenBSD >= 199603))
2088         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2089                 ifp->if_output = write_output;
2090                 sprintf(fname, "/tmp/%s", ifp->if_xname);
2091                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
2092                 if (fd == -1)
2093                         perror("open");
2094                 else
2095                         close(fd);
2096         }
2097 # else
2098
2099         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2100                 ifp->if_output = write_output;
2101                 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
2102                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
2103                 if (fd == -1)
2104                         perror("open");
2105                 else
2106                         close(fd);
2107         }
2108 # endif
2109 }
2110
2111
2112 int send_reset(ip, fin)
2113 ip_t *ip;
2114 fr_info_t *fin;
2115 {
2116         verbose("- TCP RST sent\n");
2117         return 0;
2118 }
2119
2120
2121 int send_icmp_err(ip, code, fin, dst)
2122 ip_t *ip;
2123 int code;
2124 fr_info_t *fin;
2125 int dst;
2126 {
2127         verbose("- ICMP UNREACHABLE sent\n");
2128         return 0;
2129 }
2130
2131
2132 void frsync()
2133 {
2134         return;
2135 }
2136
2137 void m_copydata(m, off, len, cp)
2138 mb_t *m;
2139 int off, len;
2140 caddr_t cp;
2141 {
2142         bcopy((char *)m + off, cp, len);
2143 }
2144
2145
2146 int ipfuiomove(buf, len, rwflag, uio)
2147 caddr_t buf;
2148 int len, rwflag;
2149 struct uio *uio;
2150 {
2151         int left, ioc, num, offset;
2152         struct iovec *io;
2153         char *start;
2154
2155         if (rwflag == UIO_READ) {
2156                 left = len;
2157                 ioc = 0;
2158
2159                 offset = uio->uio_offset;
2160
2161                 while ((left > 0) && (ioc < uio->uio_iovcnt)) {
2162                         io = uio->uio_iov + ioc;
2163                         num = io->iov_len;
2164                         if (num > left)
2165                                 num = left;
2166                         start = (char *)io->iov_base + offset;
2167                         if (start > (char *)io->iov_base + io->iov_len) {
2168                                 offset -= io->iov_len;
2169                                 ioc++;
2170                                 continue;
2171                         }
2172                         bcopy(buf, start, num);
2173                         uio->uio_resid -= num;
2174                         uio->uio_offset += num;
2175                         left -= num;
2176                         if (left > 0)
2177                                 ioc++;
2178                 }
2179                 if (left > 0)
2180                         return EFAULT;
2181         }
2182         return 0;
2183 }
2184 #endif /* _KERNEL */