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