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