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