Merge from vendor branch OPENSSH:
[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.14 2004/07/28 00:22:36 hmp 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_handle 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         ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
512 #   else
513         timeout(ipfr_slowtimer, NULL, hz/2);
514 #   endif
515 #  endif
516 # endif
517 #endif
518         return 0;
519 }
520
521
522 /*
523  * Disable the filter by removing the hooks from the IP input/output
524  * stream.
525  */
526 # if defined(__NetBSD__)
527 int ipl_disable()
528 # else
529 int ipldetach()
530 # endif
531 {
532         int s, i;
533 #if defined(NETBSD_PF) && \
534     ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) || \
535      (defined(__DragonFly_version) && (__DragonFly_version >= 100000)))
536         int error = 0;
537 # if (__NetBSD_Version__ >= 105150000) || (__DragonFly_version >= 100000)
538         struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
539 #  ifdef USE_INET6
540         struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
541 #  endif
542 # endif
543 #endif
544
545 #ifdef  _KERNEL
546 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
547         callout_stop(&ipfr_slowtimer_ch);
548 # else
549 #  if (defined(__DragonFly__) || __FreeBSD_version >= 300000)
550         untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch);
551 #  else
552 #  ifdef __sgi
553         untimeout(ipfr_slowtimer_ch);
554 #   else
555 #    if defined(__OpenBSD__)
556         timeout_del(&ipfr_slowtimer_ch);
557 #    else
558         untimeout(ipfr_slowtimer, NULL);
559 #    endif /* OpenBSD */
560 #   endif /* __sgi */
561 #  endif /* FreeBSD */
562 # endif /* NetBSD */
563 #endif
564         SPL_NET(s);
565         if (!fr_running)
566         {
567                 printf("IP Filter: not initialized\n");
568                 SPL_X(s);
569                 return 0;
570         }
571
572         printf("%s unloaded\n", ipfilter_version);
573
574         fr_checkp = fr_savep;
575         i = frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
576         i += frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
577         fr_running = 0;
578
579 # ifdef NETBSD_PF
580 #  if ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) || \
581        (__DragonFly_version >= 100000))
582 #   if (__NetBSD_Version__ >= 105110000) || (__DragonFly_version >= 100000)
583         if (ph_inet != NULL)
584                 error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
585                                          PFIL_IN|PFIL_OUT, ph_inet);
586         else
587                 error = 0;
588 #   else
589         error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
590                                  &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
591 #   endif
592         if (error) {
593                 SPL_X(s);
594                 return error;
595         }
596 #  else
597         pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
598 #  endif
599 #  ifdef USE_INET6
600 #   if (__NetBSD_Version__ >= 105110000) || (__DragonFly_version >= 100000)
601         if (ph_inet6 != NULL)
602                 error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
603                                          PFIL_IN|PFIL_OUT, ph_inet6);
604         else
605                 error = 0;
606 #   else
607         error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
608                                  &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
609 #   endif
610         if (error) {
611                 SPL_X(s);
612                 return error;
613         }
614 #  endif
615 # endif
616
617 # ifdef __sgi
618         ipfilter_sgi_detach();
619 # endif
620
621         appr_unload();
622         ipfr_unload();
623         ip_natunload();
624         fr_stateunload();
625         fr_authunload();
626
627         SPL_X(s);
628         return 0;
629 }
630 #endif /* _KERNEL */
631
632
633 static  int     frzerostats(data)
634 caddr_t data;
635 {
636         friostat_t fio;
637         int error;
638
639         fr_getstat(&fio);
640         error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio));
641         if (error)
642                 return EFAULT;
643
644         bzero((char *)frstats, sizeof(*frstats) * 2);
645
646         return 0;
647 }
648
649
650 /*
651  * Filter ioctl interface.
652  */
653 #ifdef __sgi
654 int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode
655 # ifdef _KERNEL
656         , cred_t *cp, int *rp
657 # endif
658 )
659 #else
660 int IPL_EXTERN(ioctl)(dev, cmd, data, mode
661 #if (defined(_KERNEL) && (defined(__DragonFly__) || defined(__FreeBSD__)))
662 , td)
663 struct thread *td;
664 # elif (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \
665        (NetBSD >= 199511) || defined(__DragonFly__) || (__FreeBSD_version >= 220000) || \
666        defined(__OpenBSD__)))
667 , p)
668 struct proc *p;
669 # else
670 )
671 # endif
672 dev_t dev;
673 # if defined(__NetBSD__) || defined(__OpenBSD__) || \
674         (_BSDI_VERSION >= 199701) || (defined(__DragonFly__) || __FreeBSD_version >= 300000)
675 u_long cmd;
676 # else
677 int cmd;
678 # endif
679 caddr_t data;
680 int mode;
681 #endif /* __sgi */
682 {
683 #if defined(_KERNEL) && !SOLARIS
684         int s;
685 #endif
686         int error = 0, unit = 0, tmp;
687
688 #if (BSD >= 199306) && defined(_KERNEL)
689         if ((securelevel >= 3) && (mode & FWRITE))
690                 return EPERM;
691 #endif
692 #ifdef  _KERNEL
693         unit = GET_MINOR(dev);
694         if ((IPL_LOGMAX < unit) || (unit < 0))
695                 return ENXIO;
696 #else
697         unit = dev;
698 #endif
699
700         if (fr_running == 0 && (cmd != SIOCFRENB || unit != IPL_LOGIPF))
701                 return ENODEV;
702
703         SPL_NET(s);
704
705         if (unit == IPL_LOGNAT) {
706                 if (fr_running)
707                         error = nat_ioctl(data, cmd, mode);
708                 else
709                         error = EIO;
710                 SPL_X(s);
711                 return error;
712         }
713         if (unit == IPL_LOGSTATE) {
714                 if (fr_running)
715                         error = fr_state_ioctl(data, cmd, mode);
716                 else
717                         error = EIO;
718                 SPL_X(s);
719                 return error;
720         }
721         if (unit == IPL_LOGAUTH) {
722                 if (!fr_running)
723                         error = EIO;
724                 else
725                         if ((cmd == SIOCADAFR) || (cmd == SIOCRMAFR)) {
726                                 if (!(mode & FWRITE))  {
727                                         error = EPERM;
728                                 } else {
729                                         error = frrequest(unit, cmd, data,
730                                                           fr_active);
731                                 }
732                         } else {
733                                 error = fr_auth_ioctl(data, mode, cmd);
734                         }
735                 SPL_X(s);
736                 return error;
737         }
738
739         switch (cmd) {
740         case FIONREAD :
741 #ifdef IPFILTER_LOG
742                 error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data,
743                                sizeof(iplused[IPL_LOGIPF]));
744 #endif
745                 break;
746 #if (!defined(IPFILTER_LKM) || defined(__NetBSD__)) && defined(_KERNEL)
747         case SIOCFRENB :
748         {
749                 u_int   enable;
750
751                 if (!(mode & FWRITE))
752                         error = EPERM;
753                 else {
754                         error = IRCOPY(data, (caddr_t)&enable, sizeof(enable));
755                         if (error)
756                                 break;
757                         if (enable)
758 # if defined(__NetBSD__) || defined(__OpenBSD__)
759                                 error = ipl_enable();
760 # else
761                                 error = iplattach();
762 # endif
763                         else
764 # if defined(__NetBSD__)
765                                 error = ipl_disable();
766 # else
767                                 error = ipldetach();
768 # endif
769                 }
770                 break;
771         }
772 #endif
773         case SIOCSETFF :
774                 if (!(mode & FWRITE))
775                         error = EPERM;
776                 else
777                         error = IRCOPY(data, (caddr_t)&fr_flags,
778                                        sizeof(fr_flags));
779                 break;
780         case SIOCGETFF :
781                 error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
782                 break;
783         case SIOCINAFR :
784         case SIOCRMAFR :
785         case SIOCADAFR :
786         case SIOCZRLST :
787                 if (!(mode & FWRITE))
788                         error = EPERM;
789                 else
790                         error = frrequest(unit, cmd, data, fr_active);
791                 break;
792         case SIOCINIFR :
793         case SIOCRMIFR :
794         case SIOCADIFR :
795                 if (!(mode & FWRITE))
796                         error = EPERM;
797                 else
798                         error = frrequest(unit, cmd, data, 1 - fr_active);
799                 break;
800         case SIOCSWAPA :
801                 if (!(mode & FWRITE))
802                         error = EPERM;
803                 else {
804                         bzero((char *)frcache, sizeof(frcache[0]) * 2);
805                         *(u_int *)data = fr_active;
806                         fr_active = 1 - fr_active;
807                 }
808                 break;
809         case SIOCGETFS :
810         {
811                 friostat_t      fio;
812
813                 fr_getstat(&fio);
814                 error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio));
815                 if (error)
816                         error = EFAULT;
817                 break;
818         }
819         case    SIOCFRZST :
820                 if (!(mode & FWRITE))
821                         error = EPERM;
822                 else
823                         error = frzerostats(data);
824                 break;
825         case    SIOCIPFFL :
826                 if (!(mode & FWRITE))
827                         error = EPERM;
828                 else {
829                         error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
830                         if (!error) {
831                                 tmp = frflush(unit, 4, tmp);
832                                 error = IWCOPY((caddr_t)&tmp, data,
833                                                sizeof(tmp));
834                         }
835                 }
836                 break;
837 #ifdef  USE_INET6
838         case    SIOCIPFL6 :
839                 if (!(mode & FWRITE))
840                         error = EPERM;
841                 else {
842                         error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
843                         if (!error) {
844                                 tmp = frflush(unit, 6, tmp);
845                                 error = IWCOPY((caddr_t)&tmp, data,
846                                                sizeof(tmp));
847                         }
848                 }
849                 break;
850 #endif
851         case SIOCSTLCK :
852                 error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
853                 if (!error) {
854                         fr_state_lock = tmp;
855                         fr_nat_lock = tmp;
856                         fr_frag_lock = tmp;
857                         fr_auth_lock = tmp;
858                 } else
859                         error = EFAULT;
860                 break;
861 #ifdef  IPFILTER_LOG
862         case    SIOCIPFFB :
863                 if (!(mode & FWRITE))
864                         error = EPERM;
865                 else
866                         *(int *)data = ipflog_clear(unit);
867                 break;
868 #endif /* IPFILTER_LOG */
869         case SIOCGFRST :
870                 error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data,
871                                   sizeof(ipfrstat_t));
872                 if (error)
873                         error = EFAULT;
874                 break;
875         case SIOCFRSYN :
876                 if (!(mode & FWRITE))
877                         error = EPERM;
878                 else {
879 #if defined(_KERNEL) && defined(__sgi)
880                         ipfsync();
881 #endif
882                         frsync();
883                 }
884                 break;
885         default :
886                 error = EINVAL;
887                 break;
888         }
889         SPL_X(s);
890         return error;
891 }
892
893
894 void fr_forgetifp(ifp)
895 void *ifp;
896 {
897         frentry_t *f;
898
899         WRITE_ENTER(&ipf_mutex);
900         for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
901                 if (f->fr_ifa == ifp)
902                         f->fr_ifa = (void *)-1;
903         for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
904                 if (f->fr_ifa == ifp)
905                         f->fr_ifa = (void *)-1;
906         for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
907                 if (f->fr_ifa == ifp)
908                         f->fr_ifa = (void *)-1;
909         for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
910                 if (f->fr_ifa == ifp)
911                         f->fr_ifa = (void *)-1;
912 #ifdef  USE_INET6
913         for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
914                 if (f->fr_ifa == ifp)
915                         f->fr_ifa = (void *)-1;
916         for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
917                 if (f->fr_ifa == ifp)
918                         f->fr_ifa = (void *)-1;
919         for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
920                 if (f->fr_ifa == ifp)
921                         f->fr_ifa = (void *)-1;
922         for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
923                 if (f->fr_ifa == ifp)
924                         f->fr_ifa = (void *)-1;
925 #endif
926         RWLOCK_EXIT(&ipf_mutex);
927         ip_natsync(ifp);
928 }
929
930
931 static int frrequest(unit, req, data, set)
932 int unit;
933 #if defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
934 u_long req;
935 #else
936 int req;
937 #endif
938 int set;
939 caddr_t data;
940 {
941         frentry_t *fp, *f, **fprev;
942         frentry_t **ftail;
943         frgroup_t *fg = NULL;
944         int error = 0, in, i;
945         u_int   *p, *pp;
946         frentry_t frd;
947         frdest_t *fdp;
948         u_int group;
949
950         fp = &frd;
951         error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp));
952         if (error)
953                 return EFAULT;
954         fp->fr_ref = 0;
955 #if (BSD >= 199306) && defined(_KERNEL)
956         if ((securelevel > 0) && (fp->fr_func != NULL))
957                 return EPERM;
958 #endif
959
960         /*
961          * Check that the group number does exist and that if a head group
962          * has been specified, doesn't exist.
963          */
964         if ((req != SIOCZRLST) && ((req == SIOCINAFR) || (req == SIOCINIFR) ||
965              (req == SIOCADAFR) || (req == SIOCADIFR)) && fp->fr_grhead &&
966             fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL))
967                 return EEXIST;
968         if ((req != SIOCZRLST) && fp->fr_group &&
969             !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL))
970                 return ESRCH;
971
972         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
973
974         if (unit == IPL_LOGAUTH)
975                 ftail = fprev = &ipauth;
976         else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4))
977                 ftail = fprev = &ipacct[in][set];
978         else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4))
979                 ftail = fprev = &ipfilter[in][set];
980 #ifdef  USE_INET6
981         else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6))
982                 ftail = fprev = &ipacct6[in][set];
983         else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6))
984                 ftail = fprev = &ipfilter6[in][set];
985 #endif
986         else
987                 return ESRCH;
988
989         if ((group = fp->fr_group)) {
990                 if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL)))
991                         return ESRCH;
992                 ftail = fprev = fg->fg_start;
993         }
994
995         bzero((char *)frcache, sizeof(frcache[0]) * 2);
996
997         for (i = 0; i < 4; i++) {
998                 if ((fp->fr_ifnames[i][1] == '\0') &&
999                     ((fp->fr_ifnames[i][0] == '-') ||
1000                      (fp->fr_ifnames[i][0] == '*'))) {
1001                         fp->fr_ifas[i] = NULL;
1002                 } else if (*fp->fr_ifnames[i]) {
1003                         fp->fr_ifas[i] = GETUNIT(fp->fr_ifnames[i], fp->fr_v);
1004                         if (!fp->fr_ifas[i])
1005                                 fp->fr_ifas[i] = (void *)-1;
1006                 }
1007         }
1008
1009         fdp = &fp->fr_dif;
1010         fp->fr_flags &= ~FR_DUP;
1011         if (*fdp->fd_ifname) {
1012                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v);
1013                 if (!fdp->fd_ifp)
1014                         fdp->fd_ifp = (struct ifnet *)-1;
1015                 else
1016                         fp->fr_flags |= FR_DUP;
1017         }
1018
1019         fdp = &fp->fr_tif;
1020         if (*fdp->fd_ifname) {
1021                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v);
1022                 if (!fdp->fd_ifp)
1023                         fdp->fd_ifp = (struct ifnet *)-1;
1024         }
1025
1026         /*
1027          * Look for a matching filter rule, but don't include the next or
1028          * interface pointer in the comparison (fr_next, fr_ifa).
1029          */
1030         for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum;
1031              p < pp; p++)
1032                 fp->fr_cksum += *p;
1033
1034         for (; (f = *ftail); ftail = &f->fr_next)
1035                 if ((fp->fr_cksum == f->fr_cksum) &&
1036                     !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ))
1037                         break;
1038
1039         /*
1040          * If zero'ing statistics, copy current to caller and zero.
1041          */
1042         if (req == SIOCZRLST) {
1043                 if (!f)
1044                         return ESRCH;
1045                 error = IWCOPYPTR((caddr_t)f, data, sizeof(*f));
1046                 if (error)
1047                         return EFAULT;
1048                 f->fr_hits = 0;
1049                 f->fr_bytes = 0;
1050                 return 0;
1051         }
1052
1053         if (!f) {
1054                 if (req != SIOCINAFR && req != SIOCINIFR)
1055                         while ((f = *ftail))
1056                                 ftail = &f->fr_next;
1057                 else {
1058                         ftail = fprev;
1059                         if (fp->fr_hits) {
1060                                 while (--fp->fr_hits && (f = *ftail))
1061                                         ftail = &f->fr_next;
1062                         }
1063                         f = NULL;
1064                 }
1065         }
1066
1067         if (req == SIOCRMAFR || req == SIOCRMIFR) {
1068                 if (!f)
1069                         error = ESRCH;
1070                 else {
1071                         /*
1072                          * Only return EBUSY if there is a group list, else
1073                          * it's probably just state information referencing
1074                          * the rule.
1075                          */
1076                         if ((f->fr_ref > 1) && f->fr_grp)
1077                                 return EBUSY;
1078                         if (fg && fg->fg_head)
1079                                 fg->fg_head->fr_ref--;
1080                         if (unit == IPL_LOGAUTH) {
1081                                 return fr_preauthcmd(req, f, ftail);
1082                         }
1083                         if (f->fr_grhead)
1084                                 fr_delgroup((u_int)f->fr_grhead, fp->fr_flags,
1085                                             unit, set);
1086                         fixskip(fprev, f, -1);
1087                         *ftail = f->fr_next;
1088                         f->fr_next = NULL;
1089                         f->fr_ref--;
1090                         if (f->fr_ref == 0)
1091                                 KFREE(f);
1092                 }
1093         } else {
1094                 if (f)
1095                         error = EEXIST;
1096                 else {
1097                         if (unit == IPL_LOGAUTH) {
1098                                 return fr_preauthcmd(req, fp, ftail);
1099                         }
1100                         KMALLOC(f, frentry_t *);
1101                         if (f != NULL) {
1102                                 if (fg && fg->fg_head)
1103                                         fg->fg_head->fr_ref++;
1104                                 bcopy((char *)fp, (char *)f, sizeof(*f));
1105                                 f->fr_ref = 1;
1106                                 f->fr_hits = 0;
1107                                 f->fr_next = *ftail;
1108                                 *ftail = f;
1109                                 if (req == SIOCINIFR || req == SIOCINAFR)
1110                                         fixskip(fprev, f, 1);
1111                                 f->fr_grp = NULL;
1112                                 if ((group = f->fr_grhead))
1113                                         fg = fr_addgroup(group, f, unit, set);
1114                         } else
1115                                 error = ENOMEM;
1116                 }
1117         }
1118         return (error);
1119 }
1120
1121
1122 #ifdef  _KERNEL
1123 /*
1124  * routines below for saving IP headers to buffer
1125  */
1126 # ifdef __sgi
1127 #  ifdef _KERNEL
1128 int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp)
1129 #  else
1130 int IPL_EXTERN(open)(dev_t dev, int flags)
1131 #  endif
1132 # else
1133 int IPL_EXTERN(open)(dev, flags
1134 #if defined(__DragonFly__) || defined(__FreeBSD__)
1135 , devtype, td)
1136 int devtype;
1137 struct thread *td;
1138 #elif ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
1139      (defined(__DragonFly__) || __FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
1140 , devtype, p)
1141 int devtype;
1142 struct proc *p;
1143 #  else
1144 )
1145 #  endif
1146 dev_t dev;
1147 int flags;
1148 # endif /* __sgi */
1149 {
1150 # if defined(__sgi) && defined(_KERNEL)
1151         u_int min = geteminor(*pdev);
1152 # else
1153         u_int min = GET_MINOR(dev);
1154 # endif
1155
1156         if (IPL_LOGMAX < min)
1157                 min = ENXIO;
1158         else
1159                 min = 0;
1160         return min;
1161 }
1162
1163
1164 # ifdef __sgi
1165 int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp)
1166 #else
1167 int IPL_EXTERN(close)(dev, flags
1168 #if defined(__DragonFly__) || defined(__FreeBSD__)
1169 , devtype, td)
1170 int devtype;
1171 struct thread *td;
1172 #elif ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
1173      (defined(__DragonFly__) || __FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
1174 , devtype, p)
1175 int devtype;
1176 struct proc *p;
1177 #  else
1178 )
1179 #  endif
1180 dev_t dev;
1181 int flags;
1182 # endif /* __sgi */
1183 {
1184         u_int   min = GET_MINOR(dev);
1185
1186         if (IPL_LOGMAX < min)
1187                 min = ENXIO;
1188         else
1189                 min = 0;
1190         return min;
1191 }
1192
1193 /*
1194  * iplread/ipllog
1195  * both of these must operate with at least splnet() lest they be
1196  * called during packet processing and cause an inconsistancy to appear in
1197  * the filter lists.
1198  */
1199 # ifdef __sgi
1200 int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp)
1201 # else
1202 #  if BSD >= 199306
1203 int IPL_EXTERN(read)(dev, uio, ioflag)
1204 int ioflag;
1205 #  else
1206 int IPL_EXTERN(read)(dev, uio)
1207 #  endif
1208 dev_t dev;
1209 struct uio *uio;
1210 # endif /* __sgi */
1211 {
1212 # ifdef IPFILTER_LOG
1213         return ipflog_read(GET_MINOR(dev), uio);
1214 # else
1215         return ENXIO;
1216 # endif
1217 }
1218
1219
1220 /*
1221  * send_reset - this could conceivably be a call to tcp_respond(), but that
1222  * requires a large amount of setting up and isn't any more efficient.
1223  */
1224 int send_reset(oip, fin)
1225 struct ip *oip;
1226 fr_info_t *fin;
1227 {
1228         struct tcphdr *tcp, *tcp2;
1229         int tlen = 0, hlen;
1230         struct mbuf *m;
1231 #ifdef  USE_INET6
1232         ip6_t *ip6, *oip6 = (ip6_t *)oip;
1233 #endif
1234         ip_t *ip;
1235
1236         tcp = (struct tcphdr *)fin->fin_dp;
1237         if (tcp->th_flags & TH_RST)
1238                 return -1;              /* feedback loop */
1239 # if    (BSD < 199306) || defined(__sgi)
1240         m = m_get(M_DONTWAIT, MT_HEADER);
1241 # elif defined(__DragonFly__)
1242         m = m_get(MB_DONTWAIT, MT_HEADER);
1243 # else
1244         m = m_gethdr(M_DONTWAIT, MT_HEADER);
1245 # endif
1246         if (m == NULL)
1247                 return ENOBUFS;
1248         if (m == NULL)
1249                 return -1;
1250
1251         tlen = fin->fin_dlen - (tcp->th_off << 2) +
1252                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
1253                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
1254
1255 #ifdef  USE_INET6
1256         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
1257 #else
1258         hlen = sizeof(ip_t);
1259 #endif
1260         m->m_len = sizeof(*tcp2) + hlen;
1261 # if    BSD >= 199306
1262         m->m_data += max_linkhdr;
1263         m->m_pkthdr.len = m->m_len;
1264         m->m_pkthdr.rcvif = (struct ifnet *)0;
1265 # endif
1266         ip = mtod(m, struct ip *);
1267 # ifdef USE_INET6
1268         ip6 = (ip6_t *)ip;
1269 # endif
1270         bzero((char *)ip, sizeof(*tcp2) + hlen);
1271         tcp2 = (struct tcphdr *)((char *)ip + hlen);
1272
1273         tcp2->th_sport = tcp->th_dport;
1274         tcp2->th_dport = tcp->th_sport;
1275         if (tcp->th_flags & TH_ACK) {
1276                 tcp2->th_seq = tcp->th_ack;
1277                 tcp2->th_flags = TH_RST;
1278         } else {
1279                 tcp2->th_ack = ntohl(tcp->th_seq);
1280                 tcp2->th_ack += tlen;
1281                 tcp2->th_ack = htonl(tcp2->th_ack);
1282                 tcp2->th_flags = TH_RST|TH_ACK;
1283         }
1284         tcp2->th_off = sizeof(*tcp2) >> 2;
1285 # ifdef USE_INET6
1286         if (fin->fin_v == 6) {
1287                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
1288                 ip6->ip6_nxt = IPPROTO_TCP;
1289                 ip6->ip6_src = oip6->ip6_dst;
1290                 ip6->ip6_dst = oip6->ip6_src;
1291                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
1292                                          sizeof(*ip6), sizeof(*tcp2));
1293                 return send_ip(oip, fin, &m);
1294         }
1295 # endif
1296         ip->ip_p = IPPROTO_TCP;
1297         ip->ip_len = htons(sizeof(struct tcphdr));
1298         ip->ip_src.s_addr = oip->ip_dst.s_addr;
1299         ip->ip_dst.s_addr = oip->ip_src.s_addr;
1300         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
1301         ip->ip_len = hlen + sizeof(*tcp2);
1302         return send_ip(oip, fin, &m);
1303 }
1304
1305
1306 /*
1307  * Send an IP(v4/v6) datagram out into the network
1308  */
1309 static int send_ip(oip, fin, mp)
1310 ip_t *oip;
1311 fr_info_t *fin;
1312 struct mbuf **mp;
1313 {
1314         struct mbuf *m = *mp;
1315         int error, hlen;
1316         fr_info_t frn;
1317         ip_t *ip;
1318
1319         bzero((char *)&frn, sizeof(frn));
1320         frn.fin_ifp = fin->fin_ifp;
1321         frn.fin_v = fin->fin_v;
1322         frn.fin_out = fin->fin_out;
1323         frn.fin_mp = mp;
1324
1325         ip = mtod(m, ip_t *);
1326         hlen = sizeof(*ip);
1327
1328         ip->ip_v = fin->fin_v;
1329         if (ip->ip_v == 4) {
1330                 ip->ip_hl = (sizeof(*oip) >> 2);
1331                 ip->ip_v = IPVERSION;
1332                 ip->ip_tos = oip->ip_tos;
1333                 ip->ip_id = oip->ip_id;
1334
1335 # if defined(__NetBSD__) || \
1336      (defined(__OpenBSD__) && (OpenBSD >= 200012))
1337                 if (ip_mtudisc != 0)
1338                         ip->ip_off = IP_DF;
1339 # else
1340 #  if defined(__sgi)
1341                 if (ip->ip_p == IPPROTO_TCP && tcp_mtudisc != 0)
1342                         ip->ip_off = IP_DF;
1343 #  endif
1344 # endif
1345
1346 # if (BSD < 199306) || defined(__sgi)
1347                 ip->ip_ttl = tcp_ttl;
1348 # else
1349                 ip->ip_ttl = ip_defttl;
1350 # endif
1351                 ip->ip_sum = 0;
1352                 frn.fin_dp = (char *)(ip + 1);
1353         }
1354 # ifdef USE_INET6
1355         else if (ip->ip_v == 6) {
1356                 ip6_t *ip6 = (ip6_t *)ip;
1357
1358                 hlen = sizeof(*ip6);
1359                 ip6->ip6_hlim = 127;
1360                 frn.fin_dp = (char *)(ip6 + 1);
1361         }
1362 # endif
1363 # ifdef IPSEC
1364         m->m_pkthdr.rcvif = NULL;
1365 # endif
1366
1367         if (fr_makefrip(hlen, ip, &frn) == 0)
1368                 error = ipfr_fastroute(m, mp, &frn, NULL);
1369         else
1370                 error = EINVAL;
1371         return error;
1372 }
1373
1374
1375 int send_icmp_err(oip, type, fin, dst)
1376 ip_t *oip;
1377 int type;
1378 fr_info_t *fin;
1379 int dst;
1380 {
1381         int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code;
1382         u_short shlen, slen = 0, soff = 0;
1383         struct in_addr dst4;
1384         struct icmp *icmp;
1385         struct mbuf *m;
1386         void *ifp;
1387 #ifdef USE_INET6
1388         ip6_t *ip6, *oip6 = (ip6_t *)oip;
1389         struct in6_addr dst6;
1390 #endif
1391         ip_t *ip;
1392
1393         if ((type < 0) || (type > ICMP_MAXTYPE))
1394                 return -1;
1395
1396         code = fin->fin_icode;
1397 #ifdef USE_INET6
1398         if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
1399                 return -1;
1400 #endif
1401
1402         avail = 0;
1403         m = NULL;
1404         ifp = fin->fin_ifp;
1405         if (fin->fin_v == 4) {
1406                 if ((oip->ip_p == IPPROTO_ICMP) &&
1407                     !(fin->fin_fi.fi_fl & FI_SHORT))
1408                         switch (ntohs(fin->fin_data[0]) >> 8)
1409                         {
1410                         case ICMP_ECHO :
1411                         case ICMP_TSTAMP :
1412                         case ICMP_IREQ :
1413                         case ICMP_MASKREQ :
1414                                 break;
1415                         default :
1416                                 return 0;
1417                         }
1418
1419 # if    (BSD < 199306) || defined(__sgi)
1420                 avail = MLEN;
1421                 m = m_get(M_DONTWAIT, MT_HEADER);
1422 # elif defined(__DragonFly__)
1423                 avail = MHLEN;
1424                 m = m_gethdr(MB_DONTWAIT, MT_HEADER);
1425 # else
1426                 avail = MHLEN;
1427                 m = m_gethdr(M_DONTWAIT, MT_HEADER);
1428 # endif
1429                 if (m == NULL)
1430                         return ENOBUFS;
1431
1432                 if (dst == 0) {
1433                         if (fr_ifpaddr(4, ifp, &dst4) == -1)
1434                                 return -1;
1435                 } else
1436                         dst4.s_addr = oip->ip_dst.s_addr;
1437
1438                 hlen = sizeof(ip_t);
1439                 ohlen = oip->ip_hl << 2;
1440                 xtra = 8;
1441         }
1442
1443 #ifdef  USE_INET6
1444         else if (fin->fin_v == 6) {
1445                 hlen = sizeof(ip6_t);
1446                 ohlen = sizeof(ip6_t);
1447                 type = icmptoicmp6types[type];
1448                 if (type == ICMP6_DST_UNREACH)
1449                         code = icmptoicmp6unreach[code];
1450
1451 #ifdef __DragonFly__
1452                 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
1453 #else
1454                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1455 #endif
1456                 if (!m)
1457                         return ENOBUFS;
1458
1459 #ifdef __DragonFly__
1460                 MCLGET(m, MB_DONTWAIT);
1461 #else
1462                 MCLGET(m, M_DONTWAIT);
1463 #endif
1464                 if ((m->m_flags & M_EXT) == 0) {
1465                         m_freem(m);
1466                         return ENOBUFS;
1467                 }
1468 # ifdef M_TRAILINGSPACE
1469                 m->m_len = 0;
1470                 avail = M_TRAILINGSPACE(m);
1471 # else
1472                 avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
1473 # endif
1474                 xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t),
1475                            avail - hlen - sizeof(*icmp) - max_linkhdr);
1476                 if (dst == 0) {
1477                         if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1)
1478                                 return -1;
1479                 } else
1480                         dst6 = oip6->ip6_dst;
1481         }
1482 #endif
1483
1484         iclen = hlen + sizeof(*icmp);
1485 # if    BSD >= 199306
1486         avail -= (max_linkhdr + iclen);
1487         m->m_data += max_linkhdr;
1488         m->m_pkthdr.rcvif = (struct ifnet *)0;
1489         if (xtra > avail)
1490                 xtra = avail;
1491         iclen += xtra;
1492         m->m_pkthdr.len = iclen;
1493 #else
1494         avail -= (m->m_off + iclen);
1495         if (xtra > avail)
1496                 xtra = avail;
1497         iclen += xtra;
1498 #endif
1499         m->m_len = iclen;
1500         ip = mtod(m, ip_t *);
1501         icmp = (struct icmp *)((char *)ip + hlen);
1502         bzero((char *)ip, iclen);
1503
1504         icmp->icmp_type = type;
1505         icmp->icmp_code = fin->fin_icode;
1506         icmp->icmp_cksum = 0;
1507 #ifdef  icmp_nextmtu
1508         if (type == ICMP_UNREACH &&
1509             fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
1510                 icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu);
1511 #endif
1512
1513         if (avail) {
1514                 slen = oip->ip_len;
1515                 oip->ip_len = htons(oip->ip_len);
1516                 soff = oip->ip_off;
1517                 oip->ip_off = htons(oip->ip_off);
1518                 bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
1519                 oip->ip_len = slen;
1520                 oip->ip_off = soff;
1521                 avail -= MIN(ohlen, avail);
1522         }
1523
1524 #ifdef  USE_INET6
1525         ip6 = (ip6_t *)ip;
1526         if (fin->fin_v == 6) {
1527                 ip6->ip6_flow = 0;
1528                 ip6->ip6_plen = htons(iclen - hlen);
1529                 ip6->ip6_nxt = IPPROTO_ICMPV6;
1530                 ip6->ip6_hlim = 0;
1531                 ip6->ip6_src = dst6;
1532                 ip6->ip6_dst = oip6->ip6_src;
1533                 if (avail)
1534                         bcopy((char *)oip + ohlen,
1535                               (char *)&icmp->icmp_ip + ohlen, avail);
1536                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1537                                              sizeof(*ip6), iclen - hlen);
1538         } else
1539 #endif
1540         {
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
1561         return err;
1562 }
1563
1564
1565 # if !defined(IPFILTER_LKM) && !defined(__sgi) && \
1566      (!defined(__DragonFly__) || !defined(__FreeBSD_version) || (__FreeBSD_version < 300000))
1567 #  if   (BSD < 199306)
1568 int iplinit (void);
1569
1570 int
1571 #  else
1572 void iplinit (void);
1573
1574 void
1575 #  endif
1576 iplinit()
1577 {
1578
1579 #  if defined(__NetBSD__) || defined(__OpenBSD__)
1580         if (ipl_enable() != 0)
1581 #  else
1582         if (iplattach() != 0)
1583 #  endif
1584         {
1585                 printf("IP Filter failed to attach\n");
1586         }
1587         ip_init();
1588 }
1589 # endif /* ! __NetBSD__ */
1590
1591
1592 /*
1593  * Return the length of the entire mbuf.
1594  */
1595 size_t mbufchainlen(m0)
1596 struct mbuf *m0;
1597 {
1598 #if BSD >= 199306
1599         return m0->m_pkthdr.len;
1600 #else
1601         size_t len = 0;
1602
1603         for (; m0; m0 = m0->m_next)
1604                 len += m0->m_len;
1605         return len;
1606 #endif
1607 }
1608
1609
1610 int ipfr_fastroute(m0, mpp, fin, fdp)
1611 struct mbuf *m0, **mpp;
1612 fr_info_t *fin;
1613 frdest_t *fdp;
1614 {
1615         struct ip *ip, *mhip;
1616         struct mbuf *m = m0;
1617         struct route *ro;
1618         int len, off, error = 0, hlen, code, sout;
1619         struct ifnet *ifp, *sifp;
1620         struct sockaddr_in *dst;
1621         struct route iproute;
1622         frentry_t *fr;
1623
1624         ip = NULL;
1625         ro = NULL;
1626         ifp = NULL;
1627         ro = &iproute;
1628         ro->ro_rt = NULL;
1629
1630 #ifdef  USE_INET6
1631         if (fin->fin_v == 6) {
1632                 error = ipfr_fastroute6(m0, mpp, fin, fdp);
1633                 if (error != 0)
1634                         goto bad;
1635                 goto done;
1636         }
1637 #else
1638         if (fin->fin_v == 6)
1639                 goto bad;
1640 #endif
1641
1642 #ifdef  M_WRITABLE
1643         /*
1644          * HOT FIX/KLUDGE:
1645          *
1646          * If the mbuf we're about to send is not writable (because of
1647          * a cluster reference, for example) we'll need to make a copy
1648          * of it since this routine modifies the contents.
1649          *
1650          * If you have non-crappy network hardware that can transmit data
1651          * from the mbuf, rather than making a copy, this is gonna be a
1652          * problem.
1653          */
1654         if (M_WRITABLE(m) == 0) {
1655 #ifdef __DragonFly__
1656                 if ((m0 = m_dup(m, MB_DONTWAIT)) != NULL) {
1657 #else
1658                 if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) {
1659 #endif
1660                         m_freem(*mpp);
1661                         *mpp = m0;
1662                         m = m0;
1663                 } else {
1664                         error = ENOBUFS;
1665                         m_freem(*mpp);
1666                         goto done;
1667                 }
1668         }
1669 #endif
1670
1671         hlen = fin->fin_hlen;
1672         ip = mtod(m0, struct ip *);
1673
1674 #if defined(__NetBSD__) && defined(M_CSUM_IPv4)
1675         /*
1676          * Clear any in-bound checksum flags for this packet.
1677          */
1678 # if (__NetBSD_Version__ > 105009999)
1679         m0->m_pkthdr.csum_flags = 0;
1680 # else
1681         m0->m_pkthdr.csuminfo = 0;
1682 # endif
1683 #endif /* __NetBSD__ && M_CSUM_IPv4 */
1684
1685         /*
1686          * Route packet.
1687          */
1688 #if (defined(IRIX) && (IRIX >= 605))
1689         ROUTE_RDLOCK();
1690 #endif
1691         bzero((caddr_t)ro, sizeof (*ro));
1692         dst = (struct sockaddr_in *)&ro->ro_dst;
1693         dst->sin_family = AF_INET;
1694         dst->sin_addr = ip->ip_dst;
1695
1696         fr = fin->fin_fr;
1697         if (fdp != NULL)
1698                 ifp = fdp->fd_ifp;
1699         else
1700                 ifp = fin->fin_ifp;
1701
1702         /*
1703          * In case we're here due to "to <if>" being used with "keep state",
1704          * check that we're going in the correct direction.
1705          */
1706         if ((fr != NULL) && (fin->fin_rev != 0)) {
1707                 if ((ifp != NULL) && (fdp == &fr->fr_tif)) {
1708 # if (defined(IRIX) && (IRIX >= 605))
1709                         ROUTE_UNLOCK();
1710 # endif
1711                         return 0;
1712                 }
1713         } else if (fdp != NULL) {
1714                 if (fdp->fd_ip.s_addr != 0)
1715                         dst->sin_addr = fdp->fd_ip;
1716         }
1717
1718 # if BSD >= 199306
1719         dst->sin_len = sizeof(*dst);
1720 # endif
1721 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1722         !defined(__OpenBSD__)
1723 #  ifdef        RTF_CLONING
1724         rtalloc_ign(ro, RTF_CLONING);
1725 #  else
1726         rtalloc_ign(ro, RTF_PRCLONING);
1727 #  endif
1728 # else
1729         rtalloc(ro);
1730 # endif
1731
1732         if (!ifp) {
1733                 if (!fr || !(fr->fr_flags & FR_FASTROUTE)) {
1734                         error = -2;
1735 # if (defined(IRIX) && (IRIX >= 605))
1736                         ROUTE_UNLOCK();
1737 # endif
1738                         goto bad;
1739                 }
1740         }
1741
1742         if ((ifp == NULL) && (ro->ro_rt != NULL))
1743                 ifp = ro->ro_rt->rt_ifp;
1744
1745         if ((ro->ro_rt == NULL) || (ifp == NULL)) {
1746                 if (in_localaddr(ip->ip_dst))
1747                         error = EHOSTUNREACH;
1748                 else
1749                         error = ENETUNREACH;
1750 # if (defined(IRIX) && (IRIX >= 605))
1751                         ROUTE_UNLOCK();
1752 # endif
1753                 goto bad;
1754         }
1755
1756         if (ro->ro_rt->rt_flags & RTF_GATEWAY) {
1757 #if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
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 #if (defined(IRIX) && (IRIX > 602))
1766         ROUTE_UNLOCK();
1767 #endif
1768
1769         /*
1770          * For input packets which are being "fastrouted", they won't
1771          * go back through output filtering and miss their chance to get
1772          * NAT'd and counted.
1773          */
1774         if (fin->fin_out == 0) {
1775                 sifp = fin->fin_ifp;
1776                 sout = fin->fin_out;
1777                 fin->fin_ifp = ifp;
1778                 fin->fin_out = 1;
1779                 if ((fin->fin_fr = ipacct[1][fr_active]) &&
1780                     (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
1781                         ATOMIC_INCL(frstats[1].fr_acct);
1782                 }
1783                 fin->fin_fr = NULL;
1784                 if (!fr || !(fr->fr_flags & FR_RETMASK))
1785                         (void) fr_checkstate(ip, fin);
1786
1787                 switch (ip_natout(ip, fin))
1788                 {
1789                 case 0 :
1790                         break;
1791                 case 1 :
1792                         ip->ip_sum = 0;
1793                         break;
1794                 case -1 :
1795                         error = EINVAL;
1796                         goto done;
1797                         break;
1798                 }
1799
1800                 fin->fin_ifp = sifp;
1801                 fin->fin_out = sout;
1802         } else
1803                 ip->ip_sum = 0;
1804
1805         /*
1806          * If small enough for interface, can just send directly.
1807          */
1808         if (ip->ip_len <= ifp->if_mtu) {
1809 # ifndef sparc
1810 #  if (!defined(__DragonFly__) && !defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510)) && \
1811       !(__NetBSD_Version__ >= 105110000)
1812                 ip->ip_id = htons(ip->ip_id);
1813 #  endif
1814                 ip->ip_len = htons(ip->ip_len);
1815                 ip->ip_off = htons(ip->ip_off);
1816 # endif
1817 # if defined(__NetBSD__) && defined(M_CSUM_IPv4)
1818 #  if (__NetBSD_Version__ > 105009999)
1819                 if (ifp->if_csum_flags_tx & IFCAP_CSUM_IPv4)
1820                         m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
1821                 else if (ip->ip_sum == 0)
1822                         ip->ip_sum = in_cksum(m, hlen);
1823 #  else
1824                 if (ifp->if_capabilities & IFCAP_CSUM_IPv4)
1825                         m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
1826                 else if (ip->ip_sum == 0)
1827                         ip->ip_sum = in_cksum(m, hlen);
1828 #  endif
1829 # else
1830                 if (!ip->ip_sum)
1831                         ip->ip_sum = in_cksum(m, hlen);
1832 # endif /* __NetBSD__ && M_CSUM_IPv4 */
1833 # if    (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
1834 #  ifdef IRIX
1835                 IFNET_UPPERLOCK(ifp);
1836 #  endif
1837                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1838                                           ro->ro_rt);
1839 #  ifdef IRIX
1840                 IFNET_UPPERUNLOCK(ifp);
1841 #  endif
1842 # else
1843                 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
1844 # endif
1845                 goto done;
1846         }
1847
1848         /*
1849          * Too large for interface; fragment if possible.
1850          * Must be able to put at least 8 bytes per fragment.
1851          */
1852         if (ip->ip_off & IP_DF) {
1853                 error = EMSGSIZE;
1854                 goto bad;
1855         }
1856         len = (ifp->if_mtu - hlen) &~ 7;
1857         if (len < 8) {
1858                 error = EMSGSIZE;
1859                 goto bad;
1860         }
1861
1862     {
1863         int mhlen, firstlen = len;
1864         struct mbuf **mnext = &m->m_act;
1865
1866         /*
1867          * Loop through length of segment after first fragment,
1868          * make new header and copy data of each part and link onto chain.
1869          */
1870         m0 = m;
1871         mhlen = sizeof (struct ip);
1872         for (off = hlen + len; off < ip->ip_len; off += len) {
1873 # ifdef __DragonFly__
1874                 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
1875 # elif  defined(MGETHDR)
1876                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1877 # else
1878                 MGET(m, M_DONTWAIT, MT_HEADER);
1879 # endif
1880                 if (m == 0) {
1881                         error = ENOBUFS;
1882                         goto bad;
1883                 }
1884 # if BSD >= 199306
1885                 m->m_data += max_linkhdr;
1886 # else
1887                 m->m_off = MMAXOFF - hlen;
1888 # endif
1889                 mhip = mtod(m, struct ip *);
1890                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1891                 if (hlen > sizeof (struct ip)) {
1892                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1893                         mhip->ip_hl = mhlen >> 2;
1894                 }
1895                 m->m_len = mhlen;
1896                 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
1897                 if (ip->ip_off & IP_MF)
1898                         mhip->ip_off |= IP_MF;
1899                 if (off + len >= ip->ip_len)
1900                         len = ip->ip_len - off;
1901                 else
1902                         mhip->ip_off |= IP_MF;
1903                 mhip->ip_len = htons((u_short)(len + mhlen));
1904                 m->m_next = m_copy(m0, off, len);
1905                 if (m->m_next == 0) {
1906                         error = ENOBUFS;        /* ??? */
1907                         goto sendorfree;
1908                 }
1909 # if BSD >= 199306
1910                 m->m_pkthdr.len = mhlen + len;
1911                 m->m_pkthdr.rcvif = NULL;
1912 # endif
1913                 mhip->ip_off = htons((u_short)mhip->ip_off);
1914                 mhip->ip_sum = 0;
1915                 mhip->ip_sum = in_cksum(m, mhlen);
1916                 *mnext = m;
1917                 mnext = &m->m_act;
1918         }
1919         /*
1920          * Update first fragment by trimming what's been copied out
1921          * and updating header, then send each fragment (in order).
1922          */
1923         m_adj(m0, hlen + firstlen - ip->ip_len);
1924         ip->ip_len = htons((u_short)(hlen + firstlen));
1925         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
1926         ip->ip_sum = 0;
1927         ip->ip_sum = in_cksum(m0, hlen);
1928 sendorfree:
1929         for (m = m0; m; m = m0) {
1930                 m0 = m->m_act;
1931                 m->m_act = 0;
1932                 if (error == 0)
1933 # if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
1934                         error = (*ifp->if_output)(ifp, m,
1935                             (struct sockaddr *)dst, ro->ro_rt);
1936 # else
1937                         error = (*ifp->if_output)(ifp, m,
1938                             (struct sockaddr *)dst);
1939 # endif
1940                 else
1941                         m_freem(m);
1942         }
1943     }   
1944 done:
1945         if (!error)
1946                 ipl_frouteok[0]++;
1947         else
1948                 ipl_frouteok[1]++;
1949
1950         if (ro->ro_rt != NULL) {
1951                 RTFREE(ro->ro_rt);
1952         }
1953         *mpp = NULL;
1954         return error;
1955 bad:
1956         if ((error == EMSGSIZE) && (fin->fin_v == 4)) {
1957                 sifp = fin->fin_ifp;
1958                 code = fin->fin_icode;
1959                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1960                 fin->fin_ifp = ifp;
1961                 (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1);
1962                 fin->fin_ifp = sifp;
1963                 fin->fin_icode = code;
1964         }
1965         m_freem(m);
1966         goto done;
1967 }
1968
1969
1970 /*
1971  * Return true or false depending on whether the route to the
1972  * given IP address uses the same interface as the one passed.
1973  */
1974 int fr_verifysrc(ipa, ifp)
1975 struct in_addr ipa;
1976 void *ifp;
1977 {
1978         struct sockaddr_in *dst;
1979         struct route iproute;
1980
1981         bzero((char *)&iproute, sizeof(iproute));
1982         dst = (struct sockaddr_in *)&iproute.ro_dst;
1983 # if    (BSD >= 199306)
1984         dst->sin_len = sizeof(*dst);
1985 # endif
1986         dst->sin_family = AF_INET;
1987         dst->sin_addr = ipa;
1988 # if    (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \
1989         !defined(__OpenBSD__)
1990 #  ifdef        RTF_CLONING
1991         rtalloc_ign(&iproute, RTF_CLONING);
1992 #  else
1993         rtalloc_ign(&iproute, RTF_PRCLONING);
1994 #  endif
1995 # else
1996         rtalloc(&iproute);
1997 # endif
1998         if (iproute.ro_rt == NULL)
1999                 return 0;
2000         return (ifp == iproute.ro_rt->rt_ifp);
2001 }
2002
2003
2004 # ifdef USE_GETIFNAME
2005 char *
2006 get_ifname(ifp)
2007 struct ifnet *ifp;
2008 {
2009         static char workbuf[64];
2010
2011         sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit);
2012         return workbuf;
2013 }
2014 # endif
2015
2016
2017 # if defined(USE_INET6)
2018 /*
2019  * This is the IPv6 specific fastroute code.  It doesn't clean up the mbuf's
2020  * or ensure that it is an IPv6 packet that is being forwarded, those are
2021  * expected to be done by the called (ipfr_fastroute).
2022  */
2023 static int ipfr_fastroute6(m0, mpp, fin, fdp)
2024 struct mbuf *m0, **mpp;
2025 fr_info_t *fin;
2026 frdest_t *fdp;
2027 {
2028         struct route_in6 ip6route;
2029         struct sockaddr_in6 *dst6;
2030         struct route_in6 *ro;
2031         struct ifnet *ifp;
2032         frentry_t *fr;
2033 #if defined(OpenBSD) && (OpenBSD >= 200211)
2034         struct route_in6 *ro_pmtu = NULL;
2035         struct in6_addr finaldst;
2036         ip6_t *ip6;
2037 #endif
2038         u_long mtu;
2039         int error;
2040
2041         ro = &ip6route;
2042         fr = fin->fin_fr;
2043         bzero((caddr_t)ro, sizeof(*ro));
2044         dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
2045         dst6->sin6_family = AF_INET6;
2046         dst6->sin6_len = sizeof(struct sockaddr_in6);
2047         dst6->sin6_addr = fin->fin_fi.fi_dst.in6;
2048
2049         if (fdp != NULL)
2050                 ifp = fdp->fd_ifp;
2051         else
2052                 ifp = fin->fin_ifp;
2053
2054         if ((fr != NULL) && (fin->fin_rev != 0)) {
2055                 if ((ifp != NULL) && (fdp == &fr->fr_tif))
2056                         return 0;
2057         } else if (fdp != NULL) {
2058                 if (IP6_NOTZERO(&fdp->fd_ip6))
2059                         dst6->sin6_addr = fdp->fd_ip6.in6;
2060         }
2061         if (ifp == NULL)
2062                 return -2;
2063
2064 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
2065         /* KAME */
2066         if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr))
2067                 dst6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
2068 #endif
2069         rtalloc((struct route *)ro);
2070
2071         if ((ifp == NULL) && (ro->ro_rt != NULL))
2072                 ifp = ro->ro_rt->rt_ifp;
2073
2074         if ((ro->ro_rt == NULL) || (ifp == NULL) ||
2075             (ifp != ro->ro_rt->rt_ifp)) {
2076                 error = EHOSTUNREACH;
2077         } else {
2078                 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
2079                         dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway;
2080                 ro->ro_rt->rt_use++;
2081
2082 #if defined(OpenBSD) && (OpenBSD >= 200211)
2083                 ip6 = mtod(m0, ip6_t *);
2084                 ro_pmtu = ro;
2085                 finaldst = ip6->ip6_dst;
2086                 error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu);
2087                 if (error == 0) {
2088 #else
2089                         mtu = nd_ifinfo[ifp->if_index].linkmtu;
2090 #endif
2091                         if (m0->m_pkthdr.len <= mtu)
2092                                 error = nd6_output(ifp, fin->fin_ifp, m0,
2093                                                    dst6, ro->ro_rt);
2094                         else
2095                                 error = EMSGSIZE;
2096 #if defined(OpenBSD) && (OpenBSD >= 200211)
2097                 }
2098 #endif
2099         }
2100
2101         if (ro->ro_rt != NULL) {
2102                 RTFREE(ro->ro_rt);
2103         }
2104         return error;
2105 }
2106 # endif
2107 #else /* #ifdef _KERNEL */
2108
2109
2110 # if defined(__sgi) && (IRIX < 605)
2111 static int no_output (struct ifnet *ifp, struct mbuf *m,
2112                            struct sockaddr *s)
2113 # else
2114 static int no_output (struct ifnet *ifp, struct mbuf *m,
2115                            struct sockaddr *s, struct rtentry *rt)
2116 # endif
2117 {
2118         return 0;
2119 }
2120
2121
2122 # ifdef __STDC__
2123 #  if defined(__sgi) && (IRIX < 605)
2124 static int write_output (struct ifnet *ifp, struct mbuf *m,
2125                              struct sockaddr *s)
2126 #  else
2127 static int write_output (struct ifnet *ifp, struct mbuf *m,
2128                              struct sockaddr *s, struct rtentry *rt)
2129 #  endif
2130 {
2131         ip_t *ip = (ip_t *)m;
2132 # else
2133 static int write_output(ifp, ip)
2134 struct ifnet *ifp;
2135 ip_t *ip;
2136 {
2137 # endif
2138         char fname[32];
2139         int fd;
2140
2141 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2142         (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2143         (defined(__DragonFly__))
2144         sprintf(fname, "%s", ifp->if_xname);
2145 # else
2146         sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit);
2147 # endif
2148         fd = open(fname, O_WRONLY|O_APPEND);
2149         if (fd == -1) {
2150                 perror("open");
2151                 return -1;
2152         }
2153         write(fd, (char *)ip, ntohs(ip->ip_len));
2154         close(fd);
2155         return 0;
2156 }
2157
2158
2159 char *get_ifname(ifp)
2160 struct ifnet *ifp;
2161 {
2162 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2163      (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2164      (defined(__DragonFly__))
2165         return ifp->if_xname;
2166 # else
2167         static char fullifname[LIFNAMSIZ];
2168
2169         sprintf(fullifname, "%s%d", ifp->if_name, ifp->if_unit);
2170         return fullifname;
2171 # endif
2172 }
2173
2174
2175 struct ifnet *get_unit(ifname, v)
2176 char *ifname;
2177 int v;
2178 {
2179         struct ifnet *ifp, **ifa, **old_ifneta;
2180
2181         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2182 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2183      (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2184      (defined(__DragonFly__))
2185                 if (!strncmp(ifname, ifp->if_xname, sizeof(ifp->if_xname)))
2186 # else
2187                 char fullname[LIFNAMSIZ];
2188
2189                 sprintf(fullname, "%s%d", ifp->if_name, ifp->if_unit);
2190                 if (!strcmp(ifname, fullname))
2191 # endif
2192                         return ifp;
2193         }
2194
2195         if (!ifneta) {
2196                 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
2197                 if (!ifneta)
2198                         return NULL;
2199                 ifneta[1] = NULL;
2200                 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
2201                 if (!ifneta[0]) {
2202                         free(ifneta);
2203                         return NULL;
2204                 }
2205                 nifs = 1;
2206         } else {
2207                 old_ifneta = ifneta;
2208                 nifs++;
2209                 ifneta = (struct ifnet **)realloc(ifneta,
2210                                                   (nifs + 1) * sizeof(*ifa));
2211                 if (!ifneta) {
2212                         free(old_ifneta);
2213                         nifs = 0;
2214                         return NULL;
2215                 }
2216                 ifneta[nifs] = NULL;
2217                 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
2218                 if (!ifneta[nifs - 1]) {
2219                         nifs--;
2220                         return NULL;
2221                 }
2222         }
2223         ifp = ifneta[nifs - 1];
2224
2225 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2226      (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2227      (defined(__DragonFly__))
2228         strncpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
2229 # else
2230         ifp->if_name = strdup(ifname);
2231
2232         ifname = ifp->if_name;
2233         while (*ifname && !isdigit(*ifname))
2234                 ifname++;
2235         if (*ifname && isdigit(*ifname)) {
2236                 ifp->if_unit = atoi(ifname);
2237                 *ifname = '\0';
2238         } else
2239                 ifp->if_unit = -1;
2240 # endif
2241         ifp->if_output = no_output;
2242         return ifp;
2243 }
2244
2245
2246
2247 void init_ifp()
2248 {
2249         struct ifnet *ifp, **ifa;
2250         char fname[32];
2251         int fd;
2252
2253 # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
2254         (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2255         (defined(__DragonFly__))
2256         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2257                 ifp->if_output = write_output;
2258                 sprintf(fname, "/tmp/%s", ifp->if_xname);
2259                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
2260                 if (fd == -1)
2261                         perror("open");
2262                 else
2263                         close(fd);
2264         }
2265 # else
2266
2267         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
2268                 ifp->if_output = write_output;
2269                 sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
2270                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
2271                 if (fd == -1)
2272                         perror("open");
2273                 else
2274                         close(fd);
2275         }
2276 # endif
2277 }
2278
2279
2280 int send_reset(ip, fin)
2281 ip_t *ip;
2282 fr_info_t *fin;
2283 {
2284         verbose("- TCP RST sent\n");
2285         return 0;
2286 }
2287
2288
2289 int send_icmp_err(ip, code, fin, dst)
2290 ip_t *ip;
2291 int code;
2292 fr_info_t *fin;
2293 int dst;
2294 {
2295         verbose("- ICMP UNREACHABLE sent\n");
2296         return 0;
2297 }
2298
2299
2300 void frsync()
2301 {
2302         return;
2303 }
2304
2305 void m_copydata(m, off, len, cp)
2306 mb_t *m;
2307 int off, len;
2308 caddr_t cp;
2309 {
2310         bcopy((char *)m + off, cp, len);
2311 }
2312
2313
2314 int ipfuiomove(buf, len, rwflag, uio)
2315 caddr_t buf;
2316 int len, rwflag;
2317 struct uio *uio;
2318 {
2319         int left, ioc, num, offset;
2320         struct iovec *io;
2321         char *start;
2322
2323         if (rwflag == UIO_READ) {
2324                 left = len;
2325                 ioc = 0;
2326
2327                 offset = uio->uio_offset;
2328
2329                 while ((left > 0) && (ioc < uio->uio_iovcnt)) {
2330                         io = uio->uio_iov + ioc;
2331                         num = io->iov_len;
2332                         if (num > left)
2333                                 num = left;
2334                         start = (char *)io->iov_base + offset;
2335                         if (start > (char *)io->iov_base + io->iov_len) {
2336                                 offset -= io->iov_len;
2337                                 ioc++;
2338                                 continue;
2339                         }
2340                         bcopy(buf, start, num);
2341                         uio->uio_resid -= num;
2342                         uio->uio_offset += num;
2343                         left -= num;
2344                         if (left > 0)
2345                                 ioc++;
2346                 }
2347                 if (left > 0)
2348                         return EFAULT;
2349         }
2350         return 0;
2351 }
2352 #endif /* _KERNEL */