Change mbug allocation flags from M_ to MB_ to avoid confusion with malloc
[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.11 2004/06/02 14:42:48 eirikn 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(__DragonFly__) || (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 (defined(__DragonFly__) || __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 defined(__DragonFly__) || (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 defined(__DragonFly__) || __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(__DragonFly__) || (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 <sys/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(__DragonFly__) || 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 (defined(__DragonFly__) || __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 (defined(__DragonFly__) || __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 (defined(__DragonFly__) || __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 #if defined(__DragonFly__) || defined(__FreeBSD__)
665 , td)
666 struct thread *td;
667 # elif (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \
668        (NetBSD >= 199511) || defined(__DragonFly__) || (__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) || (defined(__DragonFly__) || __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(__DragonFly__) || 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 #if defined(__DragonFly__) || defined(__FreeBSD__)
1138 , devtype, td)
1139 int devtype;
1140 struct thread *td;
1141 #elif ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
1142      (defined(__DragonFly__) || __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 #if defined(__DragonFly__) || defined(__FreeBSD__)
1172 , devtype, td)
1173 int devtype;
1174 struct thread *td;
1175 #elif ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
1176      (defined(__DragonFly__) || __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 # elif defined(__DragonFly__)
1245         m = m_get(MB_DONTWAIT, MT_HEADER);
1246 # else
1247         m = m_gethdr(M_DONTWAIT, MT_HEADER);
1248 # endif
1249         if (m == NULL)
1250                 return ENOBUFS;
1251         if (m == NULL)
1252                 return -1;
1253
1254         tlen = fin->fin_dlen - (tcp->th_off << 2) +
1255                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
1256                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
1257
1258 #ifdef  USE_INET6
1259         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
1260 #else
1261         hlen = sizeof(ip_t);
1262 #endif
1263         m->m_len = sizeof(*tcp2) + hlen;
1264 # if    BSD >= 199306
1265         m->m_data += max_linkhdr;
1266         m->m_pkthdr.len = m->m_len;
1267         m->m_pkthdr.rcvif = (struct ifnet *)0;
1268 # endif
1269         ip = mtod(m, struct ip *);
1270 # ifdef USE_INET6
1271         ip6 = (ip6_t *)ip;
1272 # endif
1273         bzero((char *)ip, sizeof(*tcp2) + hlen);
1274         tcp2 = (struct tcphdr *)((char *)ip + hlen);
1275
1276         tcp2->th_sport = tcp->th_dport;
1277         tcp2->th_dport = tcp->th_sport;
1278         if (tcp->th_flags & TH_ACK) {
1279                 tcp2->th_seq = tcp->th_ack;
1280                 tcp2->th_flags = TH_RST;
1281         } else {
1282                 tcp2->th_ack = ntohl(tcp->th_seq);
1283                 tcp2->th_ack += tlen;
1284                 tcp2->th_ack = htonl(tcp2->th_ack);
1285                 tcp2->th_flags = TH_RST|TH_ACK;
1286         }
1287         tcp2->th_off = sizeof(*tcp2) >> 2;
1288 # ifdef USE_INET6
1289         if (fin->fin_v == 6) {
1290                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
1291                 ip6->ip6_nxt = IPPROTO_TCP;
1292                 ip6->ip6_src = oip6->ip6_dst;
1293                 ip6->ip6_dst = oip6->ip6_src;
1294                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
1295                                          sizeof(*ip6), sizeof(*tcp2));
1296                 return send_ip(oip, fin, &m);
1297         }
1298 # endif
1299         ip->ip_p = IPPROTO_TCP;
1300         ip->ip_len = htons(sizeof(struct tcphdr));
1301         ip->ip_src.s_addr = oip->ip_dst.s_addr;
1302         ip->ip_dst.s_addr = oip->ip_src.s_addr;
1303         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
1304         ip->ip_len = hlen + sizeof(*tcp2);
1305         return send_ip(oip, fin, &m);
1306 }
1307
1308
1309 /*
1310  * Send an IP(v4/v6) datagram out into the network
1311  */
1312 static int send_ip(oip, fin, mp)
1313 ip_t *oip;
1314 fr_info_t *fin;
1315 struct mbuf **mp;
1316 {
1317         struct mbuf *m = *mp;
1318         int error, hlen;
1319         fr_info_t frn;
1320         ip_t *ip;
1321
1322         bzero((char *)&frn, sizeof(frn));
1323         frn.fin_ifp = fin->fin_ifp;
1324         frn.fin_v = fin->fin_v;
1325         frn.fin_out = fin->fin_out;
1326         frn.fin_mp = fin->fin_mp;
1327
1328         ip = mtod(m, ip_t *);
1329         hlen = sizeof(*ip);
1330
1331         ip->ip_v = fin->fin_v;
1332         if (ip->ip_v == 4) {
1333                 ip->ip_hl = (sizeof(*oip) >> 2);
1334                 ip->ip_v = IPVERSION;
1335                 ip->ip_tos = oip->ip_tos;
1336                 ip->ip_id = oip->ip_id;
1337
1338 # if defined(__NetBSD__) || \
1339      (defined(__OpenBSD__) && (OpenBSD >= 200012))
1340                 if (ip_mtudisc != 0)
1341                         ip->ip_off = IP_DF;
1342 # else
1343 #  if defined(__sgi)
1344                 if (ip->ip_p == IPPROTO_TCP && tcp_mtudisc != 0)
1345                         ip->ip_off = IP_DF;
1346 #  endif
1347 # endif
1348
1349 # if (BSD < 199306) || defined(__sgi)
1350                 ip->ip_ttl = tcp_ttl;
1351 # else
1352                 ip->ip_ttl = ip_defttl;
1353 # endif
1354                 ip->ip_sum = 0;
1355                 frn.fin_dp = (char *)(ip + 1);
1356         }
1357 # ifdef USE_INET6
1358         else if (ip->ip_v == 6) {
1359                 ip6_t *ip6 = (ip6_t *)ip;
1360
1361                 hlen = sizeof(*ip6);
1362                 ip6->ip6_hlim = 127;
1363                 frn.fin_dp = (char *)(ip6 + 1);
1364         }
1365 # endif
1366 # ifdef IPSEC
1367         m->m_pkthdr.rcvif = NULL;
1368 # endif
1369
1370         fr_makefrip(hlen, ip, &frn);
1371
1372         error = ipfr_fastroute(m, mp, &frn, NULL);
1373         return error;
1374 }
1375
1376
1377 int send_icmp_err(oip, type, fin, dst)
1378 ip_t *oip;
1379 int type;
1380 fr_info_t *fin;
1381 int dst;
1382 {
1383         int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code;
1384         u_short shlen, slen = 0, soff = 0;
1385         struct in_addr dst4;
1386         struct icmp *icmp;
1387         struct mbuf *m;
1388         void *ifp;
1389 #ifdef USE_INET6
1390         ip6_t *ip6, *oip6 = (ip6_t *)oip;
1391         struct in6_addr dst6;
1392 #endif
1393         ip_t *ip;
1394
1395         if ((type < 0) || (type > ICMP_MAXTYPE))
1396                 return -1;
1397
1398         code = fin->fin_icode;
1399 #ifdef USE_INET6
1400         if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
1401                 return -1;
1402 #endif
1403
1404         avail = 0;
1405         m = NULL;
1406         ifp = fin->fin_ifp;
1407         if (fin->fin_v == 4) {
1408                 if ((oip->ip_p == IPPROTO_ICMP) &&
1409                     !(fin->fin_fi.fi_fl & FI_SHORT))
1410                         switch (ntohs(fin->fin_data[0]) >> 8)
1411                         {
1412                         case ICMP_ECHO :
1413                         case ICMP_TSTAMP :
1414                         case ICMP_IREQ :
1415                         case ICMP_MASKREQ :
1416                                 break;
1417                         default :
1418                                 return 0;
1419                         }
1420
1421 # if    (BSD < 199306) || defined(__sgi)
1422                 avail = MLEN;
1423                 m = m_get(M_DONTWAIT, MT_HEADER);
1424 # elif defined(__DragonFly__)
1425                 avail = MHLEN;
1426                 m = m_gethdr(MB_DONTWAIT, MT_HEADER);
1427 # else
1428                 avail = MHLEN;
1429                 m = m_gethdr(M_DONTWAIT, MT_HEADER);
1430 # endif
1431                 if (m == NULL)
1432                         return ENOBUFS;
1433
1434                 if (dst == 0) {
1435                         if (fr_ifpaddr(4, ifp, &dst4) == -1)
1436                                 return -1;
1437                 } else
1438                         dst4.s_addr = oip->ip_dst.s_addr;
1439
1440                 hlen = sizeof(ip_t);
1441                 ohlen = oip->ip_hl << 2;
1442                 xtra = 8;
1443         }
1444
1445 #ifdef  USE_INET6
1446         else if (fin->fin_v == 6) {
1447                 hlen = sizeof(ip6_t);
1448                 ohlen = sizeof(ip6_t);
1449                 type = icmptoicmp6types[type];
1450                 if (type == ICMP6_DST_UNREACH)
1451                         code = icmptoicmp6unreach[code];
1452
1453 #ifdef __DragonFly__
1454                 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
1455 #else
1456                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1457 #endif
1458                 if (!m)
1459                         return ENOBUFS;
1460
1461 #ifdef __DragonFly__
1462                 MCLGET(m, MB_DONTWAIT);
1463 #else
1464                 MCLGET(m, M_DONTWAIT);
1465 #endif
1466                 if ((m->m_flags & M_EXT) == 0) {
1467                         m_freem(m);
1468                         return ENOBUFS;
1469                 }
1470 # ifdef M_TRAILINGSPACE
1471                 m->m_len = 0;
1472                 avail = M_TRAILINGSPACE(m);
1473 # else
1474                 avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
1475 # endif
1476                 xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t),
1477                            avail - hlen - sizeof(*icmp) - max_linkhdr);
1478                 if (dst == 0) {
1479                         if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1)
1480                                 return -1;
1481                 } else
1482                         dst6 = oip6->ip6_dst;
1483         }
1484 #endif
1485
1486         iclen = hlen + sizeof(*icmp);
1487 # if    BSD >= 199306
1488         avail -= (max_linkhdr + iclen);
1489         m->m_data += max_linkhdr;
1490         m->m_pkthdr.rcvif = (struct ifnet *)0;
1491         if (xtra > avail)
1492                 xtra = avail;
1493         iclen += xtra;
1494         m->m_pkthdr.len = iclen;
1495 #else
1496         avail -= (m->m_off + iclen);
1497         if (xtra > avail)
1498                 xtra = avail;
1499         iclen += xtra;
1500 #endif
1501         m->m_len = iclen;
1502         ip = mtod(m, ip_t *);
1503         icmp = (struct icmp *)((char *)ip + hlen);
1504         bzero((char *)ip, iclen);
1505
1506         icmp->icmp_type = type;
1507         icmp->icmp_code = fin->fin_icode;
1508         icmp->icmp_cksum = 0;
1509 #ifdef  icmp_nextmtu
1510         if (type == ICMP_UNREACH &&
1511             fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
1512                 icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu);
1513 #endif
1514
1515         if (avail) {
1516                 bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
1517                 avail -= MIN(ohlen, avail);
1518         }
1519
1520 #ifdef  USE_INET6
1521         ip6 = (ip6_t *)ip;
1522         if (fin->fin_v == 6) {
1523                 ip6->ip6_flow = 0;
1524                 ip6->ip6_plen = htons(iclen - hlen);
1525                 ip6->ip6_nxt = IPPROTO_ICMPV6;
1526                 ip6->ip6_hlim = 0;
1527                 ip6->ip6_src = dst6;
1528                 ip6->ip6_dst = oip6->ip6_src;
1529                 if (avail)
1530                         bcopy((char *)oip + ohlen,
1531                               (char *)&icmp->icmp_ip + ohlen, avail);
1532                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1533                                              sizeof(*ip6), iclen - hlen);
1534         } else
1535 #endif
1536         {
1537                 slen = oip->ip_len;
1538                 oip->ip_len = htons(oip->ip_len);
1539                 soff = oip->ip_off;
1540                 oip->ip_off = htons(ip->ip_off);
1541
1542                 ip->ip_src.s_addr = dst4.s_addr;
1543                 ip->ip_dst.s_addr = oip->ip_src.s_addr;
1544
1545                 if (avail > 8)
1546                         avail = 8;
1547                 if (avail)
1548                         bcopy((char *)oip + ohlen,
1549                               (char *)&icmp->icmp_ip + ohlen, avail);
1550                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
1551                                              sizeof(*icmp) + 8);
1552                 ip->ip_len = iclen;
1553                 ip->ip_p = IPPROTO_ICMP;
1554         }
1555
1556         shlen = fin->fin_hlen;
1557         fin->fin_hlen = hlen;
1558         err = send_ip(oip, fin, &m);
1559         fin->fin_hlen = shlen;
1560 #ifdef  USE_INET6
1561         if (fin->fin_v == 4)
1562 #endif
1563         {
1564                 oip->ip_len = slen;
1565                 oip->ip_off = soff;
1566         }
1567         return err;
1568 }
1569
1570
1571 # if !defined(IPFILTER_LKM) && !defined(__sgi) && \
1572      (!defined(__DragonFly__) || !defined(__FreeBSD_version) || (__FreeBSD_version < 300000))
1573 #  if   (BSD < 199306)
1574 int iplinit (void);
1575
1576 int
1577 #  else
1578 void iplinit (void);
1579
1580 void
1581 #  endif
1582 iplinit()
1583 {
1584
1585 #  if defined(__NetBSD__) || defined(__OpenBSD__)
1586         if (ipl_enable() != 0)
1587 #  else
1588         if (iplattach() != 0)
1589 #  endif
1590         {
1591                 printf("IP Filter failed to attach\n");
1592         }
1593         ip_init();
1594 }
1595 # endif /* ! __NetBSD__ */
1596
1597
1598 /*
1599  * Return the length of the entire mbuf.
1600  */
1601 size_t mbufchainlen(m0)
1602 struct mbuf *m0;
1603 {
1604 #if BSD >= 199306
1605         return m0->m_pkthdr.len;
1606 #else
1607         size_t len = 0;
1608
1609         for (; m0; m0 = m0->m_next)
1610                 len += m0->m_len;
1611         return len;
1612 #endif
1613 }
1614
1615
1616 int ipfr_fastroute(m0, mpp, fin, fdp)
1617 struct mbuf *m0, **mpp;
1618 fr_info_t *fin;
1619 frdest_t *fdp;
1620 {
1621         struct ip *ip, *mhip;
1622         struct mbuf *m = m0;
1623         struct route *ro;
1624         int len, off, error = 0, hlen, code;
1625         struct ifnet *ifp, *sifp;
1626         struct sockaddr_in *dst;
1627         struct route iproute;
1628         frentry_t *fr;
1629
1630         ip = NULL;
1631         ro = NULL;
1632         ifp = NULL;
1633         ro = &iproute;
1634         ro->ro_rt = NULL;
1635
1636 #ifdef  USE_INET6
1637         if (fin->fin_v == 6) {
1638                 error = ipfr_fastroute6(m0, mpp, fin, fdp);
1639                 if (error != 0)
1640                         goto bad;
1641                 goto done;
1642         }
1643 #else
1644         if (fin->fin_v == 6)
1645                 goto bad;
1646 #endif
1647
1648 #ifdef  M_WRITABLE
1649         /*
1650          * HOT FIX/KLUDGE:
1651          *
1652          * If the mbuf we're about to send is not writable (because of
1653          * a cluster reference, for example) we'll need to make a copy
1654          * of it since this routine modifies the contents.
1655          *
1656          * If you have non-crappy network hardware that can transmit data
1657          * from the mbuf, rather than making a copy, this is gonna be a
1658          * problem.
1659          */
1660         if (M_WRITABLE(m) == 0) {
1661 #ifdef __DragonFly__
1662                 if ((m0 = m_dup(m, MB_DONTWAIT)) != NULL) {
1663 #else
1664                 if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) {
1665 #endif
1666                         m_freem(*mpp);
1667                         *mpp = m0;
1668                         m = m0;
1669                 } else {
1670                         error = ENOBUFS;
1671                         m_freem(*mpp);
1672                         goto done;
1673                 }
1674         }
1675 #endif
1676
1677         hlen = fin->fin_hlen;
1678         ip = mtod(m0, struct ip *);
1679
1680 #if defined(__NetBSD__) && defined(M_CSUM_IPv4)
1681         /*
1682          * Clear any in-bound checksum flags for this packet.
1683          */
1684 # if (__NetBSD_Version__ > 105009999)
1685         m0->m_pkthdr.csum_flags = 0;
1686 # else
1687         m0->m_pkthdr.csuminfo = 0;
1688 # endif
1689 #endif /* __NetBSD__ && M_CSUM_IPv4 */
1690
1691         /*
1692          * Route packet.
1693          */
1694 #if defined(__sgi) && (IRIX >= 605)
1695         ROUTE_RDLOCK();
1696 #endif
1697         bzero((caddr_t)ro, sizeof (*ro));
1698         dst = (struct sockaddr_in *)&ro->ro_dst;
1699         dst->sin_family = AF_INET;
1700         dst->sin_addr = ip->ip_dst;
1701
1702         fr = fin->fin_fr;
1703         if (fdp != NULL)
1704                 ifp = fdp->fd_ifp;
1705         else
1706                 ifp = fin->fin_ifp;
1707
1708         /*
1709          * In case we're here due to "to <if>" being used with "keep state",
1710          * check that we're going in the correct direction.
1711          */
1712         if ((fr != NULL) && (fin->fin_rev != 0)) {
1713                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
1714                         return 0;
1715         } else if (fdp != NULL) {
1716                 if (fdp->fd_ip.s_addr != 0)
1717                         dst->sin_addr = fdp->fd_ip;
1718         }
1719
1720 # if BSD >= 199306
1721         dst->sin_len = sizeof(*dst);
1722 # endif
1723 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1724         !defined(__OpenBSD__)
1725 #  ifdef        RTF_CLONING
1726         rtalloc_ign(ro, RTF_CLONING);
1727 #  else
1728         rtalloc_ign(ro, RTF_PRCLONING);
1729 #  endif
1730 # else
1731         rtalloc(ro);
1732 # endif
1733
1734 #if defined(__sgi) && (IRIX > 602)
1735         ROUTE_UNLOCK();
1736 #endif
1737
1738         if (!ifp) {
1739                 if (!fr || !(fr->fr_flags & FR_FASTROUTE)) {
1740                         error = -2;
1741                         goto bad;
1742                 }
1743         }
1744
1745         if ((ifp == NULL) && (ro->ro_rt != NULL))
1746                 ifp = ro->ro_rt->rt_ifp;
1747
1748         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
1749                 if (in_localaddr(ip->ip_dst))
1750                         error = EHOSTUNREACH;
1751                 else
1752                         error = ENETUNREACH;
1753                 goto bad;
1754         }
1755
1756         if (ro->ro_rt->rt_flags & RTF_GATEWAY) {
1757 #if BSD >= 199306
1758                 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
1759 #else
1760                 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
1761 #endif
1762         }
1763         ro->ro_rt->rt_use++;
1764
1765         /*
1766          * For input packets which are being "fastrouted", they won't
1767          * go back through output filtering and miss their chance to get
1768          * NAT'd and counted.
1769          */
1770         if (fin->fin_out == 0) {
1771                 sifp = fin->fin_ifp;
1772                 fin->fin_ifp = ifp;
1773                 fin->fin_out = 1;
1774                 if ((fin->fin_fr = ipacct[1][fr_active]) &&
1775                     (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
1776                         ATOMIC_INCL(frstats[1].fr_acct);
1777                 }
1778                 fin->fin_fr = NULL;
1779                 if (!fr || !(fr->fr_flags & FR_RETMASK))
1780                         (void) fr_checkstate(ip, fin);
1781                 (void) ip_natout(ip, fin);
1782                 fin->fin_ifp = sifp;
1783         } else
1784                 ip->ip_sum = 0;
1785         /*
1786          * If small enough for interface, can just send directly.
1787          */
1788         if (ip->ip_len <= ifp->if_mtu) {
1789 # ifndef sparc
1790 #  if (!defined(__DragonFly__) && !defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510)) && \
1791       !(__NetBSD_Version__ >= 105110000)
1792                 ip->ip_id = htons(ip->ip_id);
1793 #  endif
1794                 ip->ip_len = htons(ip->ip_len);
1795                 ip->ip_off = htons(ip->ip_off);
1796 # endif
1797 # if defined(__NetBSD__) && defined(M_CSUM_IPv4)
1798 #  if (__NetBSD_Version__ > 105009999)
1799                 if (ifp->if_csum_flags_tx & IFCAP_CSUM_IPv4)
1800                         m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
1801                 else if (ip->ip_sum == 0)
1802                         ip->ip_sum = in_cksum(m, hlen);
1803 #  else
1804                 if (ifp->if_capabilities & IFCAP_CSUM_IPv4)
1805                         m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
1806                 else if (ip->ip_sum == 0)
1807                         ip->ip_sum = in_cksum(m, hlen);
1808 #  endif
1809 # else
1810                 if (!ip->ip_sum)
1811                         ip->ip_sum = in_cksum(m, hlen);
1812 # endif /* __NetBSD__ && M_CSUM_IPv4 */
1813 # if    (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
1814                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1815                                           ro->ro_rt);
1816 # else
1817                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
1818 # endif
1819                 goto done;
1820         }
1821
1822         /*
1823          * Too large for interface; fragment if possible.
1824          * Must be able to put at least 8 bytes per fragment.
1825          */
1826         if (ip->ip_off & IP_DF) {
1827                 error = EMSGSIZE;
1828                 goto bad;
1829         }
1830         len = (ifp->if_mtu - hlen) &~ 7;
1831         if (len < 8) {
1832                 error = EMSGSIZE;
1833                 goto bad;
1834         }
1835
1836     {
1837         int mhlen, firstlen = len;
1838         struct mbuf **mnext = &m->m_act;
1839
1840         /*
1841          * Loop through length of segment after first fragment,
1842          * make new header and copy data of each part and link onto chain.
1843          */
1844         m0 = m;
1845         mhlen = sizeof (struct ip);
1846         for (off = hlen + len; off < ip->ip_len; off += len) {
1847 # ifdef __DragonFly__
1848                 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
1849 # elif  defined(MGETHDR)
1850                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1851 # else
1852                 MGET(m, M_DONTWAIT, MT_HEADER);
1853 # endif
1854                 if (m == 0) {
1855                         error = ENOBUFS;
1856                         goto bad;
1857                 }
1858 # if BSD >= 199306
1859                 m->m_data += max_linkhdr;
1860 # else
1861                 m->m_off = MMAXOFF - hlen;
1862 # endif
1863                 mhip = mtod(m, struct ip *);
1864                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1865                 if (hlen > sizeof (struct ip)) {
1866                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1867                         mhip->ip_hl = mhlen >> 2;
1868                 }
1869                 m->m_len = mhlen;
1870                 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
1871                 if (ip->ip_off & IP_MF)
1872                         mhip->ip_off |= IP_MF;
1873                 if (off + len >= ip->ip_len)
1874                         len = ip->ip_len - off;
1875                 else
1876                         mhip->ip_off |= IP_MF;
1877                 mhip->ip_len = htons((u_short)(len + mhlen));
1878                 m->m_next = m_copy(m0, off, len);
1879                 if (m->m_next == 0) {
1880                         error = ENOBUFS;        /* ??? */
1881                         goto sendorfree;
1882                 }
1883 # if BSD >= 199306
1884                 m->m_pkthdr.len = mhlen + len;
1885                 m->m_pkthdr.rcvif = NULL;
1886 # endif
1887                 mhip->ip_off = htons((u_short)mhip->ip_off);
1888                 mhip->ip_sum = 0;
1889                 mhip->ip_sum = in_cksum(m, mhlen);
1890                 *mnext = m;
1891                 mnext = &m->m_act;
1892         }
1893         /*
1894          * Update first fragment by trimming what's been copied out
1895          * and updating header, then send each fragment (in order).
1896          */
1897         m_adj(m0, hlen + firstlen - ip->ip_len);
1898         ip->ip_len = htons((u_short)(hlen + firstlen));
1899         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1900         ip->ip_sum = 0;
1901         ip->ip_sum = in_cksum(m0, hlen);
1902 sendorfree:
1903         for (m = m0; m; m = m0) {
1904                 m0 = m->m_act;
1905                 m->m_act = 0;
1906                 if (error == 0)
1907 # if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
1908                         error = (*ifp->if_output)(ifp, m,
1909                             (struct sockaddr *)dst, ro->ro_rt);
1910 # else
1911                         error = (*ifp->if_output)(ifp, m,
1912                             (struct sockaddr *)dst);
1913 # endif
1914                 else
1915                         m_freem(m);
1916         }
1917     }   
1918 done:
1919         if (!error)
1920                 ipl_frouteok[0]++;
1921         else
1922                 ipl_frouteok[1]++;
1923
1924         if (ro->ro_rt != NULL) {
1925                 RTFREE(ro->ro_rt);
1926         }
1927         *mpp = NULL;
1928         return error;
1929 bad:
1930         if ((error == EMSGSIZE) && (fin->fin_v == 4)) {
1931                 sifp = fin->fin_ifp;
1932                 code = fin->fin_icode;
1933                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1934                 fin->fin_ifp = ifp;
1935                 (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1);
1936                 fin->fin_ifp = sifp;
1937                 fin->fin_icode = code;
1938         }
1939         m_freem(m);
1940         goto done;
1941 }
1942
1943
1944 /*
1945  * Return true or false depending on whether the route to the
1946  * given IP address uses the same interface as the one passed.
1947  */
1948 int fr_verifysrc(ipa, ifp)
1949 struct in_addr ipa;
1950 void *ifp;
1951 {
1952         struct sockaddr_in *dst;
1953         struct route iproute;
1954
1955         bzero((char *)&iproute, sizeof(iproute));
1956         dst = (struct sockaddr_in *)&iproute.ro_dst;
1957 # if    (BSD >= 199306)
1958         dst->sin_len = sizeof(*dst);
1959 # endif
1960         dst->sin_family = AF_INET;
1961         dst->sin_addr = ipa;
1962 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1963         !defined(__OpenBSD__)
1964 #  ifdef        RTF_CLONING
1965         rtalloc_ign(&iproute, RTF_CLONING);
1966 #  else
1967         rtalloc_ign(&iproute, RTF_PRCLONING);
1968 #  endif
1969 # else
1970         rtalloc(&iproute);
1971 # endif
1972         if (iproute.ro_rt == NULL)
1973                 return 0;
1974         return (ifp == iproute.ro_rt->rt_ifp);
1975 }
1976
1977
1978 # ifdef USE_GETIFNAME
1979 char *
1980 get_ifname(ifp)
1981 struct ifnet *ifp;
1982 {
1983         static char workbuf[64];
1984
1985         sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit);
1986         return workbuf;
1987 }
1988 # endif
1989
1990
1991 # if defined(USE_INET6)
1992 /*
1993  * This is the IPv6 specific fastroute code.  It doesn't clean up the mbuf's
1994  * or ensure that it is an IPv6 packet that is being forwarded, those are
1995  * expected to be done by the called (ipfr_fastroute).
1996  */
1997 static int ipfr_fastroute6(m0, mpp, fin, fdp)
1998 struct mbuf *m0, **mpp;
1999 fr_info_t *fin;
2000 frdest_t *fdp;
2001 {
2002         struct route_in6 ip6route;
2003         struct sockaddr_in6 *dst6;
2004         struct route_in6 *ro;
2005         struct ifnet *ifp;
2006         frentry_t *fr;
2007 #if defined(OpenBSD) && (OpenBSD >= 200211)
2008         struct route_in6 *ro_pmtu = NULL;
2009         struct in6_addr finaldst;
2010         ip6_t *ip6;
2011 #endif
2012         u_long mtu;
2013         int error;
2014
2015         ifp = NULL;
2016         ro = &ip6route;
2017         fr = fin->fin_fr;
2018         bzero((caddr_t)ro, sizeof(*ro));
2019         dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
2020         dst6->sin6_family = AF_INET6;
2021         dst6->sin6_len = sizeof(struct sockaddr_in6);
2022         dst6->sin6_addr = fin->fin_fi.fi_src.in6;
2023
2024         if (fdp != NULL)
2025                 ifp = fdp->fd_ifp;
2026
2027         if ((fr != NULL) && (fin->fin_rev != 0)) {
2028                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
2029                         return 0;
2030         } else if (fdp != NULL) {
2031                 if (IP6_NOTZERO(&fdp->fd_ip6))
2032                         dst6->sin6_addr = fdp->fd_ip6.in6;
2033         }
2034         if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE)))
2035                 return -2;
2036
2037         rtalloc((struct route *)ro);
2038
2039         if ((ifp == NULL) && (ro->ro_rt != NULL))
2040                 ifp = ro->ro_rt->rt_ifp;
2041
2042         if ((ro->ro_rt == NULL) || (ifp == NULL) ||
2043             (ifp != ro->ro_rt->rt_ifp)) {
2044                 error = EHOSTUNREACH;
2045         } else {
2046                 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
2047                         dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway;
2048                 ro->ro_rt->rt_use++;
2049
2050 #if defined(OpenBSD) && (OpenBSD >= 200211)
2051                 ip6 = mtod(m0, ip6_t *);
2052                 ro_pmtu = ro;
2053                 finaldst = ip6->ip6_dst;
2054                 error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu);
2055                 if (error == 0) {
2056 #else
2057                         mtu = nd_ifinfo[ifp->if_index].linkmtu;
2058 #endif
2059                         if (m0->m_pkthdr.len <= mtu)
2060                                 error = nd6_output(ifp, fin->fin_ifp, m0,
2061                                                    dst6, ro->ro_rt);
2062                         else
2063                                 error = EMSGSIZE;
2064 #if defined(OpenBSD) && (OpenBSD >= 200211)
2065                 }
2066 #endif
2067         }
2068
2069         if (ro->ro_rt != NULL) {
2070                 RTFREE(ro->ro_rt);
2071         }
2072         return error;
2073 }
2074 # endif
2075 #else /* #ifdef _KERNEL */
2076
2077
2078 # if defined(__sgi) && (IRIX < 605)
2079 static int no_output (struct ifnet *ifp, struct mbuf *m,
2080                            struct sockaddr *s)
2081 # else
2082 static int no_output (struct ifnet *ifp, struct mbuf *m,
2083                            struct sockaddr *s, struct rtentry *rt)
2084 # endif
2085 {
2086         return 0;
2087 }
2088
2089
2090 # ifdef __STDC__
2091 #  if defined(__sgi) && (IRIX < 605)
2092 static int write_output (struct ifnet *ifp, struct mbuf *m,
2093                              struct sockaddr *s)
2094 #  else
2095 static int write_output (struct ifnet *ifp, struct mbuf *m,
2096                              struct sockaddr *s, struct rtentry *rt)
2097 #  endif
2098 {
2099         ip_t *ip = (ip_t *)m;
2100 # else
2101 static int write_output(ifp, ip)
2102 struct ifnet *ifp;
2103 ip_t *ip;
2104 {
2105 # endif
2106         char fname[32];
2107         int fd;
2108
2109 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2110         (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2111         (defined(__DragonFly__))
2112         sprintf(fname, "%s", ifp->if_xname);
2113 # else
2114         sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit);
2115 # endif
2116         fd = open(fname, O_WRONLY|O_APPEND);
2117         if (fd == -1) {
2118                 perror("open");
2119                 return -1;
2120         }
2121         write(fd, (char *)ip, ntohs(ip->ip_len));
2122         close(fd);
2123         return 0;
2124 }
2125
2126
2127 char *get_ifname(ifp)
2128 struct ifnet *ifp;
2129 {
2130 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2131      (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2132      (defined(__DragonFly__))
2133         return ifp->if_xname;
2134 # else
2135         static char fullifname[LIFNAMSIZ];
2136
2137         sprintf(fullifname, "%s%d", ifp->if_name, ifp->if_unit);
2138         return fullifname;
2139 # endif
2140 }
2141
2142
2143 struct ifnet *get_unit(ifname, v)
2144 char *ifname;
2145 int v;
2146 {
2147         struct ifnet *ifp, **ifa, **old_ifneta;
2148
2149         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2150 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2151      (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2152      (defined(__DragonFly__))
2153                 if (!strncmp(ifname, ifp->if_xname, sizeof(ifp->if_xname)))
2154 # else
2155                 char fullname[LIFNAMSIZ];
2156
2157                 sprintf(fullname, "%s%d", ifp->if_name, ifp->if_unit);
2158                 if (!strcmp(ifname, fullname))
2159 # endif
2160                         return ifp;
2161         }
2162
2163         if (!ifneta) {
2164                 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
2165                 if (!ifneta)
2166                         return NULL;
2167                 ifneta[1] = NULL;
2168                 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
2169                 if (!ifneta[0]) {
2170                         free(ifneta);
2171                         return NULL;
2172                 }
2173                 nifs = 1;
2174         } else {
2175                 old_ifneta = ifneta;
2176                 nifs++;
2177                 ifneta = (struct ifnet **)realloc(ifneta,
2178                                                   (nifs + 1) * sizeof(*ifa));
2179                 if (!ifneta) {
2180                         free(old_ifneta);
2181                         nifs = 0;
2182                         return NULL;
2183                 }
2184                 ifneta[nifs] = NULL;
2185                 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
2186                 if (!ifneta[nifs - 1]) {
2187                         nifs--;
2188                         return NULL;
2189                 }
2190         }
2191         ifp = ifneta[nifs - 1];
2192
2193 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2194      (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2195      (defined(__DragonFly__))
2196         strncpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
2197 # else
2198         ifp->if_name = strdup(ifname);
2199
2200         ifname = ifp->if_name;
2201         while (*ifname && !isdigit(*ifname))
2202                 ifname++;
2203         if (*ifname && isdigit(*ifname)) {
2204                 ifp->if_unit = atoi(ifname);
2205                 *ifname = '\0';
2206         } else
2207                 ifp->if_unit = -1;
2208 # endif
2209         ifp->if_output = no_output;
2210         return ifp;
2211 }
2212
2213
2214
2215 void init_ifp()
2216 {
2217         struct ifnet *ifp, **ifa;
2218         char fname[32];
2219         int fd;
2220
2221 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2222         (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2223         (defined(__DragonFly__))
2224         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2225                 ifp->if_output = write_output;
2226                 sprintf(fname, "/tmp/%s", ifp->if_xname);
2227                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
2228                 if (fd == -1)
2229                         perror("open");
2230                 else
2231                         close(fd);
2232         }
2233 # else
2234
2235         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2236                 ifp->if_output = write_output;
2237                 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
2238                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
2239                 if (fd == -1)
2240                         perror("open");
2241                 else
2242                         close(fd);
2243         }
2244 # endif
2245 }
2246
2247
2248 int send_reset(ip, fin)
2249 ip_t *ip;
2250 fr_info_t *fin;
2251 {
2252         verbose("- TCP RST sent\n");
2253         return 0;
2254 }
2255
2256
2257 int send_icmp_err(ip, code, fin, dst)
2258 ip_t *ip;
2259 int code;
2260 fr_info_t *fin;
2261 int dst;
2262 {
2263         verbose("- ICMP UNREACHABLE sent\n");
2264         return 0;
2265 }
2266
2267
2268 void frsync()
2269 {
2270         return;
2271 }
2272
2273 void m_copydata(m, off, len, cp)
2274 mb_t *m;
2275 int off, len;
2276 caddr_t cp;
2277 {
2278         bcopy((char *)m + off, cp, len);
2279 }
2280
2281
2282 int ipfuiomove(buf, len, rwflag, uio)
2283 caddr_t buf;
2284 int len, rwflag;
2285 struct uio *uio;
2286 {
2287         int left, ioc, num, offset;
2288         struct iovec *io;
2289         char *start;
2290
2291         if (rwflag == UIO_READ) {
2292                 left = len;
2293                 ioc = 0;
2294
2295                 offset = uio->uio_offset;
2296
2297                 while ((left > 0) && (ioc < uio->uio_iovcnt)) {
2298                         io = uio->uio_iov + ioc;
2299                         num = io->iov_len;
2300                         if (num > left)
2301                                 num = left;
2302                         start = (char *)io->iov_base + offset;
2303                         if (start > (char *)io->iov_base + io->iov_len) {
2304                                 offset -= io->iov_len;
2305                                 ioc++;
2306                                 continue;
2307                         }
2308                         bcopy(buf, start, num);
2309                         uio->uio_resid -= num;
2310                         uio->uio_offset += num;
2311                         left -= num;
2312                         if (left > 0)
2313                                 ioc++;
2314                 }
2315                 if (left > 0)
2316                         return EFAULT;
2317         }
2318         return 0;
2319 }
2320 #endif /* _KERNEL */