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