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