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