Change the kernel dev_t, representing a pointer to a specinfo structure,
[dragonfly.git] / sys / contrib / ipfilter / netinet / ip_fil.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (C) 1993-2001 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
1de703da
MD
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 $
91865926 8 * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_fil.c,v 1.25.2.7 2004/07/04 09:24:38 darrenr Exp $
b13267a5 9 * $DragonFly: src/sys/contrib/ipfilter/netinet/ip_fil.c,v 1.23 2006/09/10 01:26:33 dillon Exp $
984263bc
MD
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
715fc6d8
JS
18#if defined(_KERNEL) && (defined(__DragonFly__) || (defined(__FreeBSD_version) && \
19 (__FreeBSD_version >= 400000))) && !defined(KLD_MODULE)
984263bc
MD
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>
715fc6d8 46#if (defined(__DragonFly__) || __FreeBSD_version >= 220000) && defined(_KERNEL)
984263bc
MD
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
715fc6d8 57# if defined(__DragonFly__) || (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
984263bc
MD
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>
a743ef5f 68#if defined(__DragonFly__) && defined(_KERNEL)
1a5f156c
SS
69# include <sys/thread2.h>
70#endif
984263bc
MD
71
72#include <net/if.h>
73#ifdef sun
74# include <net/af.h>
75#endif
715fc6d8 76#if defined(__DragonFly__) || __FreeBSD_version >= 300000
984263bc
MD
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
1f2de5d4 104#include "ip_compat.h"
984263bc
MD
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
1f2de5d4
MD
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"
715fc6d8 118#if defined(__DragonFly__) || (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000))
984263bc
MD
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>
6e09358b 126extern int ip_optcopy (struct ip *, struct ip *);
984263bc
MD
127#endif
128#if defined(OpenBSD) && (OpenBSD >= 200211) && defined(_KERNEL)
129extern int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
130 struct ifnet *, struct in6_addr *, u_long *);
131#endif
132
3f9db7f8 133#include <sys/in_cksum.h>
984263bc 134
1de703da 135static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
984263bc
MD
136
137extern struct protosw inetsw[];
138
139#ifndef _KERNEL
140# include "ipt.h"
141static struct ifnet **ifneta = NULL;
142static int nifs = 0;
143#else
144# if (BSD < 199306) || defined(__sgi)
145extern int tcp_ttl;
146# endif
147#endif
148
149#ifdef ICMP_UNREACH_FILTER_PROHIB
150int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB;
151#else
152int ipl_unreach = ICMP_UNREACH_FILTER;
153#endif
154u_long ipl_frouteok[2] = {0, 0};
155
6e09358b 156static int frzerostats (caddr_t);
715fc6d8 157#if defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
6e09358b 158static int frrequest (int, u_long, caddr_t, int);
984263bc 159#else
6e09358b 160static int frrequest (int, int, caddr_t, int);
984263bc
MD
161#endif
162#ifdef _KERNEL
6e09358b
RG
163static int (*fr_savep) (ip_t *, int, void *, int, struct mbuf **);
164static int send_ip (ip_t *, fr_info_t *, struct mbuf **);
984263bc 165# ifdef USE_INET6
6e09358b
RG
166static int ipfr_fastroute6 (struct mbuf *, struct mbuf **,
167 fr_info_t *, frdest_t *);
984263bc
MD
168# endif
169# ifdef __sgi
170extern int tcp_mtudisc;
171extern kmutex_t ipf_rw;
172extern KRWLOCK_T ipf_mutex;
173# endif
174#else
6e09358b 175void init_ifp (void);
984263bc 176# if defined(__sgi) && (IRIX < 605)
6e09358b
RG
177static int no_output (struct ifnet *, struct mbuf *,
178 struct sockaddr *);
179static int write_output (struct ifnet *, struct mbuf *,
180 struct sockaddr *);
984263bc 181# else
6e09358b
RG
182static int no_output (struct ifnet *, struct mbuf *,
183 struct sockaddr *, struct rtentry *);
184static int write_output (struct ifnet *, struct mbuf *,
185 struct sockaddr *, struct rtentry *);
984263bc
MD
186# endif
187#endif
188int fr_running = 0;
189
715fc6d8 190#if (defined(__DragonFly__) || __FreeBSD_version >= 300000) && defined(_KERNEL)
d41d6452 191struct callout ipfr_slowtimer_ch;
984263bc
MD
192#endif
193#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
194# include <sys/callout.h>
195struct callout ipfr_slowtimer_ch;
196#endif
197#if defined(__OpenBSD__)
198# include <sys/timeout.h>
199struct timeout ipfr_slowtimer_ch;
200#endif
201#if defined(__sgi) && defined(_KERNEL)
202toid_t ipfr_slowtimer_ch;
203#endif
204
205#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) && \
206 defined(_KERNEL)
207# include <sys/conf.h>
208const 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
218struct cfdriver iplcd = {
219 NULL, "ipl", NULL, NULL, DV_DULL, 0
220};
221
222struct 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
e7e55f42
JR
230#if defined(__NetBSD__) || defined(__OpenBSD__) || \
231 (_BSDI_VERSION >= 199701) || (defined(__DragonFly_version) && \
232 (__DragonFly_version >= 100000))
984263bc
MD
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 */
6e09358b 239int (*fr_checkp) (ip_t *ip, int hlen, void *ifp, int out, mb_t **mp);
984263bc
MD
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
248static int fr_check_wrapper(void *, struct mbuf **, struct ifnet *, int );
249
250static int fr_check_wrapper(arg, mp, ifp, dir)
251void *arg;
252struct mbuf **mp;
253struct ifnet *ifp;
254int 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 */
3c81cebc
JS
283 ip->ip_len = ntohs(ip->ip_len);
284 ip->ip_off = ntohs(ip->ip_off);
984263bc
MD
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 *);
3c81cebc
JS
290 ip->ip_len = htons(ip->ip_len);
291 ip->ip_off = htnos(ip->ip_off);
984263bc
MD
292 }
293
294 return (rv);
295}
296
297# ifdef USE_INET6
298# include <netinet/ip6.h>
299
300static int fr_check_wrapper6(void *, struct mbuf **, struct ifnet *, int );
301
302static int fr_check_wrapper6(arg, mp, ifp, dir)
303void *arg;
304struct mbuf **mp;
305struct ifnet *ifp;
306int 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 */
e7e55f42
JR
314#if defined(__DragonFly_version) && (__DragonFly_version >= 100000) && \
315 defined(_KERNEL)
316
317static int
318fr_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
327static int
328fr_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 */
984263bc
MD
335#ifdef _KERNEL
336# if defined(IPFILTER_LKM) && !defined(__sgi)
337int iplidentify(s)
338char *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)
351void
352ipfilterattach(count)
353int 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__)
365int ipl_enable()
366# else
367int iplattach()
368# endif
369{
370 char *defpass;
1a5f156c 371# if !defined(__DragonFly__)
984263bc 372 int s;
1a5f156c 373# endif
e7e55f42
JR
374# if defined(__sgi) || (defined(NETBSD_PF) && \
375 (__NetBSD_Version__ >= 104200000)) || \
376 (defined(__DragonFly_version) && (__DragonFly_version >= 100000))
984263bc
MD
377 int error = 0;
378# endif
e7e55f42
JR
379#if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)) || \
380 (defined(__DragonFly_version) && (__DragonFly_version >= 100000))
984263bc
MD
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
e7e55f42
JR
411# if (__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) || \
412 (defined(__DragonFly_version) && (__DragonFly_version >= 100000))
413# if (__NetBSD_Version__ >= 105110000) || (__DragonFly_version >= 100000)
984263bc
MD
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
e7e55f42 449# if (__NetBSD_Version__ >= 105110000) || (__DragonFly_version >= 100000)
984263bc
MD
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
465pfil_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
715fc6d8 515# if (defined(__DragonFly__) || __FreeBSD_version >= 300000) || defined(__sgi)
d41d6452
JS
516 callout_init(&ipfr_slowtimer_ch);
517 callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL);
984263bc
MD
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__)
533int ipl_disable()
534# else
535int ipldetach()
536# endif
537{
1a5f156c
SS
538# if !defined(__DragonFly__)
539 int s;
540# endif
541 int i;
984263bc 542#if defined(NETBSD_PF) && \
e7e55f42
JR
543 ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) || \
544 (defined(__DragonFly_version) && (__DragonFly_version >= 100000)))
984263bc 545 int error = 0;
e7e55f42 546# if (__NetBSD_Version__ >= 105150000) || (__DragonFly_version >= 100000)
984263bc
MD
547 struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
548# ifdef USE_INET6
91865926 549 struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
984263bc
MD
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
715fc6d8 558# if (defined(__DragonFly__) || __FreeBSD_version >= 300000)
d41d6452 559 callout_stop(&ipfr_slowtimer_ch);
984263bc
MD
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
e7e55f42
JR
589# if ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) || \
590 (__DragonFly_version >= 100000))
591# if (__NetBSD_Version__ >= 105110000) || (__DragonFly_version >= 100000)
984263bc
MD
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
e7e55f42 609# if (__NetBSD_Version__ >= 105110000) || (__DragonFly_version >= 100000)
984263bc
MD
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
642static int frzerostats(data)
643caddr_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
663int 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
fef8985e 669#if defined(__DragonFly__)
0b5d9d9f 670# if defined(_KERNEL)
fef8985e 671int IPL_EXTERN(ioctl)(struct dev_ioctl_args *ap)
0b5d9d9f 672# else
b13267a5 673int IPL_EXTERN(ioctl)(struct cdev *dev, u_long cmd, caddr_t data, int mode)
0b5d9d9f 674#endif
fef8985e 675#else
984263bc 676int IPL_EXTERN(ioctl)(dev, cmd, data, mode
fef8985e 677#if (defined(_KERNEL) && defined(__FreeBSD__))
41c20dac
MD
678, td)
679struct thread *td;
680# elif (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \
fef8985e 681 (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \
984263bc
MD
682 defined(__OpenBSD__)))
683, p)
684struct proc *p;
685# else
686)
687# endif
688dev_t dev;
689# if defined(__NetBSD__) || defined(__OpenBSD__) || \
fef8985e 690 (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000)
984263bc
MD
691u_long cmd;
692# else
693int cmd;
694# endif
695caddr_t data;
696int mode;
fef8985e 697#endif /* DragonFly */
984263bc
MD
698#endif /* __sgi */
699{
0b5d9d9f 700#if (defined(_KERNEL) && defined(__DragonFly__))
b13267a5 701 struct cdev *dev = ap->a_head.a_dev;
fef8985e
MD
702 u_long cmd = ap->a_cmd;
703 caddr_t data = ap->a_data;
704 int mode = ap->a_fflag;
705#endif
1a5f156c 706#if defined(_KERNEL) && !SOLARIS && !defined(__DragonFly__)
984263bc
MD
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
917void fr_forgetifp(ifp)
918void *ifp;
919{
f20164ba 920 frentry_t *f;
984263bc
MD
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
954static int frrequest(unit, req, data, set)
955int unit;
715fc6d8 956#if defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
984263bc
MD
957u_long req;
958#else
959int req;
960#endif
961int set;
962caddr_t data;
963{
f20164ba
RG
964 frentry_t *fp, *f, **fprev;
965 frentry_t **ftail;
984263bc
MD
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 {
91865926 1081 ftail = fprev;
984263bc 1082 if (fp->fr_hits) {
984263bc
MD
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 */
fef8985e
MD
1149#ifdef __DragonFly__
1150int IPL_EXTERN(open)(struct dev_open_args *ap)
1151#else
984263bc 1152# ifdef __sgi
984263bc 1153int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp)
984263bc
MD
1154# else
1155int IPL_EXTERN(open)(dev, flags
fef8985e 1156#if defined(__FreeBSD__)
41c20dac
MD
1157, devtype, td)
1158int devtype;
1159struct thread *td;
1160#elif ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
fef8985e 1161 (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
984263bc
MD
1162, devtype, p)
1163int devtype;
1164struct proc *p;
1165# else
1166)
1167# endif
1168dev_t dev;
1169int flags;
1170# endif /* __sgi */
fef8985e 1171#endif /* DragonFly */
984263bc 1172{
fef8985e 1173#ifdef __DragonFly__
b13267a5 1174 struct cdev *dev = ap->a_head.a_dev;
fef8985e 1175#endif
984263bc
MD
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
fef8985e
MD
1190#ifdef __DragonFly__
1191int IPL_EXTERN(close)(struct dev_close_args *ap)
1192#else
984263bc
MD
1193# ifdef __sgi
1194int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp)
1195#else
1196int IPL_EXTERN(close)(dev, flags
fef8985e 1197#if defined(__FreeBSD__)
41c20dac
MD
1198, devtype, td)
1199int devtype;
1200struct thread *td;
1201#elif ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \
fef8985e 1202 (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL)
984263bc
MD
1203, devtype, p)
1204int devtype;
1205struct proc *p;
1206# else
1207)
1208# endif
1209dev_t dev;
1210int flags;
1211# endif /* __sgi */
fef8985e 1212#endif /* DragonFly */
984263bc 1213{
fef8985e 1214#ifdef __DragonFly__
b13267a5 1215 struct cdev *dev = ap->a_head.a_dev;
fef8985e 1216#endif
984263bc
MD
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 */
fef8985e
MD
1232#ifdef __DragonFly__
1233int IPL_EXTERN(read)(struct dev_read_args *ap)
1234#else
984263bc
MD
1235# ifdef __sgi
1236int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp)
1237# else
1238# if BSD >= 199306
1239int IPL_EXTERN(read)(dev, uio, ioflag)
1240int ioflag;
1241# else
1242int IPL_EXTERN(read)(dev, uio)
1243# endif
1244dev_t dev;
f20164ba 1245struct uio *uio;
984263bc 1246# endif /* __sgi */
fef8985e 1247#endif /* DragonFly */
984263bc 1248{
fef8985e 1249#ifdef __DragonFly__
b13267a5 1250 struct cdev *dev = ap->a_head.a_dev;
fef8985e
MD
1251 struct uio *uio = ap->a_uio;
1252#endif
984263bc
MD
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 */
1265int send_reset(oip, fin)
1266struct ip *oip;
1267fr_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);
74f1caca 1282# elif defined(__DragonFly__)
d52d36a3 1283 m = m_gethdr(MB_DONTWAIT, MT_HEADER);
984263bc
MD
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 */
1350static int send_ip(oip, fin, mp)
1351ip_t *oip;
1352fr_info_t *fin;
1353struct 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;
91865926 1364 frn.fin_mp = mp;
984263bc
MD
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
91865926
HP
1408 if (fr_makefrip(hlen, ip, &frn) == 0)
1409 error = ipfr_fastroute(m, mp, &frn, NULL);
1410 else
1411 error = EINVAL;
984263bc
MD
1412 return error;
1413}
1414
1415
1416int send_icmp_err(oip, type, fin, dst)
1417ip_t *oip;
1418int type;
1419fr_info_t *fin;
1420int 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);
74f1caca
EN
1463# elif defined(__DragonFly__)
1464 avail = MHLEN;
1465 m = m_gethdr(MB_DONTWAIT, MT_HEADER);
984263bc
MD
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
74f1caca
EN
1492#ifdef __DragonFly__
1493 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
1494#else
984263bc 1495 MGETHDR(m, M_DONTWAIT, MT_HEADER);
74f1caca 1496#endif
984263bc
MD
1497 if (!m)
1498 return ENOBUFS;
1499
74f1caca
EN
1500#ifdef __DragonFly__
1501 MCLGET(m, MB_DONTWAIT);
1502#else
984263bc 1503 MCLGET(m, M_DONTWAIT);
74f1caca 1504#endif
984263bc
MD
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) {
91865926
HP
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);
984263bc 1559 bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
91865926
HP
1560 oip->ip_len = slen;
1561 oip->ip_off = soff;
984263bc
MD
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 {
984263bc
MD
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;
91865926 1601
984263bc
MD
1602 return err;
1603}
1604
1605
1606# if !defined(IPFILTER_LKM) && !defined(__sgi) && \
715fc6d8 1607 (!defined(__DragonFly__) || !defined(__FreeBSD_version) || (__FreeBSD_version < 300000))
984263bc 1608# if (BSD < 199306)
6e09358b 1609int iplinit (void);
984263bc
MD
1610
1611int
1612# else
6e09358b 1613void iplinit (void);
984263bc
MD
1614
1615void
1616# endif
1617iplinit()
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 */
1636size_t mbufchainlen(m0)
f20164ba 1637struct mbuf *m0;
984263bc
MD
1638{
1639#if BSD >= 199306
1640 return m0->m_pkthdr.len;
1641#else
f20164ba 1642 size_t len = 0;
984263bc
MD
1643
1644 for (; m0; m0 = m0->m_next)
1645 len += m0->m_len;
1646 return len;
1647#endif
1648}
1649
1650
1651int ipfr_fastroute(m0, mpp, fin, fdp)
1652struct mbuf *m0, **mpp;
1653fr_info_t *fin;
1654frdest_t *fdp;
1655{
f20164ba
RG
1656 struct ip *ip, *mhip;
1657 struct mbuf *m = m0;
1658 struct route *ro;
91865926 1659 int len, off, error = 0, hlen, code, sout;
984263bc
MD
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) {
74f1caca
EN
1696#ifdef __DragonFly__
1697 if ((m0 = m_dup(m, MB_DONTWAIT)) != NULL) {
1698#else
984263bc 1699 if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) {
74f1caca 1700#endif
984263bc
MD
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 */
91865926 1729#if (defined(IRIX) && (IRIX >= 605))
984263bc
MD
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)) {
91865926
HP
1748 if ((ifp != NULL) && (fdp == &fr->fr_tif)) {
1749# if (defined(IRIX) && (IRIX >= 605))
1750 ROUTE_UNLOCK();
1751# endif
984263bc 1752 return 0;
91865926 1753 }
984263bc
MD
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
984263bc
MD
1773 if (!ifp) {
1774 if (!fr || !(fr->fr_flags & FR_FASTROUTE)) {
1775 error = -2;
91865926
HP
1776# if (defined(IRIX) && (IRIX >= 605))
1777 ROUTE_UNLOCK();
1778# endif
984263bc
MD
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;
91865926
HP
1791# if (defined(IRIX) && (IRIX >= 605))
1792 ROUTE_UNLOCK();
1793# endif
984263bc
MD
1794 goto bad;
1795 }
1796
1797 if (ro->ro_rt->rt_flags & RTF_GATEWAY) {
91865926 1798#if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605))
984263bc
MD
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
91865926
HP
1806#if (defined(IRIX) && (IRIX > 602))
1807 ROUTE_UNLOCK();
1808#endif
1809
984263bc
MD
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;
91865926 1817 sout = fin->fin_out;
984263bc
MD
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);
91865926
HP
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
984263bc 1841 fin->fin_ifp = sifp;
91865926 1842 fin->fin_out = sout;
984263bc
MD
1843 } else
1844 ip->ip_sum = 0;
91865926 1845
984263bc
MD
1846 /*
1847 * If small enough for interface, can just send directly.
1848 */
1849 if (ip->ip_len <= ifp->if_mtu) {
1850# ifndef sparc
715fc6d8 1851# if (!defined(__DragonFly__) && !defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510)) && \
984263bc
MD
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))
91865926
HP
1875# ifdef IRIX
1876 IFNET_UPPERLOCK(ifp);
1877# endif
78195a76 1878 lwkt_serialize_enter(ifp->if_serializer);
984263bc
MD
1879 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1880 ro->ro_rt);
78195a76 1881 lwkt_serialize_exit(ifp->if_serializer);
91865926
HP
1882# ifdef IRIX
1883 IFNET_UPPERUNLOCK(ifp);
1884# endif
984263bc 1885# else
78195a76 1886 lwkt_serialize_enter(ifp->if_serializer);
984263bc 1887 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
78195a76 1888 lwkt_serialize_exit(ifp->if_serializer);
984263bc
MD
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) {
74f1caca
EN
1918# ifdef __DragonFly__
1919 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
1920# elif defined(MGETHDR)
984263bc
MD
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);
1973sendorfree:
1974 for (m = m0; m; m = m0) {
1975 m0 = m->m_act;
1976 m->m_act = 0;
78195a76
MD
1977 if (error == 0) {
1978 lwkt_serialize_enter(ifp->if_serializer);
984263bc
MD
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
78195a76
MD
1986 lwkt_serialize_exit(ifp->if_serializer);
1987 } else {
984263bc 1988 m_freem(m);
78195a76 1989 }
984263bc
MD
1990 }
1991 }
1992done:
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;
2003bad:
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 */
2022int fr_verifysrc(ipa, ifp)
2023struct in_addr ipa;
2024void *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__) && \
91865926 2037 !defined(__OpenBSD__)
984263bc
MD
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
2053char *
2054get_ifname(ifp)
2055struct 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 */
2071static int ipfr_fastroute6(m0, mpp, fin, fdp)
2072struct mbuf *m0, **mpp;
2073fr_info_t *fin;
2074frdest_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
984263bc
MD
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);
91865926 2095 dst6->sin6_addr = fin->fin_fi.fi_dst.in6;
984263bc
MD
2096
2097 if (fdp != NULL)
2098 ifp = fdp->fd_ifp;
91865926
HP
2099 else
2100 ifp = fin->fin_ifp;
984263bc
MD
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 }
91865926 2109 if (ifp == NULL)
984263bc
MD
2110 return -2;
2111
91865926
HP
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
984263bc
MD
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) {
521741a2
HS
2136#else
2137#ifdef ND_IFINFO
2138 mtu = ND_IFINFO(ifp)->linkmtu;
984263bc
MD
2139#else
2140 mtu = nd_ifinfo[ifp->if_index].linkmtu;
521741a2 2141#endif
984263bc
MD
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)
6e09358b
RG
2163static int no_output (struct ifnet *ifp, struct mbuf *m,
2164 struct sockaddr *s)
984263bc 2165# else
6e09358b
RG
2166static int no_output (struct ifnet *ifp, struct mbuf *m,
2167 struct sockaddr *s, struct rtentry *rt)
984263bc
MD
2168# endif
2169{
2170 return 0;
2171}
2172
2173
2174# ifdef __STDC__
2175# if defined(__sgi) && (IRIX < 605)
6e09358b
RG
2176static int write_output (struct ifnet *ifp, struct mbuf *m,
2177 struct sockaddr *s)
984263bc 2178# else
6e09358b
RG
2179static int write_output (struct ifnet *ifp, struct mbuf *m,
2180 struct sockaddr *s, struct rtentry *rt)
984263bc
MD
2181# endif
2182{
2183 ip_t *ip = (ip_t *)m;
2184# else
2185static int write_output(ifp, ip)
2186struct ifnet *ifp;
2187ip_t *ip;
2188{
2189# endif
2190 char fname[32];
2191 int fd;
2192
2193# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
3e4a09e7
MD
2194 (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2195 (defined(__DragonFly__))
984263bc
MD
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
2211char *get_ifname(ifp)
2212struct ifnet *ifp;
2213{
2214# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
3e4a09e7
MD
2215 (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2216 (defined(__DragonFly__))
984263bc
MD
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
2227struct ifnet *get_unit(ifname, v)
2228char *ifname;
2229int 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)) || \
3e4a09e7
MD
2235 (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2236 (defined(__DragonFly__))
984263bc
MD
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)) || \
3e4a09e7
MD
2278 (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2279 (defined(__DragonFly__))
984263bc
MD
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
2299void init_ifp()
2300{
2301 struct ifnet *ifp, **ifa;
2302 char fname[32];
2303 int fd;
2304
2305# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
3e4a09e7
MD
2306 (defined(OpenBSD) && (OpenBSD >= 199603)) || \
2307 (defined(__DragonFly__))
984263bc
MD
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
2332int send_reset(ip, fin)
2333ip_t *ip;
2334fr_info_t *fin;
2335{
2336 verbose("- TCP RST sent\n");
2337 return 0;
2338}
2339
2340
2341int send_icmp_err(ip, code, fin, dst)
2342ip_t *ip;
2343int code;
2344fr_info_t *fin;
2345int dst;
2346{
2347 verbose("- ICMP UNREACHABLE sent\n");
2348 return 0;
2349}
2350
2351
2352void frsync()
2353{
2354 return;
2355}
2356
2357void m_copydata(m, off, len, cp)
2358mb_t *m;
2359int off, len;
2360caddr_t cp;
2361{
2362 bcopy((char *)m + off, cp, len);
2363}
2364
2365
2366int ipfuiomove(buf, len, rwflag, uio)
2367caddr_t buf;
2368int len, rwflag;
2369struct 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 */