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