Home | History | Annotate | Line # | Download | only in netinet
ip_fil_netbsd.c revision 1.22.4.5
      1  1.22.4.5  pgoyette /*	$NetBSD: ip_fil_netbsd.c,v 1.22.4.5 2017/05/02 05:17:56 pgoyette Exp $	*/
      2       1.1  christos 
      3       1.1  christos /*
      4       1.1  christos  * Copyright (C) 2012 by Darren Reed.
      5       1.1  christos  *
      6       1.1  christos  * See the IPFILTER.LICENCE file for details on licencing.
      7       1.1  christos  */
      8       1.1  christos #if !defined(lint)
      9       1.2  christos #if defined(__NetBSD__)
     10       1.2  christos #include <sys/cdefs.h>
     11  1.22.4.5  pgoyette __KERNEL_RCSID(0, "$NetBSD: ip_fil_netbsd.c,v 1.22.4.5 2017/05/02 05:17:56 pgoyette Exp $");
     12       1.2  christos #else
     13       1.1  christos static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
     14       1.3   darrenr static const char rcsid[] = "@(#)Id: ip_fil_netbsd.c,v 1.1.1.2 2012/07/22 13:45:17 darrenr Exp";
     15       1.2  christos #endif
     16       1.1  christos #endif
     17       1.1  christos 
     18       1.1  christos #if defined(KERNEL) || defined(_KERNEL)
     19       1.1  christos # undef KERNEL
     20       1.1  christos # undef _KERNEL
     21       1.1  christos # define        KERNEL	1
     22       1.1  christos # define        _KERNEL	1
     23       1.1  christos #endif
     24       1.1  christos #include <sys/param.h>
     25       1.1  christos #if (NetBSD >= 199905) && !defined(IPFILTER_LKM)
     26      1.13  pgoyette # if (__NetBSD_Version__ >= 799003000)
     27      1.13  pgoyette #   ifdef _KERNEL_OPT
     28      1.13  pgoyette #    include "opt_ipsec.h"
     29      1.13  pgoyette #   endif
     30      1.13  pgoyette # else
     31      1.13  pgoyette #  include "opt_ipsec.h"
     32      1.13  pgoyette # endif
     33       1.1  christos #endif
     34       1.1  christos #include <sys/errno.h>
     35       1.1  christos #include <sys/types.h>
     36       1.1  christos #include <sys/file.h>
     37       1.1  christos #include <sys/ioctl.h>
     38       1.1  christos #include <sys/time.h>
     39       1.1  christos #include <sys/systm.h>
     40       1.1  christos #include <sys/select.h>
     41       1.1  christos #if (NetBSD > 199609)
     42       1.1  christos # include <sys/dirent.h>
     43       1.1  christos #else
     44       1.1  christos # include <sys/dir.h>
     45       1.1  christos #endif
     46       1.1  christos #if (__NetBSD_Version__ >= 599005900)
     47       1.1  christos # include <sys/cprng.h>
     48       1.1  christos #endif
     49       1.1  christos #include <sys/mbuf.h>
     50       1.1  christos #include <sys/protosw.h>
     51       1.1  christos #include <sys/socket.h>
     52       1.1  christos #include <sys/poll.h>
     53       1.1  christos #if (__NetBSD_Version__ >= 399002000)
     54       1.1  christos # include <sys/kauth.h>
     55       1.1  christos #endif
     56      1.13  pgoyette #if (__NetBSD_Version__ >= 799003000)
     57      1.13  pgoyette #include <sys/module.h>
     58      1.13  pgoyette #include <sys/mutex.h>
     59      1.13  pgoyette #endif
     60       1.1  christos 
     61       1.1  christos #include <net/if.h>
     62       1.1  christos #include <net/route.h>
     63       1.1  christos #include <netinet/in.h>
     64       1.1  christos #include <netinet/in_var.h>
     65       1.1  christos #include <netinet/in_systm.h>
     66       1.1  christos #include <netinet/ip.h>
     67       1.1  christos #include <netinet/ip_var.h>
     68       1.1  christos #include <netinet/tcp.h>
     69       1.1  christos #if __NetBSD_Version__ >= 105190000	/* 1.5T */
     70       1.1  christos # include <netinet/tcp_timer.h>
     71       1.1  christos # include <netinet/tcp_var.h>
     72       1.1  christos #endif
     73       1.1  christos #include <netinet/udp.h>
     74       1.1  christos #include <netinet/tcpip.h>
     75       1.1  christos #include <netinet/ip_icmp.h>
     76       1.1  christos #include "netinet/ip_compat.h"
     77       1.1  christos #ifdef USE_INET6
     78       1.1  christos # include <netinet/icmp6.h>
     79       1.1  christos # if (__NetBSD_Version__ >= 106000000)
     80       1.1  christos #  include <netinet6/nd6.h>
     81       1.1  christos # endif
     82       1.1  christos #endif
     83       1.1  christos #include "netinet/ip_fil.h"
     84       1.1  christos #include "netinet/ip_nat.h"
     85       1.1  christos #include "netinet/ip_frag.h"
     86       1.1  christos #include "netinet/ip_state.h"
     87       1.1  christos #include "netinet/ip_proxy.h"
     88       1.1  christos #include "netinet/ip_auth.h"
     89       1.1  christos #include "netinet/ip_sync.h"
     90       1.1  christos #include "netinet/ip_lookup.h"
     91       1.1  christos #include "netinet/ip_dstlist.h"
     92       1.1  christos #ifdef	IPFILTER_SCAN
     93       1.1  christos #include "netinet/ip_scan.h"
     94       1.1  christos #endif
     95       1.1  christos #include <sys/md5.h>
     96       1.1  christos #include <sys/kernel.h>
     97       1.1  christos #include <sys/conf.h>
     98       1.1  christos #ifdef INET
     99       1.2  christos extern	int	ip_optcopy (struct ip *, struct ip *);
    100       1.1  christos #endif
    101       1.1  christos 
    102       1.1  christos #ifdef IPFILTER_M_IPFILTER
    103       1.1  christos MALLOC_DEFINE(M_IPFILTER, "IP Filter", "IP Filter packet filter data structures");
    104       1.1  christos #endif
    105       1.1  christos 
    106       1.1  christos #if __NetBSD_Version__ >= 105009999
    107       1.1  christos # define	csuminfo	csum_flags
    108       1.1  christos #endif
    109       1.1  christos 
    110       1.1  christos #if __NetBSD_Version__ < 200000000
    111       1.1  christos extern	struct	protosw	inetsw[];
    112       1.1  christos #endif
    113       1.2  christos 
    114       1.2  christos #if (__NetBSD_Version__ >= 599002000)
    115       1.2  christos static kauth_listener_t ipf_listener;
    116       1.2  christos #endif
    117       1.2  christos 
    118       1.2  christos #if (__NetBSD_Version__ < 399001400)
    119       1.2  christos extern int ip6_getpmtu (struct route_in6 *, struct route_in6 *,
    120       1.2  christos 			    struct ifnet *, struct in6_addr *, u_long *,
    121       1.2  christos 			    int *);
    122       1.2  christos #endif
    123       1.1  christos #if (NetBSD >= 199511)
    124       1.1  christos static  int     ipfopen(dev_t dev, int flags, int devtype, PROC_T *p);
    125       1.1  christos static  int     ipfclose(dev_t dev, int flags, int devtype, PROC_T *p);
    126       1.1  christos #else
    127       1.1  christos # if (__NetBSD_Version__ >= 399001400)
    128       1.1  christos static  int     ipfopen(dev_t dev, int flags, struct lwp *);
    129       1.1  christos static  int     ipfclose(dev_t dev, int flags, struct lwp *);
    130       1.1  christos # else
    131       1.1  christos static  int     ipfopen(dev_t dev, int flags);
    132       1.1  christos static  int     ipfclose(dev_t dev, int flags);
    133       1.1  christos # endif /* __NetBSD_Version__ >= 399001400 */
    134       1.1  christos #endif
    135       1.1  christos static  int     ipfread(dev_t, struct uio *, int ioflag);
    136       1.1  christos static  int     ipfwrite(dev_t, struct uio *, int ioflag);
    137       1.1  christos static  int     ipfpoll(dev_t, int events, PROC_T *);
    138       1.2  christos static	void	ipf_timer_func(void *ptr);
    139       1.1  christos 
    140       1.1  christos const struct cdevsw ipl_cdevsw = {
    141  1.22.4.5  pgoyette #if	(__NetBSD_Version__ >= 799007200)
    142  1.22.4.1  pgoyette 	DEVSW_MODULE_INIT
    143  1.22.4.1  pgoyette #endif
    144       1.8  dholland 	.d_open = ipfopen,
    145       1.8  dholland 	.d_close = ipfclose,
    146       1.8  dholland 	.d_read = ipfread,
    147       1.8  dholland 	.d_write = ipfwrite,
    148       1.8  dholland 	.d_ioctl = ipfioctl,
    149       1.8  dholland 	.d_stop = nostop,
    150       1.8  dholland 	.d_tty = notty,
    151       1.8  dholland 	.d_poll = ipfpoll,
    152       1.8  dholland 	.d_mmap = nommap,
    153       1.1  christos #if  (__NetBSD_Version__ >= 200000000)
    154       1.8  dholland 	.d_kqfilter = nokqfilter,
    155       1.1  christos #endif
    156      1.11  dholland 	.d_discard = nodiscard,
    157       1.1  christos #ifdef D_OTHER
    158       1.8  dholland 	.d_flag = D_OTHER
    159       1.8  dholland #else
    160       1.8  dholland 	.d_flag = 0
    161       1.1  christos #endif
    162       1.1  christos };
    163      1.13  pgoyette #if (__NetBSD_Version__ >= 799003000)
    164      1.13  pgoyette kmutex_t ipf_ref_mutex;
    165      1.13  pgoyette int	ipf_active;
    166      1.13  pgoyette #endif
    167       1.1  christos 
    168       1.1  christos ipf_main_softc_t ipfmain;
    169       1.1  christos 
    170       1.1  christos static	u_short	ipid = 0;
    171       1.2  christos static	int	(*ipf_savep)(void *, ip_t *, int, void *, int, struct mbuf **);
    172       1.2  christos static	int	ipf_send_ip(fr_info_t *, mb_t *);
    173       1.1  christos #ifdef USE_INET6
    174       1.2  christos static int ipf_fastroute6(struct mbuf *, struct mbuf **,
    175       1.2  christos 			      fr_info_t *, frdest_t *);
    176       1.1  christos #endif
    177       1.1  christos 
    178       1.1  christos #if defined(NETBSD_PF)
    179       1.1  christos # include <net/pfil.h>
    180       1.1  christos /*
    181       1.1  christos  * We provide the ipf_checkp name just to minimize changes later.
    182       1.1  christos  */
    183       1.2  christos int (*ipf_checkp)(void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp);
    184       1.1  christos #endif /* NETBSD_PF */
    185       1.1  christos 
    186       1.1  christos #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)
    187       1.1  christos # include <net/pfil.h>
    188       1.1  christos 
    189       1.1  christos static int ipf_check_wrapper(void *, struct mbuf **, struct ifnet *, int );
    190       1.1  christos 
    191       1.1  christos static int
    192       1.2  christos ipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
    193       1.1  christos {
    194       1.1  christos 	struct ip *ip;
    195       1.1  christos 	int rv, hlen;
    196       1.1  christos 
    197       1.1  christos #if __NetBSD_Version__ >= 200080000
    198       1.1  christos 	/*
    199       1.1  christos 	 * ensure that mbufs are writable beforehand
    200       1.1  christos 	 * as it's assumed by ipf code.
    201       1.1  christos 	 * XXX inefficient
    202       1.1  christos 	 */
    203       1.1  christos 	int error = m_makewritable(mp, 0, M_COPYALL, M_DONTWAIT);
    204       1.1  christos 
    205       1.1  christos 	if (error) {
    206       1.1  christos 		m_freem(*mp);
    207       1.1  christos 		*mp = NULL;
    208       1.1  christos 		return error;
    209       1.1  christos 	}
    210       1.1  christos #endif
    211       1.1  christos 	ip = mtod(*mp, struct ip *);
    212       1.1  christos 	hlen = ip->ip_hl << 2;
    213       1.1  christos 
    214       1.1  christos #ifdef INET
    215       1.1  christos #if defined(M_CSUM_TCPv4)
    216       1.1  christos 	/*
    217       1.1  christos 	 * If the packet is out-bound, we can't delay checksums
    218       1.1  christos 	 * here.  For in-bound, the checksum has already been
    219       1.1  christos 	 * validated.
    220       1.1  christos 	 */
    221       1.1  christos 	if (dir == PFIL_OUT) {
    222       1.1  christos 		if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
    223       1.1  christos 			in_delayed_cksum(*mp);
    224       1.1  christos 			(*mp)->m_pkthdr.csum_flags &=
    225       1.1  christos 			    ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
    226       1.1  christos 		}
    227       1.1  christos 	}
    228       1.1  christos #endif /* M_CSUM_TCPv4 */
    229       1.1  christos #endif /* INET */
    230       1.1  christos 
    231       1.1  christos 	/*
    232       1.1  christos 	 * Note, we don't need to update the checksum, because
    233       1.1  christos 	 * it has already been verified.
    234       1.1  christos 	 */
    235       1.1  christos 	rv = ipf_check(&ipfmain, ip, hlen, ifp, (dir == PFIL_OUT), mp);
    236       1.1  christos 
    237       1.1  christos 	return (rv);
    238       1.1  christos }
    239       1.1  christos 
    240       1.1  christos # ifdef USE_INET6
    241       1.1  christos #  include <netinet/ip6.h>
    242       1.1  christos 
    243       1.1  christos static int ipf_check_wrapper6(void *, struct mbuf **, struct ifnet *, int );
    244       1.1  christos 
    245       1.1  christos static int
    246       1.2  christos ipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
    247       1.1  christos {
    248       1.2  christos #if defined(INET6)
    249       1.1  christos #  if defined(M_CSUM_TCPv6) && (__NetBSD_Version__ > 200000000)
    250       1.1  christos 	/*
    251       1.1  christos 	 * If the packet is out-bound, we can't delay checksums
    252       1.1  christos 	 * here.  For in-bound, the checksum has already been
    253       1.1  christos 	 * validated.
    254       1.1  christos 	 */
    255       1.1  christos 	if (dir == PFIL_OUT) {
    256       1.1  christos 		if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) {
    257       1.1  christos #   if (__NetBSD_Version__ > 399000600)
    258       1.1  christos 			in6_delayed_cksum(*mp);
    259       1.1  christos #   endif
    260       1.1  christos 			(*mp)->m_pkthdr.csum_flags &= ~(M_CSUM_TCPv6|
    261       1.1  christos 							M_CSUM_UDPv6);
    262       1.1  christos 		}
    263       1.1  christos 	}
    264       1.1  christos #  endif
    265       1.2  christos #endif /* INET6 */
    266       1.1  christos 
    267       1.1  christos 	return (ipf_check(&ipfmain, mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
    268       1.1  christos 	    ifp, (dir == PFIL_OUT), mp));
    269       1.1  christos }
    270       1.1  christos # endif
    271       1.1  christos 
    272       1.1  christos 
    273       1.1  christos # if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    274       1.1  christos 
    275      1.20  christos #  if (__NetBSD_Version__ >= 799000400)
    276      1.20  christos 
    277      1.20  christos static void ipf_pfilsync(void *, unsigned long, void *);
    278      1.20  christos 
    279      1.20  christos static void
    280      1.20  christos ipf_pfilsync(void *hdr, unsigned long cmd, void *arg2)
    281       1.1  christos {
    282       1.1  christos 	/*
    283       1.1  christos 	 * The interface pointer is useless for create (we have nothing to
    284       1.1  christos 	 * compare it to) and at detach, the interface name is still in the
    285       1.1  christos 	 * list of active NICs (albeit, down, but that's not any real
    286       1.1  christos 	 * indicator) and doing ifunit() on the name will still return the
    287       1.1  christos 	 * pointer, so it's not much use then, either.
    288       1.1  christos 	 */
    289       1.1  christos 	ipf_sync(&ipfmain, NULL);
    290      1.20  christos }
    291      1.20  christos 
    292      1.20  christos #  else
    293      1.20  christos 
    294      1.20  christos static int ipf_pfilsync(void *, struct mbuf **, struct ifnet *, int);
    295      1.20  christos 
    296      1.20  christos static int
    297      1.20  christos ipf_pfilsync(void *hdr, struct mbuf **mp, struct ifnet *ifp, int dir)
    298      1.20  christos {
    299      1.20  christos 	ipf_sync(&ipfmain, NULL);
    300       1.1  christos 	return 0;
    301       1.1  christos }
    302      1.20  christos 
    303      1.20  christos #  endif
    304       1.1  christos # endif
    305       1.1  christos 
    306       1.1  christos #endif /* __NetBSD_Version__ >= 105110000 */
    307       1.1  christos 
    308       1.1  christos 
    309       1.1  christos #if defined(IPFILTER_LKM)
    310       1.1  christos int
    311       1.1  christos ipf_identify(s)
    312       1.1  christos 	char *s;
    313       1.1  christos {
    314       1.1  christos 	if (strcmp(s, "ipl") == 0)
    315       1.1  christos 		return 1;
    316       1.1  christos 	return 0;
    317       1.1  christos }
    318       1.1  christos #endif /* IPFILTER_LKM */
    319       1.1  christos 
    320       1.2  christos #if (__NetBSD_Version__ >= 599002000)
    321       1.2  christos static int
    322       1.2  christos ipf_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
    323       1.2  christos     void *arg0, void *arg1, void *arg2, void *arg3)
    324       1.2  christos {
    325       1.2  christos 	int result;
    326       1.2  christos 	enum kauth_network_req req;
    327       1.2  christos 
    328       1.2  christos 	result = KAUTH_RESULT_DEFER;
    329       1.2  christos 	req = (enum kauth_network_req)arg0;
    330       1.2  christos 
    331       1.2  christos 	if (action != KAUTH_NETWORK_FIREWALL)
    332       1.2  christos 		return result;
    333       1.2  christos 
    334       1.2  christos 	/* These must have came from device context. */
    335       1.2  christos 	if ((req == KAUTH_REQ_NETWORK_FIREWALL_FW) ||
    336       1.2  christos 	    (req == KAUTH_REQ_NETWORK_FIREWALL_NAT))
    337       1.2  christos 		result = KAUTH_RESULT_ALLOW;
    338       1.2  christos 
    339       1.2  christos 	return result;
    340       1.2  christos }
    341       1.2  christos #endif
    342       1.1  christos 
    343       1.1  christos /*
    344       1.1  christos  * Try to detect the case when compiling for NetBSD with pseudo-device
    345       1.1  christos  */
    346       1.1  christos void
    347       1.2  christos ipfilterattach(int count)
    348       1.1  christos {
    349       1.2  christos 
    350      1.13  pgoyette #if (__NetBSD_Version__ >= 799003000)
    351      1.13  pgoyette 	return;
    352      1.13  pgoyette #else
    353       1.2  christos #if (__NetBSD_Version__ >= 599002000)
    354       1.2  christos 	ipf_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
    355       1.2  christos 	    ipf_listener_cb, NULL);
    356       1.2  christos #endif
    357       1.2  christos 
    358       1.1  christos 	if (ipf_load_all() == 0)
    359       1.1  christos 		(void) ipf_create_all(&ipfmain);
    360      1.13  pgoyette #endif
    361       1.1  christos }
    362       1.1  christos 
    363       1.1  christos 
    364       1.1  christos int
    365       1.2  christos ipfattach(ipf_main_softc_t *softc)
    366       1.1  christos {
    367       1.1  christos 	SPL_INT(s);
    368       1.1  christos #if (__NetBSD_Version__ >= 499005500)
    369       1.1  christos 	int i;
    370       1.1  christos #endif
    371       1.1  christos #if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)
    372       1.1  christos 	int error = 0;
    373       1.1  christos # if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000)
    374       1.5     rmind         pfil_head_t *ph_inet;
    375       1.1  christos #  ifdef USE_INET6
    376       1.5     rmind         pfil_head_t *ph_inet6;
    377       1.1  christos #  endif
    378       1.1  christos #  if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    379       1.5     rmind         pfil_head_t *ph_ifsync;
    380       1.1  christos #  endif
    381       1.1  christos # endif
    382       1.1  christos #endif
    383       1.1  christos 
    384       1.1  christos 	SPL_NET(s);
    385       1.1  christos 	if ((softc->ipf_running > 0) || (ipf_checkp == ipf_check)) {
    386       1.1  christos 		printf("IP Filter: already initialized\n");
    387       1.1  christos 		SPL_X(s);
    388       1.1  christos 		IPFERROR(130017);
    389       1.1  christos 		return EBUSY;
    390       1.1  christos 	}
    391       1.1  christos 
    392       1.1  christos 	if (ipf_init_all(softc) < 0) {
    393       1.1  christos 		SPL_X(s);
    394       1.1  christos 		IPFERROR(130015);
    395       1.1  christos 		return EIO;
    396       1.1  christos 	}
    397       1.1  christos 
    398       1.1  christos #ifdef NETBSD_PF
    399       1.1  christos # if (__NetBSD_Version__ >= 104200000)
    400       1.1  christos #  if __NetBSD_Version__ >= 105110000
    401       1.5     rmind 	ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET);
    402       1.1  christos #   ifdef USE_INET6
    403       1.5     rmind 	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6);
    404       1.1  christos #   endif
    405       1.1  christos #   if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    406       1.1  christos 	ph_ifsync = pfil_head_get(PFIL_TYPE_IFNET, 0);
    407       1.1  christos #   endif
    408       1.1  christos 
    409       1.1  christos 	if (ph_inet == NULL
    410       1.1  christos #   ifdef USE_INET6
    411       1.1  christos 	    && ph_inet6 == NULL
    412       1.1  christos #   endif
    413       1.1  christos #   if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    414       1.1  christos 	    && ph_ifsync == NULL
    415       1.1  christos #   endif
    416       1.1  christos 	   ) {
    417       1.1  christos 		SPL_X(s);
    418       1.1  christos 		IPFERROR(130016);
    419       1.1  christos 		return ENODEV;
    420       1.1  christos 	}
    421       1.1  christos 
    422       1.1  christos 	if (ph_inet != NULL)
    423       1.1  christos 		error = pfil_add_hook((void *)ipf_check_wrapper, NULL,
    424       1.1  christos 				      PFIL_IN|PFIL_OUT, ph_inet);
    425       1.1  christos 	else
    426       1.1  christos 		error = 0;
    427       1.1  christos #  else
    428       1.1  christos 	error = pfil_add_hook((void *)ipf_check, PFIL_IN|PFIL_OUT,
    429       1.1  christos 			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
    430       1.1  christos #  endif
    431       1.1  christos 	if (error) {
    432       1.1  christos 		IPFERROR(130013);
    433       1.1  christos 		goto pfil_error;
    434       1.1  christos 	}
    435       1.1  christos # else
    436       1.1  christos 	pfil_add_hook((void *)ipf_check, PFIL_IN|PFIL_OUT);
    437       1.1  christos # endif
    438       1.1  christos 
    439       1.1  christos # ifdef USE_INET6
    440       1.1  christos #  if __NetBSD_Version__ >= 105110000
    441       1.1  christos 	if (ph_inet6 != NULL)
    442       1.1  christos 		error = pfil_add_hook((void *)ipf_check_wrapper6, NULL,
    443       1.1  christos 				      PFIL_IN|PFIL_OUT, ph_inet6);
    444       1.1  christos 	else
    445       1.1  christos 		error = 0;
    446       1.1  christos 	if (error) {
    447       1.1  christos 		pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
    448       1.1  christos 				 PFIL_IN|PFIL_OUT, ph_inet6);
    449       1.1  christos 		ipfmain.ipf_interror = 130014;
    450       1.1  christos 		goto pfil_error;
    451       1.1  christos 	}
    452       1.1  christos #  else
    453       1.1  christos 	error = pfil_add_hook((void *)ipf_check, PFIL_IN|PFIL_OUT,
    454       1.1  christos 			      &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
    455       1.1  christos 	if (error) {
    456       1.1  christos 		pfil_remove_hook((void *)ipf_check, PFIL_IN|PFIL_OUT,
    457       1.1  christos 				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
    458       1.1  christos 		IPFERROR(130014);
    459       1.1  christos 		goto pfil_error;
    460       1.1  christos 	}
    461       1.1  christos #  endif
    462       1.1  christos # endif
    463       1.1  christos 
    464       1.1  christos # if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    465       1.1  christos 	if (ph_ifsync != NULL)
    466      1.20  christos #if (__NetBSD_Version__ >= 799000400)
    467      1.21  christos 		(void) pfil_add_ihook((void *)ipf_pfilsync, NULL,
    468      1.21  christos 				      PFIL_IFNET, ph_ifsync);
    469      1.20  christos #else
    470      1.20  christos 		(void) pfil_add_hook((void *)ipf_pfilsync, NULL,
    471      1.20  christos 				     PFIL_IFNET, ph_ifsync);
    472      1.20  christos #endif
    473       1.1  christos # endif
    474       1.1  christos #endif
    475       1.1  christos 
    476       1.1  christos #if (__NetBSD_Version__ >= 499005500)
    477       1.1  christos 	for (i = 0; i < IPL_LOGSIZE; i++)
    478       1.1  christos 		selinit(&ipfmain.ipf_selwait[i]);
    479       1.1  christos #else
    480       1.1  christos 	bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait));
    481       1.1  christos #endif
    482       1.1  christos 	ipf_savep = ipf_checkp;
    483       1.1  christos 	ipf_checkp = ipf_check;
    484       1.1  christos 
    485       1.1  christos #ifdef INET
    486       1.1  christos 	if (softc->ipf_control_forwarding & 1)
    487       1.1  christos 		ipforwarding = 1;
    488       1.1  christos #endif
    489       1.1  christos 
    490       1.1  christos 	ipid = 0;
    491       1.1  christos 
    492       1.1  christos 	SPL_X(s);
    493       1.1  christos 
    494       1.1  christos #if (__NetBSD_Version__ >= 104010000)
    495       1.1  christos # if (__NetBSD_Version__ >= 499002000)
    496       1.1  christos 	callout_init(&softc->ipf_slow_ch, 0);
    497       1.1  christos # else
    498       1.1  christos 	callout_init(&softc->ipf_slow_ch);
    499       1.1  christos # endif
    500       1.1  christos 	callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
    501       1.1  christos 		     ipf_timer_func, softc);
    502       1.1  christos #else
    503       1.1  christos 	timeout(ipf_timer_func, softc, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
    504       1.1  christos #endif
    505       1.2  christos 
    506       1.1  christos 	return 0;
    507       1.1  christos 
    508       1.1  christos #if __NetBSD_Version__ >= 105110000
    509       1.1  christos pfil_error:
    510       1.1  christos 	SPL_X(s);
    511       1.1  christos 	ipf_fini_all(softc);
    512       1.1  christos 	return error;
    513       1.1  christos #endif
    514       1.1  christos }
    515       1.1  christos 
    516       1.1  christos static void
    517       1.2  christos ipf_timer_func(void *ptr)
    518       1.1  christos {
    519       1.1  christos 	ipf_main_softc_t *softc = ptr;
    520       1.1  christos 	SPL_INT(s);
    521       1.1  christos 
    522       1.1  christos 	SPL_NET(s);
    523       1.1  christos 	READ_ENTER(&softc->ipf_global);
    524       1.1  christos 
    525       1.1  christos 	if (softc->ipf_running > 0)
    526       1.1  christos 		ipf_slowtimer(softc);
    527       1.1  christos 
    528       1.1  christos 	if (softc->ipf_running == -1 || softc->ipf_running == 1) {
    529       1.1  christos #if NETBSD_GE_REV(104240000)
    530       1.1  christos 		callout_reset(&softc->ipf_slow_ch, hz / 2,
    531       1.1  christos 			      ipf_timer_func, softc);
    532       1.1  christos #else
    533       1.1  christos 		timeout(ipf_timer_func, softc,
    534       1.1  christos 			(hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
    535       1.1  christos #endif
    536       1.1  christos 	}
    537       1.1  christos 	RWLOCK_EXIT(&softc->ipf_global);
    538       1.1  christos 	SPL_X(s);
    539       1.1  christos }
    540       1.1  christos 
    541       1.1  christos 
    542       1.1  christos /*
    543       1.1  christos  * Disable the filter by removing the hooks from the IP input/output
    544       1.1  christos  * stream.
    545       1.1  christos  */
    546       1.1  christos int
    547       1.2  christos ipfdetach(ipf_main_softc_t *softc)
    548       1.1  christos {
    549       1.1  christos 	SPL_INT(s);
    550       1.1  christos #if (__NetBSD_Version__ >= 499005500)
    551       1.1  christos 	int i;
    552       1.1  christos #endif
    553       1.1  christos #if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)
    554       1.1  christos 	int error = 0;
    555       1.1  christos # if __NetBSD_Version__ >= 105150000
    556       1.5     rmind 	pfil_head_t *ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET);
    557       1.1  christos #  ifdef USE_INET6
    558       1.5     rmind 	pfil_head_t *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6);
    559       1.1  christos #  endif
    560       1.1  christos #  if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    561       1.1  christos 	struct pfil_head *ph_ifsync = pfil_head_get(PFIL_TYPE_IFNET, 0);
    562       1.1  christos #  endif
    563       1.1  christos # endif
    564       1.1  christos #endif
    565       1.1  christos 
    566       1.1  christos 	SPL_NET(s);
    567       1.1  christos 
    568       1.1  christos #if (__NetBSD_Version__ >= 104010000)
    569       1.1  christos 	if (softc->ipf_running > 0)
    570       1.1  christos 		callout_stop(&softc->ipf_slow_ch);
    571       1.1  christos #else
    572       1.1  christos 	untimeout(ipf_slowtimer, NULL);
    573       1.1  christos #endif /* NetBSD */
    574       1.1  christos 
    575       1.1  christos 	ipf_checkp = ipf_savep;
    576       1.1  christos 	(void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
    577       1.1  christos 	(void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
    578       1.1  christos 
    579       1.1  christos #ifdef INET
    580       1.1  christos 	if (softc->ipf_control_forwarding & 2)
    581       1.1  christos 		ipforwarding = 0;
    582       1.1  christos #endif
    583       1.1  christos 
    584       1.1  christos #ifdef NETBSD_PF
    585       1.1  christos # if (__NetBSD_Version__ >= 104200000)
    586       1.1  christos #  if __NetBSD_Version__ >= 105110000
    587       1.1  christos #   if defined(PFIL_TYPE_IFNET) && defined(PFIL_IFNET)
    588       1.1  christos 	(void) pfil_remove_hook((void *)ipf_pfilsync, NULL,
    589       1.1  christos 				PFIL_IFNET, ph_ifsync);
    590       1.1  christos #   endif
    591       1.1  christos 
    592       1.1  christos 	if (ph_inet != NULL)
    593       1.1  christos 		error = pfil_remove_hook((void *)ipf_check_wrapper, NULL,
    594       1.1  christos 					 PFIL_IN|PFIL_OUT, ph_inet);
    595       1.1  christos 	else
    596       1.1  christos 		error = 0;
    597       1.1  christos #  else
    598       1.1  christos 	error = pfil_remove_hook((void *)ipf_check, PFIL_IN|PFIL_OUT,
    599       1.1  christos 				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
    600       1.1  christos #  endif
    601       1.1  christos 	if (error) {
    602       1.1  christos 		SPL_X(s);
    603       1.1  christos 		IPFERROR(130011);
    604       1.1  christos 		return error;
    605       1.1  christos 	}
    606       1.1  christos # else
    607       1.1  christos 	pfil_remove_hook((void *)ipf_check, PFIL_IN|PFIL_OUT);
    608       1.1  christos # endif
    609       1.1  christos # ifdef USE_INET6
    610       1.1  christos #  if __NetBSD_Version__ >= 105110000
    611       1.1  christos 	if (ph_inet6 != NULL)
    612       1.1  christos 		error = pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
    613       1.1  christos 					 PFIL_IN|PFIL_OUT, ph_inet6);
    614       1.1  christos 	else
    615       1.1  christos 		error = 0;
    616       1.1  christos #  else
    617       1.1  christos 	error = pfil_remove_hook((void *)ipf_check, PFIL_IN|PFIL_OUT,
    618       1.1  christos 				 &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
    619       1.1  christos #  endif
    620       1.1  christos 	if (error) {
    621       1.1  christos 		SPL_X(s);
    622       1.1  christos 		IPFERROR(130012);
    623       1.1  christos 		return error;
    624       1.1  christos 	}
    625       1.1  christos # endif
    626       1.1  christos #endif
    627       1.1  christos 	SPL_X(s);
    628       1.1  christos 
    629       1.1  christos #if (__NetBSD_Version__ >= 499005500)
    630       1.1  christos 	for (i = 0; i < IPL_LOGSIZE; i++)
    631       1.1  christos 		seldestroy(&ipfmain.ipf_selwait[i]);
    632       1.1  christos #endif
    633       1.1  christos 
    634       1.1  christos 	ipf_fini_all(softc);
    635       1.1  christos 
    636       1.1  christos 	return 0;
    637       1.1  christos }
    638       1.1  christos 
    639       1.1  christos 
    640       1.1  christos /*
    641       1.1  christos  * Filter ioctl interface.
    642       1.1  christos  */
    643       1.1  christos int
    644       1.2  christos ipfioctl(dev_t dev, u_long cmd,
    645       1.2  christos #if  (__NetBSD_Version__ >= 499001000)
    646       1.2  christos 	void *data,
    647       1.2  christos #else
    648       1.2  christos 	caddr_t data,
    649       1.2  christos #endif
    650       1.2  christos 	int mode
    651       1.1  christos #if (NetBSD >= 199511)
    652       1.1  christos # if  (__NetBSD_Version__ >= 399001400)
    653       1.2  christos 	, struct lwp *p
    654       1.1  christos #   if (__NetBSD_Version__ >= 399002000)
    655       1.1  christos #     define	UID(l)	kauth_cred_getuid((l)->l_cred)
    656       1.1  christos #  else
    657       1.1  christos #     define	UID(l)	((l)->l_proc->p_cred->p_ruid)
    658       1.1  christos #  endif
    659       1.1  christos # else
    660       1.2  christos 	, struct proc *p
    661       1.1  christos #  define	UID(p)	((p)->p_cred->p_ruid)
    662       1.1  christos # endif
    663       1.2  christos #endif
    664       1.1  christos )
    665       1.1  christos {
    666       1.1  christos 	int error = 0, unit = 0;
    667       1.1  christos 	SPL_INT(s);
    668       1.1  christos 
    669       1.1  christos #if (__NetBSD_Version__ >= 399002000)
    670       1.1  christos 	if ((mode & FWRITE) &&
    671       1.1  christos 	    kauth_authorize_network(p->l_cred, KAUTH_NETWORK_FIREWALL,
    672       1.1  christos 				    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL,
    673       1.1  christos 				    NULL, NULL)) {
    674       1.1  christos 		ipfmain.ipf_interror = 130005;
    675       1.1  christos 		return EPERM;
    676       1.1  christos 	}
    677       1.1  christos #else
    678       1.1  christos 	if ((securelevel >= 2) && (mode & FWRITE)) {
    679       1.1  christos 		ipfmain.ipf_interror = 130001;
    680       1.1  christos 		return EPERM;
    681       1.1  christos 	}
    682       1.1  christos #endif
    683       1.1  christos 
    684       1.1  christos   	unit = GET_MINOR(dev);
    685       1.1  christos   	if ((IPL_LOGMAX < unit) || (unit < 0)) {
    686       1.1  christos 		ipfmain.ipf_interror = 130002;
    687       1.1  christos 		return ENXIO;
    688       1.1  christos 	}
    689       1.1  christos 
    690       1.1  christos 	if (ipfmain.ipf_running <= 0) {
    691       1.2  christos 		if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
    692       1.1  christos 			ipfmain.ipf_interror = 130003;
    693       1.1  christos 			return EIO;
    694       1.1  christos 		}
    695       1.1  christos 		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
    696       1.1  christos 		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
    697       1.1  christos 		    cmd != SIOCGETFS && cmd != SIOCGETFF &&
    698       1.1  christos 		    cmd != SIOCIPFINTERROR) {
    699       1.1  christos 			ipfmain.ipf_interror = 130004;
    700       1.1  christos 			return EIO;
    701       1.1  christos 		}
    702       1.1  christos 	}
    703       1.1  christos 
    704       1.1  christos 	SPL_NET(s);
    705       1.1  christos 
    706       1.1  christos 	error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, UID(p), p);
    707       1.1  christos 	if (error != -1) {
    708       1.1  christos 		SPL_X(s);
    709       1.1  christos 		return error;
    710       1.1  christos 	}
    711       1.1  christos 
    712       1.1  christos 	SPL_X(s);
    713       1.1  christos 	return error;
    714       1.1  christos }
    715       1.1  christos 
    716       1.1  christos 
    717       1.1  christos /*
    718       1.1  christos  * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
    719       1.1  christos  * requires a large amount of setting up and isn't any more efficient.
    720       1.1  christos  */
    721       1.1  christos int
    722       1.2  christos ipf_send_reset(fr_info_t *fin)
    723       1.1  christos {
    724       1.1  christos 	struct tcphdr *tcp, *tcp2;
    725       1.1  christos 	int tlen = 0, hlen;
    726       1.1  christos 	struct mbuf *m;
    727       1.1  christos #ifdef USE_INET6
    728       1.1  christos 	ip6_t *ip6;
    729       1.1  christos #endif
    730       1.1  christos 	ip_t *ip;
    731       1.1  christos 
    732       1.1  christos 	tcp = fin->fin_dp;
    733       1.1  christos 	if (tcp->th_flags & TH_RST)
    734       1.1  christos 		return -1;		/* feedback loop */
    735       1.1  christos 
    736       1.1  christos 	if (ipf_checkl4sum(fin) == -1)
    737       1.1  christos 		return -1;
    738       1.1  christos 
    739       1.1  christos 	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
    740       1.1  christos 			((tcp->th_flags & TH_SYN) ? 1 : 0) +
    741       1.1  christos 			((tcp->th_flags & TH_FIN) ? 1 : 0);
    742       1.1  christos 
    743       1.1  christos #ifdef USE_INET6
    744       1.1  christos 	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
    745       1.1  christos #else
    746       1.1  christos 	hlen = sizeof(ip_t);
    747       1.1  christos #endif
    748       1.1  christos #ifdef MGETHDR
    749       1.1  christos 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
    750       1.1  christos #else
    751       1.1  christos 	MGET(m, M_DONTWAIT, MT_HEADER);
    752       1.1  christos #endif
    753       1.1  christos 	if (m == NULL)
    754       1.1  christos 		return -1;
    755       1.1  christos 	if (sizeof(*tcp2) + hlen > MHLEN) {
    756       1.1  christos 		MCLGET(m, M_DONTWAIT);
    757       1.1  christos 		if (m == NULL)
    758       1.1  christos 			return -1;
    759       1.1  christos 		if ((m->m_flags & M_EXT) == 0) {
    760       1.1  christos 			FREE_MB_T(m);
    761       1.1  christos 			return -1;
    762       1.1  christos 		}
    763       1.1  christos 	}
    764       1.1  christos 
    765       1.1  christos 	m->m_len = sizeof(*tcp2) + hlen;
    766       1.1  christos 	m->m_data += max_linkhdr;
    767       1.1  christos 	m->m_pkthdr.len = m->m_len;
    768      1.14     ozaki 	m_reset_rcvif(m);
    769       1.1  christos 	ip = mtod(m, struct ip *);
    770       1.1  christos 	bzero((char *)ip, hlen);
    771       1.1  christos #ifdef USE_INET6
    772       1.1  christos 	ip6 = (ip6_t *)ip;
    773       1.1  christos #endif
    774       1.1  christos 	bzero((char *)ip, sizeof(*tcp2) + hlen);
    775       1.1  christos 	tcp2 = (struct tcphdr *)((char *)ip + hlen);
    776       1.1  christos 	tcp2->th_sport = tcp->th_dport;
    777       1.1  christos 	tcp2->th_dport = tcp->th_sport;
    778       1.1  christos 
    779       1.1  christos 	if (tcp->th_flags & TH_ACK) {
    780       1.1  christos 		tcp2->th_seq = tcp->th_ack;
    781       1.1  christos 		tcp2->th_flags = TH_RST;
    782       1.1  christos 		tcp2->th_ack = 0;
    783       1.1  christos 	} else {
    784       1.1  christos 		tcp2->th_seq = 0;
    785       1.1  christos 		tcp2->th_ack = ntohl(tcp->th_seq);
    786       1.1  christos 		tcp2->th_ack += tlen;
    787       1.1  christos 		tcp2->th_ack = htonl(tcp2->th_ack);
    788       1.1  christos 		tcp2->th_flags = TH_RST|TH_ACK;
    789       1.1  christos 	}
    790       1.1  christos 	tcp2->th_x2 = 0;
    791       1.1  christos 	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
    792       1.1  christos 	tcp2->th_win = tcp->th_win;
    793       1.1  christos 	tcp2->th_sum = 0;
    794       1.1  christos 	tcp2->th_urp = 0;
    795       1.1  christos 
    796       1.1  christos #ifdef USE_INET6
    797       1.1  christos 	if (fin->fin_v == 6) {
    798       1.1  christos 		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
    799       1.1  christos 		ip6->ip6_plen = htons(sizeof(struct tcphdr));
    800       1.1  christos 		ip6->ip6_nxt = IPPROTO_TCP;
    801       1.1  christos 		ip6->ip6_hlim = 0;
    802       1.1  christos 		ip6->ip6_src = fin->fin_dst6.in6;
    803       1.1  christos 		ip6->ip6_dst = fin->fin_src6.in6;
    804       1.1  christos 		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
    805       1.1  christos 					 sizeof(*ip6), sizeof(*tcp2));
    806       1.1  christos 		return ipf_send_ip(fin, m);
    807       1.1  christos 	}
    808       1.1  christos #endif
    809       1.1  christos #ifdef INET
    810       1.1  christos 	ip->ip_p = IPPROTO_TCP;
    811       1.1  christos 	ip->ip_len = htons(sizeof(struct tcphdr));
    812       1.1  christos 	ip->ip_src.s_addr = fin->fin_daddr;
    813       1.1  christos 	ip->ip_dst.s_addr = fin->fin_saddr;
    814       1.1  christos 	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
    815       1.1  christos 	ip->ip_len = hlen + sizeof(*tcp2);
    816       1.1  christos 	return ipf_send_ip(fin, m);
    817       1.1  christos #else
    818       1.1  christos 	return 0;
    819       1.1  christos #endif
    820       1.1  christos }
    821       1.1  christos 
    822       1.1  christos 
    823       1.1  christos /*
    824       1.1  christos  * Expects ip_len to be in host byte order when called.
    825       1.1  christos  */
    826       1.1  christos static int
    827       1.2  christos ipf_send_ip(fr_info_t *fin, mb_t *m)
    828       1.1  christos {
    829       1.1  christos 	fr_info_t fnew;
    830       1.1  christos #ifdef INET
    831       1.1  christos 	ip_t *oip;
    832       1.1  christos #endif
    833       1.1  christos 	ip_t *ip;
    834       1.1  christos 	int hlen;
    835       1.1  christos 
    836       1.1  christos 	ip = mtod(m, ip_t *);
    837       1.1  christos 	bzero((char *)&fnew, sizeof(fnew));
    838       1.1  christos 	fnew.fin_main_soft = fin->fin_main_soft;
    839       1.1  christos 
    840       1.1  christos 	IP_V_A(ip, fin->fin_v);
    841       1.1  christos 	switch (fin->fin_v)
    842       1.1  christos 	{
    843       1.1  christos #ifdef INET
    844       1.1  christos 	case 4 :
    845       1.1  christos 		oip = fin->fin_ip;
    846       1.1  christos 		hlen = sizeof(*oip);
    847       1.1  christos 		fnew.fin_v = 4;
    848       1.1  christos 		fnew.fin_p = ip->ip_p;
    849       1.1  christos 		fnew.fin_plen = ntohs(ip->ip_len);
    850       1.1  christos 		HTONS(ip->ip_len);
    851       1.1  christos 		IP_HL_A(ip, sizeof(*oip) >> 2);
    852       1.1  christos 		ip->ip_tos = oip->ip_tos;
    853       1.1  christos 		ip->ip_id = ipf_nextipid(fin);
    854       1.1  christos 		ip->ip_off = htons(ip_mtudisc ? IP_DF : 0);
    855       1.1  christos 		ip->ip_ttl = ip_defttl;
    856       1.1  christos 		ip->ip_sum = 0;
    857       1.1  christos 		break;
    858       1.1  christos #endif
    859       1.1  christos #ifdef USE_INET6
    860       1.1  christos 	case 6 :
    861       1.1  christos 	{
    862       1.1  christos 		ip6_t *ip6 = (ip6_t *)ip;
    863       1.1  christos 
    864       1.1  christos 		ip6->ip6_vfc = 0x60;
    865       1.1  christos 		ip6->ip6_hlim = IPDEFTTL;
    866       1.1  christos 
    867       1.1  christos 		hlen = sizeof(*ip6);
    868       1.1  christos 		fnew.fin_p = ip6->ip6_nxt;
    869       1.1  christos 		fnew.fin_v = 6;
    870       1.1  christos 		fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
    871       1.1  christos 		break;
    872       1.1  christos 	}
    873       1.1  christos #endif
    874       1.1  christos 	default :
    875       1.1  christos 		return EINVAL;
    876       1.1  christos 	}
    877       1.2  christos #ifdef KAME_IPSEC
    878      1.14     ozaki 	m_reset_rcvif(m);
    879       1.1  christos #endif
    880       1.1  christos 
    881       1.1  christos 	fnew.fin_ifp = fin->fin_ifp;
    882       1.1  christos 	fnew.fin_flx = FI_NOCKSUM;
    883       1.1  christos 	fnew.fin_m = m;
    884       1.1  christos 	fnew.fin_ip = ip;
    885       1.1  christos 	fnew.fin_mp = &m;
    886       1.1  christos 	fnew.fin_hlen = hlen;
    887       1.1  christos 	fnew.fin_dp = (char *)ip + hlen;
    888       1.1  christos 	(void) ipf_makefrip(hlen, ip, &fnew);
    889       1.1  christos 
    890       1.1  christos 	return ipf_fastroute(m, &m, &fnew, NULL);
    891       1.1  christos }
    892       1.1  christos 
    893       1.1  christos 
    894       1.1  christos int
    895       1.2  christos ipf_send_icmp_err(int type, fr_info_t *fin, int dst)
    896       1.1  christos {
    897       1.7       mrg 	int err, hlen, xtra, iclen, ohlen, avail;
    898       1.1  christos 	struct in_addr dst4;
    899       1.1  christos 	struct icmp *icmp;
    900       1.1  christos 	struct mbuf *m;
    901       1.1  christos 	i6addr_t dst6;
    902       1.1  christos 	void *ifp;
    903       1.1  christos #ifdef USE_INET6
    904       1.7       mrg 	int code;
    905       1.1  christos 	ip6_t *ip6;
    906       1.1  christos #endif
    907       1.1  christos 	ip_t *ip, *ip2;
    908       1.1  christos 
    909       1.1  christos 	if ((type < 0) || (type > ICMP_MAXTYPE))
    910       1.1  christos 		return -1;
    911       1.1  christos 
    912       1.7       mrg #ifdef USE_INET6
    913       1.1  christos 	code = fin->fin_icode;
    914       1.4   msaitoh 	if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
    915       1.1  christos 		return -1;
    916       1.1  christos #endif
    917       1.1  christos 
    918       1.1  christos 	if (ipf_checkl4sum(fin) == -1)
    919       1.1  christos 		return -1;
    920       1.1  christos #ifdef MGETHDR
    921       1.1  christos 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
    922       1.1  christos #else
    923       1.1  christos 	MGET(m, M_DONTWAIT, MT_HEADER);
    924       1.1  christos #endif
    925       1.1  christos 	if (m == NULL)
    926       1.1  christos 		return -1;
    927       1.1  christos 	avail = MHLEN;
    928       1.1  christos 
    929       1.1  christos 	xtra = 0;
    930       1.1  christos 	hlen = 0;
    931       1.1  christos 	ohlen = 0;
    932       1.1  christos 	dst4.s_addr = 0;
    933       1.1  christos 	ifp = fin->fin_ifp;
    934       1.1  christos 	if (fin->fin_v == 4) {
    935       1.1  christos 		if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
    936       1.1  christos 			switch (ntohs(fin->fin_data[0]) >> 8)
    937       1.1  christos 			{
    938       1.1  christos 			case ICMP_ECHO :
    939       1.1  christos 			case ICMP_TSTAMP :
    940       1.1  christos 			case ICMP_IREQ :
    941       1.1  christos 			case ICMP_MASKREQ :
    942       1.1  christos 				break;
    943       1.1  christos 			default :
    944       1.1  christos 				FREE_MB_T(m);
    945       1.1  christos 				return 0;
    946       1.1  christos 			}
    947       1.1  christos 
    948       1.1  christos 		if (dst == 0) {
    949       1.1  christos 			if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp,
    950       1.1  christos 				       &dst6, NULL) == -1) {
    951       1.1  christos 				FREE_MB_T(m);
    952       1.1  christos 				return -1;
    953       1.1  christos 			}
    954       1.1  christos 			dst4 = dst6.in4;
    955       1.1  christos 		} else
    956       1.1  christos 			dst4.s_addr = fin->fin_daddr;
    957       1.1  christos 
    958       1.1  christos 		hlen = sizeof(ip_t);
    959       1.1  christos 		ohlen = fin->fin_hlen;
    960       1.1  christos 		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
    961       1.1  christos 		if (fin->fin_hlen < fin->fin_plen)
    962       1.1  christos 			xtra = MIN(fin->fin_dlen, 8);
    963       1.1  christos 		else
    964       1.1  christos 			xtra = 0;
    965       1.1  christos 	}
    966       1.1  christos 
    967       1.1  christos #ifdef USE_INET6
    968       1.1  christos 	else if (fin->fin_v == 6) {
    969       1.1  christos 		hlen = sizeof(ip6_t);
    970       1.1  christos 		ohlen = sizeof(ip6_t);
    971       1.1  christos 		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
    972       1.1  christos 		type = icmptoicmp6types[type];
    973       1.1  christos 		if (type == ICMP6_DST_UNREACH)
    974       1.1  christos 			code = icmptoicmp6unreach[code];
    975       1.1  christos 
    976       1.1  christos 		if (iclen + max_linkhdr + fin->fin_plen > avail) {
    977       1.1  christos 			MCLGET(m, M_DONTWAIT);
    978       1.1  christos 			if (m == NULL)
    979       1.1  christos 				return -1;
    980       1.1  christos 			if ((m->m_flags & M_EXT) == 0) {
    981       1.1  christos 				FREE_MB_T(m);
    982       1.1  christos 				return -1;
    983       1.1  christos 			}
    984       1.1  christos 			avail = MCLBYTES;
    985       1.1  christos 		}
    986       1.1  christos 		xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
    987       1.1  christos 		xtra = MIN(xtra, IPV6_MMTU - iclen);
    988       1.1  christos 		if (dst == 0) {
    989       1.1  christos 			if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp,
    990       1.1  christos 				       &dst6, NULL) == -1) {
    991       1.1  christos 				FREE_MB_T(m);
    992       1.1  christos 				return -1;
    993       1.1  christos 			}
    994       1.1  christos 		} else
    995       1.1  christos 			dst6 = fin->fin_dst6;
    996       1.1  christos 	}
    997       1.1  christos #endif
    998       1.1  christos 	else {
    999       1.1  christos 		FREE_MB_T(m);
   1000       1.1  christos 		return -1;
   1001       1.1  christos 	}
   1002       1.1  christos 
   1003       1.1  christos 	avail -= (max_linkhdr + iclen);
   1004       1.1  christos 	if (avail < 0) {
   1005       1.1  christos 		FREE_MB_T(m);
   1006       1.1  christos 		return -1;
   1007       1.1  christos 	}
   1008       1.1  christos 	if (xtra > avail)
   1009       1.1  christos 		xtra = avail;
   1010       1.1  christos 	iclen += xtra;
   1011       1.1  christos 	m->m_data += max_linkhdr;
   1012      1.14     ozaki 	m_reset_rcvif(m);
   1013       1.1  christos 	m->m_pkthdr.len = iclen;
   1014       1.1  christos 	m->m_len = iclen;
   1015       1.1  christos 	ip = mtod(m, ip_t *);
   1016       1.1  christos 	icmp = (struct icmp *)((char *)ip + hlen);
   1017       1.1  christos 	ip2 = (ip_t *)&icmp->icmp_ip;
   1018       1.1  christos 
   1019       1.1  christos 	icmp->icmp_type = type;
   1020       1.1  christos 	icmp->icmp_code = fin->fin_icode;
   1021       1.1  christos 	icmp->icmp_cksum = 0;
   1022       1.1  christos #ifdef icmp_nextmtu
   1023       1.1  christos 	if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
   1024       1.1  christos 		if (fin->fin_mtu != 0) {
   1025       1.1  christos 			icmp->icmp_nextmtu = htons(fin->fin_mtu);
   1026       1.1  christos 
   1027       1.1  christos 		} else if (ifp != NULL) {
   1028       1.1  christos 			icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
   1029       1.1  christos 
   1030       1.1  christos 		} else {	/* make up a number... */
   1031       1.1  christos 			icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
   1032       1.1  christos 		}
   1033       1.1  christos 	}
   1034       1.1  christos #endif
   1035       1.1  christos 
   1036       1.1  christos 	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
   1037       1.1  christos 
   1038       1.1  christos #if defined(M_CSUM_IPv4)
   1039       1.1  christos 	/*
   1040       1.1  christos 	 * Clear any in-bound checksum flags for this packet.
   1041       1.1  christos 	 */
   1042       1.1  christos 	m->m_pkthdr.csuminfo = 0;
   1043       1.1  christos #endif /* __NetBSD__ && M_CSUM_IPv4 */
   1044       1.1  christos 
   1045       1.1  christos #ifdef USE_INET6
   1046       1.1  christos 	ip6 = (ip6_t *)ip;
   1047       1.1  christos 	if (fin->fin_v == 6) {
   1048       1.1  christos 		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
   1049       1.1  christos 		ip6->ip6_plen = htons(iclen - hlen);
   1050       1.1  christos 		ip6->ip6_nxt = IPPROTO_ICMPV6;
   1051       1.1  christos 		ip6->ip6_hlim = 0;
   1052       1.1  christos 		ip6->ip6_src = dst6.in6;
   1053       1.1  christos 		ip6->ip6_dst = fin->fin_src6.in6;
   1054       1.1  christos 		if (xtra > 0)
   1055       1.1  christos 			bcopy((char *)fin->fin_ip + ohlen,
   1056       1.1  christos 			      (char *)&icmp->icmp_ip + ohlen, xtra);
   1057       1.1  christos 		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
   1058       1.1  christos 					     sizeof(*ip6), iclen - hlen);
   1059       1.1  christos 	} else
   1060       1.1  christos #endif
   1061       1.1  christos 	{
   1062       1.1  christos 		ip->ip_p = IPPROTO_ICMP;
   1063       1.1  christos 		ip->ip_src.s_addr = dst4.s_addr;
   1064       1.1  christos 		ip->ip_dst.s_addr = fin->fin_saddr;
   1065       1.1  christos 
   1066       1.1  christos 		if (xtra > 0)
   1067       1.1  christos 			bcopy((char *)fin->fin_ip + ohlen,
   1068       1.1  christos 			      (char *)&icmp->icmp_ip + ohlen, xtra);
   1069       1.1  christos 		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
   1070       1.1  christos 					     sizeof(*icmp) + 8);
   1071       1.1  christos 		ip->ip_len = iclen;
   1072       1.1  christos 		ip->ip_p = IPPROTO_ICMP;
   1073       1.1  christos 	}
   1074       1.1  christos 	err = ipf_send_ip(fin, m);
   1075       1.1  christos 	return err;
   1076       1.1  christos }
   1077       1.1  christos 
   1078       1.1  christos 
   1079       1.1  christos /*
   1080       1.1  christos  * m0 - pointer to mbuf where the IP packet starts
   1081       1.1  christos  * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
   1082       1.1  christos  */
   1083       1.1  christos int
   1084       1.2  christos ipf_fastroute(mb_t *m0, mb_t **mpp, fr_info_t *fin, frdest_t *fdp)
   1085       1.1  christos {
   1086       1.1  christos 	register struct ip *ip, *mhip;
   1087       1.1  christos 	register struct mbuf *m = *mpp;
   1088       1.1  christos 	register struct route *ro;
   1089       1.1  christos 	int len, off, error = 0, hlen, code;
   1090       1.1  christos 	struct ifnet *ifp, *sifp;
   1091       1.1  christos 	ipf_main_softc_t *softc;
   1092       1.1  christos #if __NetBSD_Version__ >= 499001100
   1093       1.1  christos 	union {
   1094       1.1  christos 		struct sockaddr         dst;
   1095       1.1  christos 		struct sockaddr_in      dst4;
   1096       1.1  christos 	} u;
   1097       1.1  christos #else
   1098       1.1  christos 	struct sockaddr_in *dst4;
   1099       1.1  christos #endif
   1100       1.1  christos 	struct sockaddr *dst;
   1101       1.1  christos 	u_short ip_off, ip_len;
   1102       1.1  christos 	struct route iproute;
   1103       1.1  christos 	struct rtentry *rt;
   1104       1.1  christos 	frdest_t node;
   1105       1.1  christos 	frentry_t *fr;
   1106       1.1  christos 
   1107       1.1  christos 	if (fin->fin_v == 6) {
   1108       1.1  christos #ifdef USE_INET6
   1109       1.1  christos 		error = ipf_fastroute6(m0, mpp, fin, fdp);
   1110       1.1  christos #else
   1111       1.1  christos 		error = EPROTONOSUPPORT;
   1112       1.1  christos #endif
   1113       1.1  christos 		if ((error != 0) && (*mpp != NULL))
   1114       1.1  christos 			FREE_MB_T(*mpp);
   1115       1.1  christos 		return error;
   1116       1.1  christos 	}
   1117       1.1  christos #ifndef INET
   1118       1.1  christos 	FREE_MB_T(*mpp);
   1119       1.1  christos 	return EPROTONOSUPPORT;
   1120       1.1  christos #else
   1121       1.1  christos 
   1122       1.1  christos 	hlen = fin->fin_hlen;
   1123       1.1  christos 	ip = mtod(m0, struct ip *);
   1124       1.1  christos 	softc = fin->fin_main_soft;
   1125       1.1  christos 	rt = NULL;
   1126       1.1  christos 	ifp = NULL;
   1127       1.1  christos 
   1128       1.1  christos # if defined(M_CSUM_IPv4)
   1129       1.1  christos 	/*
   1130       1.1  christos 	 * Clear any in-bound checksum flags for this packet.
   1131       1.1  christos 	 */
   1132       1.1  christos 	m0->m_pkthdr.csuminfo = 0;
   1133       1.1  christos # endif /* __NetBSD__ && M_CSUM_IPv4 */
   1134       1.1  christos 
   1135       1.1  christos 	/*
   1136       1.1  christos 	 * Route packet.
   1137       1.1  christos 	 */
   1138       1.1  christos 	ro = &iproute;
   1139       1.2  christos 	memset(ro, 0, sizeof(*ro));
   1140       1.1  christos 	fr = fin->fin_fr;
   1141       1.1  christos 
   1142       1.1  christos 	if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
   1143       1.1  christos 	    (fdp->fd_type == FRD_DSTLIST)) {
   1144       1.1  christos 		if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
   1145       1.1  christos 			fdp = &node;
   1146       1.1  christos 	}
   1147       1.1  christos 	if (fdp != NULL)
   1148       1.1  christos 		ifp = fdp->fd_ptr;
   1149       1.1  christos 	else
   1150       1.1  christos 		ifp = fin->fin_ifp;
   1151       1.1  christos 
   1152       1.1  christos 	if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
   1153       1.1  christos 		error = -2;
   1154       1.1  christos 		goto bad;
   1155       1.1  christos 	}
   1156       1.1  christos 
   1157       1.1  christos # if __NetBSD_Version__ >= 499001100
   1158       1.1  christos 	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
   1159       1.1  christos 		sockaddr_in_init(&u.dst4, &fdp->fd_ip, 0);
   1160       1.1  christos 	else
   1161       1.1  christos 		sockaddr_in_init(&u.dst4, &ip->ip_dst, 0);
   1162       1.1  christos 	dst = &u.dst;
   1163       1.1  christos 	rtcache_setdst(ro, dst);
   1164       1.1  christos 	rt = rtcache_init(ro);
   1165       1.1  christos # else
   1166       1.1  christos 	dst4 = (struct sockaddr_in *)&ro->ro_dst;
   1167       1.1  christos 	dst = (struct sockaddr *)dst4;
   1168       1.1  christos 	dst4->sin_family = AF_INET;
   1169       1.1  christos 	dst4->sin_addr = ip->ip_dst;
   1170       1.1  christos 
   1171       1.1  christos 	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
   1172       1.1  christos 		dst4->sin_addr = fdp->fd_ip;
   1173       1.1  christos 
   1174       1.1  christos 	dst4->sin_len = sizeof(*dst);
   1175       1.1  christos 	rtalloc(ro);
   1176       1.1  christos 	rt = ro->ro_rt;
   1177       1.1  christos # endif
   1178       1.1  christos 	if ((ifp == NULL) && (rt != NULL))
   1179       1.1  christos 		ifp = rt->rt_ifp;
   1180       1.1  christos 	if ((rt == NULL) || (ifp == NULL)) {
   1181       1.2  christos #ifdef INET
   1182       1.1  christos 		if (in_localaddr(ip->ip_dst))
   1183       1.1  christos 			error = EHOSTUNREACH;
   1184       1.1  christos 		else
   1185       1.2  christos #endif
   1186       1.1  christos 			error = ENETUNREACH;
   1187       1.1  christos 		goto bad;
   1188       1.1  christos 	}
   1189       1.1  christos 
   1190       1.1  christos 
   1191       1.1  christos 	if (rt->rt_flags & RTF_GATEWAY)
   1192       1.1  christos 		dst = rt->rt_gateway;
   1193       1.1  christos 
   1194       1.1  christos 	rt->rt_use++;
   1195       1.1  christos 
   1196       1.1  christos 	/*
   1197       1.1  christos 	 * For input packets which are being "fastrouted", they won't
   1198       1.1  christos 	 * go back through output filtering and miss their chance to get
   1199       1.1  christos 	 * NAT'd and counted.  Duplicated packets aren't considered to be
   1200       1.1  christos 	 * part of the normal packet stream, so do not NAT them or pass
   1201       1.1  christos 	 * them through stateful checking, etc.
   1202       1.1  christos 	 */
   1203       1.1  christos 	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
   1204       1.1  christos 		sifp = fin->fin_ifp;
   1205       1.1  christos 		fin->fin_ifp = ifp;
   1206       1.1  christos 		fin->fin_out = 1;
   1207       1.1  christos 		(void) ipf_acctpkt(fin, NULL);
   1208       1.1  christos 		fin->fin_fr = NULL;
   1209       1.1  christos 		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
   1210       1.1  christos 			u_32_t pass;
   1211       1.1  christos 
   1212       1.1  christos 			(void) ipf_state_check(fin, &pass);
   1213       1.1  christos 		}
   1214       1.1  christos 
   1215       1.1  christos 		switch (ipf_nat_checkout(fin, NULL))
   1216       1.1  christos 		{
   1217       1.1  christos 		case 0 :
   1218       1.1  christos 			break;
   1219       1.1  christos 		case 1 :
   1220       1.1  christos 			ip->ip_sum = 0;
   1221       1.1  christos 			break;
   1222       1.1  christos 		case -1 :
   1223       1.1  christos 			error = -1;
   1224       1.1  christos 			goto bad;
   1225       1.1  christos 			break;
   1226       1.1  christos 		}
   1227       1.1  christos 
   1228       1.1  christos 		fin->fin_ifp = sifp;
   1229       1.1  christos 		fin->fin_out = 0;
   1230       1.1  christos 	} else
   1231       1.1  christos 		ip->ip_sum = 0;
   1232       1.1  christos 	/*
   1233       1.1  christos 	 * If small enough for interface, can just send directly.
   1234       1.1  christos 	 */
   1235      1.14     ozaki 	m_set_rcvif(m, ifp);
   1236       1.1  christos 
   1237       1.1  christos 	ip_len = ntohs(ip->ip_len);
   1238       1.1  christos 	if (ip_len <= ifp->if_mtu) {
   1239       1.1  christos # if defined(M_CSUM_IPv4)
   1240       1.1  christos #  if (__NetBSD_Version__ >= 105009999)
   1241       1.1  christos 		if (ifp->if_csum_flags_tx & M_CSUM_IPv4)
   1242       1.1  christos 			m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
   1243       1.1  christos #  else
   1244       1.1  christos 		if (ifp->if_capabilities & IFCAP_CSUM_IPv4)
   1245       1.1  christos 			m->m_pkthdr.csuminfo |= M_CSUM_IPv4;
   1246       1.1  christos #  endif /* (__NetBSD_Version__ >= 105009999) */
   1247       1.1  christos 		else if (ip->ip_sum == 0)
   1248       1.1  christos 			ip->ip_sum = in_cksum(m, hlen);
   1249       1.1  christos # else
   1250       1.1  christos 		if (!ip->ip_sum)
   1251       1.1  christos 			ip->ip_sum = in_cksum(m, hlen);
   1252       1.1  christos # endif /* M_CSUM_IPv4 */
   1253       1.1  christos 
   1254      1.15  knakahar 		error = if_output_lock(ifp, ifp, m, dst, rt);
   1255       1.1  christos 		goto done;
   1256       1.1  christos 	}
   1257       1.1  christos 
   1258       1.1  christos 	/*
   1259       1.1  christos 	 * Too large for interface; fragment if possible.
   1260       1.1  christos 	 * Must be able to put at least 8 bytes per fragment.
   1261       1.1  christos 	 */
   1262       1.1  christos 	ip_off = ntohs(ip->ip_off);
   1263       1.1  christos 	if (ip_off & IP_DF) {
   1264       1.1  christos 		error = EMSGSIZE;
   1265       1.1  christos 		goto bad;
   1266       1.1  christos 	}
   1267       1.1  christos 	len = (ifp->if_mtu - hlen) &~ 7;
   1268       1.1  christos 	if (len < 8) {
   1269       1.1  christos 		error = EMSGSIZE;
   1270       1.1  christos 		goto bad;
   1271       1.1  christos 	}
   1272       1.1  christos 
   1273       1.1  christos     {
   1274       1.1  christos 	int mhlen, firstlen = len;
   1275       1.1  christos 	struct mbuf **mnext = &m->m_act;
   1276       1.1  christos 
   1277       1.1  christos 	/*
   1278       1.1  christos 	 * Loop through length of segment after first fragment,
   1279       1.1  christos 	 * make new header and copy data of each part and link onto chain.
   1280       1.1  christos 	 */
   1281       1.1  christos 	m0 = m;
   1282       1.1  christos 	mhlen = sizeof (struct ip);
   1283       1.1  christos 	for (off = hlen + len; off < ip_len; off += len) {
   1284       1.1  christos # ifdef MGETHDR
   1285       1.1  christos 		MGETHDR(m, M_DONTWAIT, MT_HEADER);
   1286       1.1  christos # else
   1287       1.1  christos 		MGET(m, M_DONTWAIT, MT_HEADER);
   1288       1.1  christos # endif
   1289       1.1  christos 		if (m == 0) {
   1290       1.1  christos 			m = m0;
   1291       1.1  christos 			error = ENOBUFS;
   1292       1.1  christos 			goto bad;
   1293       1.1  christos 		}
   1294       1.1  christos 		m->m_data += max_linkhdr;
   1295       1.1  christos 		mhip = mtod(m, struct ip *);
   1296       1.1  christos 		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
   1297       1.2  christos #ifdef INET
   1298       1.1  christos 		if (hlen > sizeof (struct ip)) {
   1299       1.1  christos 			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
   1300       1.1  christos 			IP_HL_A(mhip, mhlen >> 2);
   1301       1.1  christos 		}
   1302       1.2  christos #endif
   1303       1.1  christos 		m->m_len = mhlen;
   1304       1.1  christos 		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
   1305       1.1  christos 		if (off + len >= ip_len)
   1306       1.1  christos 			len = ip_len - off;
   1307       1.1  christos 		else
   1308       1.1  christos 			mhip->ip_off |= IP_MF;
   1309       1.1  christos 		mhip->ip_len = htons((u_short)(len + mhlen));
   1310       1.1  christos 		m->m_next = m_copy(m0, off, len);
   1311       1.1  christos 		if (m->m_next == 0) {
   1312       1.1  christos 			error = ENOBUFS;	/* ??? */
   1313       1.1  christos 			goto sendorfree;
   1314       1.1  christos 		}
   1315       1.1  christos 		m->m_pkthdr.len = mhlen + len;
   1316      1.14     ozaki 		m_reset_rcvif(m);
   1317       1.1  christos 		mhip->ip_off = htons((u_short)mhip->ip_off);
   1318       1.1  christos 		mhip->ip_sum = 0;
   1319       1.2  christos #ifdef INET
   1320       1.1  christos 		mhip->ip_sum = in_cksum(m, mhlen);
   1321       1.2  christos #endif
   1322       1.1  christos 		*mnext = m;
   1323       1.1  christos 		mnext = &m->m_act;
   1324       1.1  christos 	}
   1325       1.1  christos 	/*
   1326       1.1  christos 	 * Update first fragment by trimming what's been copied out
   1327       1.1  christos 	 * and updating header, then send each fragment (in order).
   1328       1.1  christos 	 */
   1329       1.1  christos 	m_adj(m0, hlen + firstlen - ip_len);
   1330       1.1  christos 	ip->ip_len = htons((u_short)(hlen + firstlen));
   1331       1.1  christos 	ip->ip_off = htons((u_short)IP_MF);
   1332       1.1  christos 	ip->ip_sum = 0;
   1333       1.2  christos #ifdef INET
   1334       1.1  christos 	ip->ip_sum = in_cksum(m0, hlen);
   1335       1.2  christos #endif
   1336       1.1  christos sendorfree:
   1337       1.1  christos 	for (m = m0; m; m = m0) {
   1338       1.1  christos 		m0 = m->m_act;
   1339       1.1  christos 		m->m_act = 0;
   1340       1.1  christos 		if (error == 0) {
   1341       1.9    bouyer 			KERNEL_LOCK(1, NULL);
   1342       1.1  christos 			error = (*ifp->if_output)(ifp, m, dst, rt);
   1343       1.9    bouyer 			KERNEL_UNLOCK_ONE(NULL);
   1344       1.1  christos 		} else {
   1345       1.1  christos 			FREE_MB_T(m);
   1346       1.1  christos 		}
   1347       1.1  christos 	}
   1348       1.1  christos     }
   1349       1.1  christos done:
   1350       1.1  christos 	if (!error)
   1351       1.1  christos 		softc->ipf_frouteok[0]++;
   1352       1.1  christos 	else
   1353       1.1  christos 		softc->ipf_frouteok[1]++;
   1354       1.1  christos 
   1355       1.1  christos # if __NetBSD_Version__ >= 499001100
   1356      1.19     ozaki 	rtcache_unref(rt, ro);
   1357       1.1  christos 	rtcache_free(ro);
   1358       1.1  christos # else
   1359       1.1  christos 	if (rt) {
   1360       1.1  christos 		RTFREE(rt);
   1361       1.1  christos 	}
   1362       1.1  christos # endif
   1363       1.1  christos 	return error;
   1364       1.1  christos bad:
   1365       1.1  christos 	if (error == EMSGSIZE) {
   1366       1.1  christos 		sifp = fin->fin_ifp;
   1367       1.1  christos 		code = fin->fin_icode;
   1368       1.1  christos 		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
   1369       1.1  christos 		fin->fin_ifp = ifp;
   1370       1.1  christos 		(void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
   1371       1.1  christos 		fin->fin_ifp = sifp;
   1372       1.1  christos 		fin->fin_icode = code;
   1373       1.1  christos 	}
   1374       1.1  christos 	FREE_MB_T(m);
   1375       1.1  christos 	goto done;
   1376       1.1  christos #endif /* INET */
   1377       1.1  christos }
   1378       1.1  christos 
   1379       1.1  christos 
   1380       1.1  christos #if defined(USE_INET6)
   1381       1.1  christos /*
   1382       1.1  christos  * This is the IPv6 specific fastroute code.  It doesn't clean up the mbuf's
   1383       1.1  christos  * or ensure that it is an IPv6 packet that is being forwarded, those are
   1384       1.1  christos  * expected to be done by the called (ipf_fastroute).
   1385       1.1  christos  */
   1386       1.1  christos static int
   1387       1.2  christos ipf_fastroute6(struct mbuf *m0, struct mbuf **mpp, fr_info_t *fin,
   1388       1.2  christos     frdest_t *fdp)
   1389       1.1  christos {
   1390       1.1  christos # if __NetBSD_Version__ >= 499001100
   1391       1.1  christos 	struct route ip6route;
   1392       1.1  christos 	const struct sockaddr *dst;
   1393       1.1  christos 	union {
   1394       1.1  christos 		struct sockaddr         dst;
   1395       1.1  christos 		struct sockaddr_in6     dst6;
   1396       1.1  christos 	} u;
   1397       1.1  christos 	struct route *ro;
   1398       1.1  christos # else
   1399       1.1  christos 	struct route_in6 ip6route;
   1400       1.1  christos 	struct sockaddr_in6 *dst6;
   1401       1.1  christos 	struct route_in6 *ro;
   1402       1.1  christos # endif
   1403       1.1  christos 	struct rtentry *rt;
   1404       1.1  christos 	struct ifnet *ifp;
   1405       1.1  christos 	u_long mtu;
   1406       1.1  christos 	int error;
   1407       1.1  christos 
   1408       1.1  christos 	error = 0;
   1409       1.1  christos 	ro = &ip6route;
   1410       1.1  christos 
   1411       1.1  christos 	if (fdp != NULL)
   1412       1.1  christos 		ifp = fdp->fd_ptr;
   1413       1.1  christos 	else
   1414       1.1  christos 		ifp = fin->fin_ifp;
   1415       1.2  christos 	memset(ro, 0, sizeof(*ro));
   1416       1.1  christos # if __NetBSD_Version__ >= 499001100
   1417       1.1  christos 	if (fdp != NULL && IP6_NOTZERO(&fdp->fd_ip6))
   1418       1.1  christos 		sockaddr_in6_init(&u.dst6, &fdp->fd_ip6.in6, 0, 0, 0);
   1419       1.1  christos 	else
   1420       1.1  christos 		sockaddr_in6_init(&u.dst6, &fin->fin_fi.fi_dst.in6, 0, 0, 0);
   1421       1.1  christos 	dst = &u.dst;
   1422       1.1  christos 	rtcache_setdst(ro, dst);
   1423       1.1  christos 
   1424       1.1  christos 	rt = rtcache_init(ro);
   1425       1.1  christos 	if ((ifp == NULL) && (rt != NULL))
   1426       1.1  christos 		ifp = rt->rt_ifp;
   1427       1.1  christos # else
   1428       1.1  christos 	dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
   1429       1.1  christos 	dst6->sin6_family = AF_INET6;
   1430       1.1  christos 	dst6->sin6_len = sizeof(struct sockaddr_in6);
   1431       1.1  christos 	dst6->sin6_addr = fin->fin_fi.fi_dst.in6;
   1432       1.1  christos 
   1433       1.1  christos 	if (fdp != NULL) {
   1434       1.1  christos 		if (IP6_NOTZERO(&fdp->fd_ip6))
   1435       1.1  christos 			dst6->sin6_addr = fdp->fd_ip6.in6;
   1436       1.1  christos 	}
   1437       1.1  christos 
   1438       1.1  christos 	rtalloc((struct route *)ro);
   1439       1.1  christos 
   1440       1.1  christos 	if ((ifp == NULL) && (ro->ro_rt != NULL))
   1441       1.1  christos 		ifp = ro->ro_rt->rt_ifp;
   1442       1.1  christos 	rt = ro->ro_rt;
   1443       1.1  christos # endif
   1444       1.1  christos 	if ((rt == NULL) || (ifp == NULL)) {
   1445       1.1  christos 
   1446       1.1  christos 		error = EHOSTUNREACH;
   1447       1.1  christos 		goto bad;
   1448       1.1  christos 	}
   1449       1.1  christos 
   1450       1.1  christos 	/* KAME */
   1451       1.1  christos # if __NetBSD_Version__ >= 499001100
   1452       1.1  christos 	if (IN6_IS_ADDR_LINKLOCAL(&u.dst6.sin6_addr))
   1453       1.1  christos 		u.dst6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
   1454       1.1  christos # else
   1455       1.1  christos 	if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr))
   1456       1.1  christos 		dst6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
   1457       1.1  christos # endif
   1458       1.1  christos 
   1459       1.1  christos 	{
   1460       1.6    martin # if (__NetBSD_Version__ >= 106010000) && !defined(IN6_LINKMTU)
   1461       1.1  christos 		struct in6_ifextra *ife;
   1462       1.1  christos # endif
   1463       1.1  christos 		if (rt->rt_flags & RTF_GATEWAY)
   1464       1.1  christos # if __NetBSD_Version__ >= 499001100
   1465       1.1  christos 			dst = rt->rt_gateway;
   1466       1.1  christos # else
   1467       1.1  christos 			dst6 = (struct sockaddr_in6 *)rt->rt_gateway;
   1468       1.1  christos # endif
   1469       1.1  christos 		rt->rt_use++;
   1470       1.1  christos 
   1471       1.1  christos 		/* Determine path MTU. */
   1472       1.1  christos # if (__NetBSD_Version__ <= 106009999)
   1473       1.1  christos 		mtu = nd_ifinfo[ifp->if_index].linkmtu;
   1474       1.1  christos # else
   1475       1.1  christos #  ifdef IN6_LINKMTU
   1476       1.1  christos 		mtu = IN6_LINKMTU(ifp);
   1477       1.1  christos #  else
   1478       1.6    martin 		ife = (struct in6_ifextra *)(ifp)->if_afdata[AF_INET6];
   1479       1.1  christos 		mtu = ife->nd_ifinfo[ifp->if_index].linkmtu;
   1480       1.1  christos #  endif
   1481       1.1  christos # endif
   1482       1.1  christos 		if ((error == 0) && (m0->m_pkthdr.len <= mtu)) {
   1483       1.1  christos # if __NetBSD_Version__ >= 499001100
   1484      1.22     ozaki 			error = ip6_if_output(ifp, ifp, m0, satocsin6(dst), rt);
   1485       1.1  christos # else
   1486       1.2  christos 			error = nd6_output(ifp, ifp, m0, dst6, rt);
   1487       1.1  christos # endif
   1488       1.1  christos 		} else {
   1489       1.1  christos 			error = EMSGSIZE;
   1490       1.1  christos 		}
   1491       1.1  christos 	}
   1492       1.1  christos bad:
   1493       1.1  christos # if __NetBSD_Version__ >= 499001100
   1494      1.19     ozaki 	rtcache_unref(rt, ro);
   1495       1.1  christos 	rtcache_free(ro);
   1496       1.1  christos # else
   1497       1.1  christos 	if (ro->ro_rt != NULL) {
   1498       1.1  christos 		RTFREE(((struct route *)ro)->ro_rt);
   1499       1.1  christos 	}
   1500       1.1  christos # endif
   1501       1.1  christos 	return error;
   1502       1.1  christos }
   1503       1.1  christos #endif	/* INET6 */
   1504       1.1  christos 
   1505       1.1  christos 
   1506       1.1  christos int
   1507       1.2  christos ipf_verifysrc(fr_info_t *fin)
   1508       1.1  christos {
   1509       1.1  christos #if __NetBSD_Version__ >= 499001100
   1510       1.1  christos 	union {
   1511       1.1  christos 		struct sockaddr         dst;
   1512       1.1  christos 		struct sockaddr_in      dst4;
   1513       1.1  christos 	} u;
   1514       1.1  christos 	struct rtentry *rt;
   1515       1.1  christos #else
   1516       1.1  christos 	struct sockaddr_in *dst;
   1517       1.1  christos #endif
   1518       1.1  christos 	struct route iproute;
   1519       1.1  christos 	int rc;
   1520       1.1  christos 
   1521       1.1  christos #if __NetBSD_Version__ >= 499001100
   1522       1.1  christos 	sockaddr_in_init(&u.dst4, &fin->fin_src, 0);
   1523       1.1  christos 	rtcache_setdst(&iproute, &u.dst);
   1524       1.1  christos 	rt = rtcache_init(&iproute);
   1525       1.1  christos 	if (rt == NULL)
   1526       1.1  christos 		rc = 0;
   1527       1.1  christos 	else
   1528       1.1  christos 		rc = (fin->fin_ifp == rt->rt_ifp);
   1529      1.19     ozaki 	rtcache_unref(rt, &iproute);
   1530       1.1  christos 	rtcache_free(&iproute);
   1531       1.1  christos #else
   1532       1.1  christos 	dst = (struct sockaddr_in *)&iproute.ro_dst;
   1533       1.1  christos 	dst->sin_len = sizeof(*dst);
   1534       1.1  christos 	dst->sin_family = AF_INET;
   1535       1.1  christos 	dst->sin_addr = fin->fin_src;
   1536       1.1  christos 	rtalloc(&iproute);
   1537       1.1  christos 	if (iproute.ro_rt == NULL)
   1538       1.1  christos 		return 0;
   1539       1.1  christos 	rc = (fin->fin_ifp == iproute.ro_rt->rt_ifp);
   1540       1.1  christos 	RTFREE(iproute.ro_rt);
   1541       1.1  christos #endif
   1542       1.1  christos 	return rc;
   1543       1.1  christos }
   1544       1.1  christos 
   1545       1.1  christos 
   1546       1.1  christos /*
   1547       1.1  christos  * return the first IP Address associated with an interface
   1548       1.1  christos  */
   1549       1.1  christos int
   1550       1.2  christos ipf_ifpaddr(ipf_main_softc_t *softc, int v, int atype, void *ifptr,
   1551       1.2  christos     i6addr_t *inp, i6addr_t *inpmask)
   1552       1.1  christos {
   1553       1.1  christos #ifdef USE_INET6
   1554       1.1  christos 	struct in6_addr *inp6 = NULL;
   1555       1.1  christos #endif
   1556       1.1  christos 	struct sockaddr *sock, *mask;
   1557       1.1  christos 	struct sockaddr_in *sin;
   1558       1.1  christos 	struct ifaddr *ifa;
   1559       1.1  christos 	struct ifnet *ifp;
   1560       1.1  christos 
   1561       1.1  christos 	if ((ifptr == NULL) || (ifptr == (void *)-1))
   1562       1.1  christos 		return -1;
   1563       1.1  christos 
   1564       1.1  christos 	ifp = ifptr;
   1565       1.1  christos 	mask = NULL;
   1566       1.1  christos 
   1567       1.1  christos 	if (v == 4)
   1568       1.1  christos 		inp->in4.s_addr = 0;
   1569       1.1  christos #ifdef USE_INET6
   1570       1.1  christos 	else if (v == 6)
   1571       1.1  christos 		bzero((char *)inp, sizeof(*inp));
   1572       1.1  christos #endif
   1573       1.1  christos 
   1574      1.16     ozaki 	ifa = IFADDR_READER_FIRST(ifp);
   1575       1.2  christos 	sock = ifa ? ifa->ifa_addr : NULL;
   1576       1.1  christos 	while (sock != NULL && ifa != NULL) {
   1577       1.1  christos 		sin = (struct sockaddr_in *)sock;
   1578       1.1  christos 		if ((v == 4) && (sin->sin_family == AF_INET))
   1579       1.1  christos 			break;
   1580       1.1  christos #ifdef USE_INET6
   1581       1.1  christos 		if ((v == 6) && (sin->sin_family == AF_INET6)) {
   1582       1.1  christos 			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
   1583       1.1  christos 			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
   1584       1.1  christos 			    !IN6_IS_ADDR_LOOPBACK(inp6))
   1585       1.1  christos 				break;
   1586       1.1  christos 		}
   1587       1.1  christos #endif
   1588      1.16     ozaki 		ifa = IFADDR_READER_NEXT(ifa);
   1589       1.1  christos 		if (ifa != NULL)
   1590       1.1  christos 			sock = ifa->ifa_addr;
   1591       1.1  christos 	}
   1592       1.1  christos 	if (ifa == NULL || sock == NULL)
   1593       1.1  christos 		return -1;
   1594       1.1  christos 
   1595       1.1  christos 	mask = ifa->ifa_netmask;
   1596       1.1  christos 	if (atype == FRI_BROADCAST)
   1597       1.1  christos 		sock = ifa->ifa_broadaddr;
   1598       1.1  christos 	else if (atype == FRI_PEERADDR)
   1599       1.1  christos 		sock = ifa->ifa_dstaddr;
   1600       1.1  christos 
   1601       1.1  christos #ifdef USE_INET6
   1602       1.1  christos 	if (v == 6)
   1603       1.1  christos 		return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
   1604       1.1  christos 					(struct sockaddr_in6 *)mask,
   1605       1.1  christos 					inp, inpmask);
   1606       1.1  christos #endif
   1607       1.1  christos 	return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
   1608       1.1  christos 				(struct sockaddr_in *)mask,
   1609       1.1  christos 				&inp->in4, &inpmask->in4);
   1610       1.1  christos }
   1611       1.1  christos 
   1612       1.1  christos 
   1613       1.1  christos u_32_t
   1614       1.2  christos ipf_newisn(fr_info_t *fin)
   1615       1.1  christos {
   1616       1.1  christos #if __NetBSD_Version__ >= 105190000	/* 1.5T */
   1617       1.1  christos 	size_t asz;
   1618       1.1  christos 
   1619       1.1  christos 	if (fin->fin_v == 4)
   1620       1.1  christos 		asz = sizeof(struct in_addr);
   1621       1.1  christos 	else if (fin->fin_v == 6)
   1622       1.1  christos 		asz = sizeof(fin->fin_src);
   1623       1.1  christos 	else	/* XXX: no way to return error */
   1624       1.1  christos 		return 0;
   1625       1.2  christos #ifdef INET
   1626       1.1  christos 	return tcp_new_iss1((void *)&fin->fin_src, (void *)&fin->fin_dst,
   1627       1.1  christos 			    fin->fin_sport, fin->fin_dport, asz, 0);
   1628       1.1  christos #else
   1629       1.2  christos 	return ENOSYS;
   1630       1.2  christos #endif
   1631       1.2  christos #else
   1632       1.1  christos 	static int iss_seq_off = 0;
   1633       1.1  christos 	u_char hash[16];
   1634       1.1  christos 	u_32_t newiss;
   1635       1.1  christos 	MD5_CTX ctx;
   1636       1.1  christos 
   1637       1.1  christos 	/*
   1638       1.1  christos 	 * Compute the base value of the ISS.  It is a hash
   1639       1.1  christos 	 * of (saddr, sport, daddr, dport, secret).
   1640       1.1  christos 	 */
   1641       1.1  christos 	MD5Init(&ctx);
   1642       1.1  christos 
   1643       1.1  christos 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
   1644       1.1  christos 		  sizeof(fin->fin_fi.fi_src));
   1645       1.1  christos 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
   1646       1.1  christos 		  sizeof(fin->fin_fi.fi_dst));
   1647       1.1  christos 	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
   1648       1.1  christos 
   1649       1.1  christos 	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
   1650       1.1  christos 
   1651       1.1  christos 	MD5Final(hash, &ctx);
   1652       1.1  christos 
   1653       1.1  christos 	memcpy(&newiss, hash, sizeof(newiss));
   1654       1.1  christos 
   1655       1.1  christos 	/*
   1656       1.1  christos 	 * Now increment our "timer", and add it in to
   1657       1.1  christos 	 * the computed value.
   1658       1.1  christos 	 *
   1659       1.1  christos 	 * XXX Use `addin'?
   1660       1.1  christos 	 * XXX TCP_ISSINCR too large to use?
   1661       1.1  christos 	 */
   1662       1.1  christos 	iss_seq_off += 0x00010000;
   1663       1.1  christos 	newiss += iss_seq_off;
   1664       1.1  christos 	return newiss;
   1665       1.1  christos #endif
   1666       1.1  christos }
   1667       1.1  christos 
   1668       1.1  christos 
   1669       1.1  christos /* ------------------------------------------------------------------------ */
   1670       1.1  christos /* Function:    ipf_nextipid                                                 */
   1671       1.1  christos /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
   1672       1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
   1673       1.1  christos /*                                                                          */
   1674       1.1  christos /* Returns the next IPv4 ID to use for this packet.                         */
   1675       1.1  christos /* ------------------------------------------------------------------------ */
   1676       1.1  christos u_short
   1677       1.2  christos ipf_nextipid(fr_info_t *fin)
   1678       1.1  christos {
   1679       1.1  christos #ifdef USE_MUTEXES
   1680       1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
   1681       1.1  christos #endif
   1682       1.1  christos 	u_short id;
   1683       1.1  christos 
   1684       1.1  christos 	MUTEX_ENTER(&softc->ipf_rw);
   1685       1.1  christos 	id = ipid++;
   1686       1.1  christos 	MUTEX_EXIT(&softc->ipf_rw);
   1687       1.1  christos 
   1688       1.1  christos 	return id;
   1689       1.1  christos }
   1690       1.1  christos 
   1691       1.1  christos 
   1692       1.2  christos EXTERN_INLINE int
   1693       1.2  christos ipf_checkv4sum(fr_info_t *fin)
   1694       1.1  christos {
   1695       1.1  christos #ifdef M_CSUM_TCP_UDP_BAD
   1696       1.1  christos 	int manual, pflag, cflags, active;
   1697       1.1  christos 	mb_t *m;
   1698       1.1  christos 
   1699       1.1  christos 	if ((fin->fin_flx & FI_NOCKSUM) != 0)
   1700       1.1  christos 		return 0;
   1701       1.1  christos 
   1702       1.1  christos 	if ((fin->fin_flx & FI_SHORT) != 0)
   1703       1.1  christos 		return 1;
   1704       1.1  christos 
   1705       1.3   darrenr 	if (fin->fin_cksum != FI_CK_NEEDED)
   1706       1.3   darrenr 		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
   1707       1.1  christos 
   1708       1.1  christos 	manual = 0;
   1709       1.1  christos 	m = fin->fin_m;
   1710       1.1  christos 	if (m == NULL) {
   1711       1.1  christos 		manual = 1;
   1712       1.1  christos 		goto skipauto;
   1713       1.1  christos 	}
   1714       1.1  christos 
   1715       1.1  christos 	switch (fin->fin_p)
   1716       1.1  christos 	{
   1717       1.1  christos 	case IPPROTO_UDP :
   1718       1.1  christos 		pflag = M_CSUM_UDPv4;
   1719       1.1  christos 		break;
   1720       1.1  christos 	case IPPROTO_TCP :
   1721       1.1  christos 		pflag = M_CSUM_TCPv4;
   1722       1.1  christos 		break;
   1723       1.1  christos 	default :
   1724       1.1  christos 		pflag = 0;
   1725       1.1  christos 		manual = 1;
   1726       1.1  christos 		break;
   1727       1.1  christos 	}
   1728       1.1  christos 
   1729       1.1  christos 	active = ((struct ifnet *)fin->fin_ifp)->if_csum_flags_rx & pflag;
   1730       1.1  christos 	active |= M_CSUM_TCP_UDP_BAD | M_CSUM_DATA;
   1731       1.1  christos 	cflags = m->m_pkthdr.csum_flags & active;
   1732       1.1  christos 
   1733       1.1  christos 	if (pflag != 0) {
   1734       1.1  christos 		if (cflags == (pflag | M_CSUM_TCP_UDP_BAD)) {
   1735       1.1  christos 			fin->fin_flx |= FI_BAD;
   1736       1.3   darrenr 			fin->fin_cksum = FI_CK_BAD;
   1737       1.1  christos 		} else if (cflags == (pflag | M_CSUM_DATA)) {
   1738       1.1  christos 			if ((m->m_pkthdr.csum_data ^ 0xffff) != 0) {
   1739       1.1  christos 				fin->fin_flx |= FI_BAD;
   1740       1.3   darrenr 				fin->fin_cksum = FI_CK_BAD;
   1741       1.1  christos 			} else {
   1742       1.3   darrenr 				fin->fin_cksum = FI_CK_SUMOK;
   1743       1.1  christos 			}
   1744       1.1  christos 		} else if (cflags == pflag) {
   1745       1.3   darrenr 			fin->fin_cksum = FI_CK_SUMOK;
   1746       1.1  christos 		} else {
   1747       1.1  christos 			manual = 1;
   1748       1.1  christos 		}
   1749       1.1  christos 	}
   1750       1.1  christos skipauto:
   1751       1.1  christos 	if (manual != 0) {
   1752       1.1  christos 		if (ipf_checkl4sum(fin) == -1) {
   1753       1.1  christos 			fin->fin_flx |= FI_BAD;
   1754       1.1  christos 			return -1;
   1755       1.1  christos 		}
   1756       1.1  christos 	}
   1757       1.1  christos #else
   1758       1.1  christos 	if (ipf_checkl4sum(fin) == -1) {
   1759       1.1  christos 		fin->fin_flx |= FI_BAD;
   1760       1.1  christos 		return -1;
   1761       1.1  christos 	}
   1762       1.1  christos #endif
   1763       1.1  christos 	return 0;
   1764       1.1  christos }
   1765       1.1  christos 
   1766       1.1  christos 
   1767       1.1  christos #ifdef USE_INET6
   1768       1.2  christos EXTERN_INLINE int
   1769       1.2  christos ipf_checkv6sum(fr_info_t *fin)
   1770       1.1  christos {
   1771       1.1  christos # ifdef M_CSUM_TCP_UDP_BAD
   1772       1.1  christos 	int manual, pflag, cflags, active;
   1773       1.1  christos 	mb_t *m;
   1774       1.1  christos 
   1775       1.1  christos 	if ((fin->fin_flx & FI_NOCKSUM) != 0)
   1776       1.1  christos 		return 0;
   1777       1.1  christos 
   1778       1.1  christos 	if ((fin->fin_flx & FI_SHORT) != 0)
   1779       1.1  christos 		return 1;
   1780       1.1  christos 
   1781       1.3   darrenr 	if (fin->fin_cksum != FI_CK_SUMOK)
   1782       1.3   darrenr 		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
   1783       1.1  christos 
   1784       1.1  christos 
   1785       1.1  christos 	manual = 0;
   1786       1.1  christos 	m = fin->fin_m;
   1787       1.1  christos 
   1788       1.1  christos 	switch (fin->fin_p)
   1789       1.1  christos 	{
   1790       1.1  christos 	case IPPROTO_UDP :
   1791       1.1  christos 		pflag = M_CSUM_UDPv6;
   1792       1.1  christos 		break;
   1793       1.1  christos 	case IPPROTO_TCP :
   1794       1.1  christos 		pflag = M_CSUM_TCPv6;
   1795       1.1  christos 		break;
   1796       1.1  christos 	default :
   1797       1.1  christos 		pflag = 0;
   1798       1.1  christos 		manual = 1;
   1799       1.1  christos 		break;
   1800       1.1  christos 	}
   1801       1.1  christos 
   1802       1.1  christos 	active = ((struct ifnet *)fin->fin_ifp)->if_csum_flags_rx & pflag;
   1803       1.1  christos 	active |= M_CSUM_TCP_UDP_BAD | M_CSUM_DATA;
   1804       1.1  christos 	cflags = m->m_pkthdr.csum_flags & active;
   1805       1.1  christos 
   1806       1.1  christos 	if (pflag != 0) {
   1807       1.1  christos 		if (cflags == (pflag | M_CSUM_TCP_UDP_BAD)) {
   1808       1.1  christos 			fin->fin_flx |= FI_BAD;
   1809       1.1  christos 		} else if (cflags == (pflag | M_CSUM_DATA)) {
   1810       1.1  christos 			if ((m->m_pkthdr.csum_data ^ 0xffff) != 0)
   1811       1.1  christos 				fin->fin_flx |= FI_BAD;
   1812       1.1  christos 		} else if (cflags == pflag) {
   1813       1.1  christos 			;
   1814       1.1  christos 		} else {
   1815       1.1  christos 			manual = 1;
   1816       1.1  christos 		}
   1817       1.1  christos 	}
   1818       1.1  christos 	if (manual != 0) {
   1819       1.1  christos 		if (ipf_checkl4sum(fin) == -1) {
   1820       1.1  christos 			fin->fin_flx |= FI_BAD;
   1821       1.1  christos 			return -1;
   1822       1.1  christos 		}
   1823       1.1  christos 	}
   1824       1.1  christos # else
   1825       1.1  christos 	if (ipf_checkl4sum(fin) == -1) {
   1826       1.1  christos 		fin->fin_flx |= FI_BAD;
   1827       1.1  christos 		return -1;
   1828       1.1  christos 	}
   1829       1.1  christos # endif
   1830       1.1  christos 	return 0;
   1831       1.1  christos }
   1832       1.1  christos #endif /* USE_INET6 */
   1833       1.1  christos 
   1834       1.1  christos 
   1835       1.1  christos size_t
   1836       1.2  christos mbufchainlen(struct mbuf *m0)
   1837       1.1  christos {
   1838       1.1  christos 	size_t len;
   1839       1.1  christos 
   1840       1.1  christos 	if ((m0->m_flags & M_PKTHDR) != 0) {
   1841       1.1  christos 		len = m0->m_pkthdr.len;
   1842       1.1  christos 	} else {
   1843       1.1  christos 		struct mbuf *m;
   1844       1.1  christos 
   1845       1.1  christos 		for (m = m0, len = 0; m != NULL; m = m->m_next)
   1846       1.1  christos 			len += m->m_len;
   1847       1.1  christos 	}
   1848       1.1  christos 	return len;
   1849       1.1  christos }
   1850       1.1  christos 
   1851       1.1  christos 
   1852       1.1  christos /* ------------------------------------------------------------------------ */
   1853       1.1  christos /* Function:    ipf_pullup                                                  */
   1854       1.1  christos /* Returns:     NULL == pullup failed, else pointer to protocol header      */
   1855       1.1  christos /* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
   1856       1.1  christos /*              fin(I) - pointer to packet information                      */
   1857       1.1  christos /*              len(I) - number of bytes to pullup                          */
   1858       1.1  christos /*                                                                          */
   1859       1.1  christos /* Attempt to move at least len bytes (from the start of the buffer) into a */
   1860       1.1  christos /* single buffer for ease of access.  Operating system native functions are */
   1861       1.1  christos /* used to manage buffers - if necessary.  If the entire packet ends up in  */
   1862       1.1  christos /* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
   1863       1.1  christos /* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
   1864       1.1  christos /* and ONLY if the pullup succeeds.                                         */
   1865       1.1  christos /*                                                                          */
   1866       1.1  christos /* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
   1867       1.1  christos /* of buffers that starts at *fin->fin_mp.                                  */
   1868       1.1  christos /* ------------------------------------------------------------------------ */
   1869       1.1  christos void *
   1870       1.2  christos ipf_pullup(mb_t *xmin, fr_info_t *fin, int len)
   1871       1.1  christos {
   1872       1.1  christos 	int dpoff, ipoff;
   1873       1.1  christos 	mb_t *m = xmin;
   1874       1.1  christos 	char *ip;
   1875       1.1  christos 
   1876       1.1  christos 	if (m == NULL)
   1877       1.1  christos 		return NULL;
   1878       1.1  christos 
   1879       1.1  christos 	ip = (char *)fin->fin_ip;
   1880       1.1  christos 	if ((fin->fin_flx & FI_COALESCE) != 0)
   1881       1.1  christos 		return ip;
   1882       1.1  christos 
   1883       1.1  christos 	ipoff = fin->fin_ipoff;
   1884       1.1  christos 	if (fin->fin_dp != NULL)
   1885       1.1  christos 		dpoff = (char *)fin->fin_dp - (char *)ip;
   1886       1.1  christos 	else
   1887       1.1  christos 		dpoff = 0;
   1888       1.1  christos 
   1889       1.1  christos 	if (M_LEN(m) < len) {
   1890       1.1  christos 		mb_t *n = *fin->fin_mp;
   1891       1.1  christos 		/*
   1892       1.1  christos 		 * Assume that M_PKTHDR is set and just work with what is left
   1893       1.1  christos 		 * rather than check..
   1894       1.1  christos 		 * Should not make any real difference, anyway.
   1895       1.1  christos 		 */
   1896       1.1  christos 		if (m != n) {
   1897       1.1  christos 			/*
   1898       1.1  christos 			 * Record the mbuf that points to the mbuf that we're
   1899       1.1  christos 			 * about to go to work on so that we can update the
   1900       1.1  christos 			 * m_next appropriately later.
   1901       1.1  christos 			 */
   1902       1.1  christos 			for (; n->m_next != m; n = n->m_next)
   1903       1.1  christos 				;
   1904       1.1  christos 		} else {
   1905       1.1  christos 			n = NULL;
   1906       1.1  christos 		}
   1907       1.1  christos 
   1908       1.1  christos #ifdef MHLEN
   1909       1.1  christos 		if (len > MHLEN)
   1910       1.1  christos #else
   1911       1.1  christos 		if (len > MLEN)
   1912       1.1  christos #endif
   1913       1.1  christos 		{
   1914       1.1  christos #ifdef HAVE_M_PULLDOWN
   1915       1.1  christos 			if (m_pulldown(m, 0, len, NULL) == NULL)
   1916       1.1  christos 				m = NULL;
   1917       1.1  christos #else
   1918       1.1  christos 			FREE_MB_T(*fin->fin_mp);
   1919       1.1  christos 			m = NULL;
   1920       1.1  christos 			n = NULL;
   1921       1.1  christos #endif
   1922       1.1  christos 		} else
   1923       1.1  christos 		{
   1924       1.1  christos 			m = m_pullup(m, len);
   1925       1.1  christos 		}
   1926       1.1  christos 		if (n != NULL)
   1927       1.1  christos 			n->m_next = m;
   1928       1.1  christos 		if (m == NULL) {
   1929       1.1  christos 			/*
   1930       1.1  christos 			 * When n is non-NULL, it indicates that m pointed to
   1931       1.1  christos 			 * a sub-chain (tail) of the mbuf and that the head
   1932       1.1  christos 			 * of this chain has not yet been free'd.
   1933       1.1  christos 			 */
   1934       1.1  christos 			if (n != NULL) {
   1935       1.1  christos 				FREE_MB_T(*fin->fin_mp);
   1936       1.1  christos 			}
   1937       1.1  christos 
   1938       1.1  christos 			*fin->fin_mp = NULL;
   1939       1.1  christos 			fin->fin_m = NULL;
   1940       1.1  christos 			return NULL;
   1941       1.1  christos 		}
   1942       1.1  christos 
   1943       1.1  christos 		if (n == NULL)
   1944       1.1  christos 			*fin->fin_mp = m;
   1945       1.1  christos 
   1946       1.1  christos 		while (M_LEN(m) == 0) {
   1947       1.1  christos 			m = m->m_next;
   1948       1.1  christos 		}
   1949       1.1  christos 		fin->fin_m = m;
   1950       1.1  christos 		ip = MTOD(m, char *) + ipoff;
   1951       1.1  christos 
   1952       1.1  christos 		fin->fin_ip = (ip_t *)ip;
   1953       1.1  christos 		if (fin->fin_dp != NULL)
   1954       1.1  christos 			fin->fin_dp = (char *)fin->fin_ip + dpoff;
   1955       1.3   darrenr 		if (fin->fin_fraghdr != NULL)
   1956       1.3   darrenr 			fin->fin_fraghdr = (char *)ip +
   1957       1.3   darrenr 					   ((char *)fin->fin_fraghdr -
   1958       1.3   darrenr 					    (char *)fin->fin_ip);
   1959       1.1  christos 	}
   1960       1.1  christos 
   1961       1.1  christos 	if (len == fin->fin_plen)
   1962       1.1  christos 		fin->fin_flx |= FI_COALESCE;
   1963       1.1  christos 	return ip;
   1964       1.1  christos }
   1965       1.1  christos 
   1966       1.1  christos 
   1967       1.1  christos int
   1968       1.2  christos ipf_inject(fr_info_t *fin, mb_t *m)
   1969       1.1  christos {
   1970       1.1  christos 	int error;
   1971       1.1  christos 
   1972       1.1  christos 	if (fin->fin_out == 0) {
   1973      1.10     rmind 		if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) {
   1974       1.1  christos 			FREE_MB_T(m);
   1975       1.1  christos 			error = ENOBUFS;
   1976       1.1  christos 		} else {
   1977       1.1  christos 			error = 0;
   1978       1.1  christos 		}
   1979       1.1  christos 	} else {
   1980      1.12  riastrad 		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
   1981       1.1  christos 	}
   1982       1.1  christos 	return error;
   1983       1.1  christos }
   1984       1.1  christos 
   1985       1.1  christos 
   1986       1.1  christos u_32_t
   1987       1.2  christos ipf_random(void)
   1988       1.1  christos {
   1989       1.1  christos 	int number;
   1990       1.1  christos 
   1991       1.1  christos #ifdef _CPRNG_H
   1992       1.1  christos 	number = cprng_fast32();
   1993       1.1  christos #else
   1994       1.1  christos 	number = arc4random();
   1995       1.1  christos #endif
   1996       1.1  christos 	return number;
   1997       1.1  christos }
   1998       1.1  christos 
   1999       1.1  christos 
   2000       1.1  christos /*
   2001       1.1  christos  * routines below for saving IP headers to buffer
   2002       1.1  christos  */
   2003       1.2  christos static int ipfopen(dev_t dev, int flags
   2004       1.1  christos #if (NetBSD >= 199511)
   2005       1.2  christos     , int devtype, PROC_T *p
   2006       1.2  christos #endif
   2007       1.1  christos )
   2008       1.1  christos {
   2009       1.1  christos 	u_int unit = GET_MINOR(dev);
   2010       1.1  christos 	int error;
   2011       1.1  christos 
   2012       1.1  christos 	if (IPL_LOGMAX < unit) {
   2013       1.1  christos 		error = ENXIO;
   2014       1.1  christos 	} else {
   2015       1.1  christos 		switch (unit)
   2016       1.1  christos 		{
   2017       1.1  christos 		case IPL_LOGIPF :
   2018       1.1  christos 		case IPL_LOGNAT :
   2019       1.1  christos 		case IPL_LOGSTATE :
   2020       1.1  christos 		case IPL_LOGAUTH :
   2021       1.1  christos 		case IPL_LOGLOOKUP :
   2022       1.1  christos 		case IPL_LOGSYNC :
   2023       1.1  christos #ifdef IPFILTER_SCAN
   2024       1.1  christos 		case IPL_LOGSCAN :
   2025       1.1  christos #endif
   2026       1.1  christos 			error = 0;
   2027       1.1  christos 			break;
   2028       1.1  christos 		default :
   2029       1.1  christos 			error = ENXIO;
   2030       1.1  christos 			break;
   2031       1.1  christos 		}
   2032       1.1  christos 	}
   2033      1.13  pgoyette #if (__NetBSD_Version__ >= 799003000)
   2034      1.13  pgoyette 	if (error == 0) {
   2035      1.13  pgoyette 		mutex_enter(&ipf_ref_mutex);
   2036      1.13  pgoyette 		ipf_active = 1;
   2037      1.13  pgoyette 		mutex_exit(&ipf_ref_mutex);
   2038      1.13  pgoyette 	}
   2039      1.13  pgoyette #endif
   2040       1.1  christos 	return error;
   2041       1.1  christos }
   2042       1.1  christos 
   2043       1.1  christos 
   2044       1.2  christos static int ipfclose(dev_t dev, int flags
   2045       1.1  christos #if (NetBSD >= 199511)
   2046       1.2  christos 	, int devtype, PROC_T *p
   2047       1.2  christos #endif
   2048       1.1  christos )
   2049       1.1  christos {
   2050       1.1  christos 	u_int	unit = GET_MINOR(dev);
   2051       1.1  christos 
   2052       1.1  christos 	if (IPL_LOGMAX < unit)
   2053      1.13  pgoyette 		return ENXIO;
   2054      1.13  pgoyette 	else {
   2055      1.13  pgoyette #if (__NetBSD_Version__ >= 799003000)
   2056      1.13  pgoyette 		mutex_enter(&ipf_ref_mutex);
   2057      1.13  pgoyette 		ipf_active = 0;
   2058      1.13  pgoyette 		mutex_exit(&ipf_ref_mutex);
   2059      1.13  pgoyette #endif
   2060      1.13  pgoyette 		return 0;
   2061      1.13  pgoyette 	}
   2062       1.1  christos }
   2063       1.1  christos 
   2064       1.1  christos /*
   2065       1.1  christos  * ipfread/ipflog
   2066       1.1  christos  * both of these must operate with at least splnet() lest they be
   2067       1.1  christos  * called during packet processing and cause an inconsistancy to appear in
   2068       1.1  christos  * the filter lists.
   2069       1.1  christos  */
   2070       1.2  christos static int ipfread(dev_t dev, struct uio *uio, int ioflag)
   2071       1.1  christos {
   2072       1.1  christos 
   2073       1.1  christos 	if (ipfmain.ipf_running < 1) {
   2074       1.1  christos 		ipfmain.ipf_interror = 130006;
   2075       1.1  christos 		return EIO;
   2076       1.1  christos 	}
   2077       1.1  christos 
   2078       1.1  christos 	if (GET_MINOR(dev) == IPL_LOGSYNC)
   2079       1.1  christos 		return ipf_sync_read(&ipfmain, uio);
   2080       1.1  christos 
   2081       1.1  christos #ifdef IPFILTER_LOG
   2082       1.1  christos 	return ipf_log_read(&ipfmain, GET_MINOR(dev), uio);
   2083       1.1  christos #else
   2084       1.1  christos 	ipfmain.ipf_interror = 130007;
   2085       1.1  christos 	return ENXIO;
   2086       1.1  christos #endif
   2087       1.1  christos }
   2088       1.1  christos 
   2089       1.1  christos 
   2090       1.1  christos /*
   2091       1.1  christos  * ipfwrite
   2092       1.1  christos  * both of these must operate with at least splnet() lest they be
   2093       1.1  christos  * called during packet processing and cause an inconsistancy to appear in
   2094       1.1  christos  * the filter lists.
   2095       1.1  christos  */
   2096       1.2  christos static int ipfwrite(dev_t dev, struct uio *uio, int ioflag)
   2097       1.1  christos {
   2098       1.1  christos 
   2099       1.1  christos 	if (ipfmain.ipf_running < 1) {
   2100       1.1  christos 		ipfmain.ipf_interror = 130008;
   2101       1.1  christos 		return EIO;
   2102       1.1  christos 	}
   2103       1.1  christos 
   2104       1.1  christos 	if (GET_MINOR(dev) == IPL_LOGSYNC)
   2105       1.1  christos 		return ipf_sync_write(&ipfmain, uio);
   2106       1.1  christos 	ipfmain.ipf_interror = 130009;
   2107       1.1  christos 	return ENXIO;
   2108       1.1  christos }
   2109       1.1  christos 
   2110       1.1  christos 
   2111       1.2  christos static int ipfpoll(dev_t dev, int events, PROC_T *p)
   2112       1.1  christos {
   2113       1.1  christos 	u_int unit = GET_MINOR(dev);
   2114       1.1  christos 	int revents = 0;
   2115       1.1  christos 
   2116       1.1  christos 	if (IPL_LOGMAX < unit) {
   2117       1.1  christos 		ipfmain.ipf_interror = 130010;
   2118       1.1  christos 		return ENXIO;
   2119       1.1  christos 	}
   2120       1.1  christos 
   2121       1.1  christos 	switch (unit)
   2122       1.1  christos 	{
   2123       1.1  christos 	case IPL_LOGIPF :
   2124       1.1  christos 	case IPL_LOGNAT :
   2125       1.1  christos 	case IPL_LOGSTATE :
   2126       1.1  christos #ifdef IPFILTER_LOG
   2127       1.1  christos 		if ((events & (POLLIN | POLLRDNORM)) &&
   2128       1.1  christos 		    ipf_log_canread(&ipfmain, unit))
   2129       1.1  christos 			revents |= events & (POLLIN | POLLRDNORM);
   2130       1.1  christos #endif
   2131       1.1  christos 		break;
   2132       1.1  christos 	case IPL_LOGAUTH :
   2133       1.1  christos 		if ((events & (POLLIN | POLLRDNORM)) &&
   2134       1.1  christos 		    ipf_auth_waiting(&ipfmain))
   2135       1.1  christos 			revents |= events & (POLLIN | POLLRDNORM);
   2136       1.1  christos 		break;
   2137       1.1  christos 	case IPL_LOGSYNC :
   2138       1.1  christos 		if ((events & (POLLIN | POLLRDNORM)) &&
   2139       1.1  christos 		    ipf_sync_canread(&ipfmain))
   2140       1.1  christos 			revents |= events & (POLLIN | POLLRDNORM);
   2141       1.1  christos 		if ((events & (POLLOUT | POLLWRNORM)) &&
   2142       1.1  christos 		    ipf_sync_canwrite(&ipfmain))
   2143       1.1  christos 			revents |= events & (POLLOUT | POLLWRNORM);
   2144       1.1  christos 		break;
   2145       1.1  christos 	case IPL_LOGSCAN :
   2146       1.1  christos 	case IPL_LOGLOOKUP :
   2147       1.1  christos 	default :
   2148       1.1  christos 		break;
   2149       1.1  christos 	}
   2150       1.1  christos 
   2151       1.1  christos 	if ((revents == 0) && (((events & (POLLIN|POLLRDNORM)) != 0)))
   2152       1.1  christos 		selrecord(p, &ipfmain.ipf_selwait[unit]);
   2153       1.1  christos 	return revents;
   2154       1.1  christos }
   2155       1.1  christos 
   2156       1.1  christos u_int
   2157       1.2  christos ipf_pcksum(fr_info_t *fin, int hlen, u_int sum)
   2158       1.1  christos {
   2159       1.1  christos 	struct mbuf *m;
   2160       1.1  christos 	u_int sum2;
   2161       1.1  christos 	int off;
   2162       1.1  christos 
   2163       1.1  christos 	m = fin->fin_m;
   2164       1.1  christos 	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
   2165       1.1  christos 	m->m_data += hlen;
   2166       1.1  christos 	m->m_len -= hlen;
   2167       1.1  christos 	sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
   2168       1.1  christos 	m->m_len += hlen;
   2169       1.1  christos 	m->m_data -= hlen;
   2170       1.1  christos 
   2171       1.1  christos 	/*
   2172       1.1  christos 	 * Both sum and sum2 are partial sums, so combine them together.
   2173       1.1  christos 	 */
   2174       1.1  christos 	sum += ~sum2 & 0xffff;
   2175       1.1  christos 	while (sum > 0xffff)
   2176       1.1  christos 		sum = (sum & 0xffff) + (sum >> 16);
   2177       1.1  christos 	sum2 = ~sum & 0xffff;
   2178       1.1  christos 	return sum2;
   2179       1.1  christos }
   2180      1.13  pgoyette 
   2181      1.13  pgoyette #if (__NetBSD_Version__ >= 799003000)
   2182      1.13  pgoyette 
   2183      1.13  pgoyette /* NetBSD module interface */
   2184      1.13  pgoyette 
   2185      1.13  pgoyette MODULE(MODULE_CLASS_DRIVER, ipl, "bpf_filter");
   2186      1.13  pgoyette 
   2187      1.13  pgoyette static int ipl_init(void *);
   2188      1.13  pgoyette static int ipl_fini(void *);
   2189      1.13  pgoyette static int ipl_modcmd(modcmd_t, void *);
   2190      1.13  pgoyette 
   2191      1.17  pgoyette #ifdef _MODULE
   2192      1.13  pgoyette static devmajor_t ipl_cmaj = -1, ipl_bmaj = -1;
   2193      1.17  pgoyette #endif
   2194      1.13  pgoyette 
   2195      1.13  pgoyette static int
   2196      1.13  pgoyette ipl_modcmd(modcmd_t cmd, void *opaque)
   2197      1.13  pgoyette {
   2198      1.13  pgoyette 
   2199      1.13  pgoyette 	switch (cmd) {
   2200      1.13  pgoyette 	case MODULE_CMD_INIT:
   2201      1.13  pgoyette 		return ipl_init(opaque);
   2202      1.13  pgoyette 	case MODULE_CMD_FINI:
   2203      1.13  pgoyette 		return ipl_fini(opaque);
   2204      1.13  pgoyette 	default:
   2205      1.13  pgoyette 		return ENOTTY;
   2206      1.13  pgoyette 	}
   2207      1.13  pgoyette }
   2208      1.13  pgoyette 
   2209      1.13  pgoyette static int
   2210      1.13  pgoyette ipl_init(void *opaque)
   2211      1.13  pgoyette {
   2212      1.13  pgoyette 	int error;
   2213      1.13  pgoyette 
   2214      1.13  pgoyette 	ipf_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
   2215      1.13  pgoyette 	    ipf_listener_cb, NULL);
   2216      1.13  pgoyette 
   2217      1.13  pgoyette 	if ((error = ipf_load_all()) != 0)
   2218      1.13  pgoyette 		return error;
   2219      1.13  pgoyette 
   2220      1.13  pgoyette 	if (ipf_create_all(&ipfmain) == NULL) {
   2221      1.13  pgoyette 		ipf_unload_all();
   2222      1.13  pgoyette 		return ENODEV;
   2223      1.13  pgoyette 	}
   2224      1.13  pgoyette 
   2225      1.13  pgoyette 	/* Initialize our mutex and reference count */
   2226      1.13  pgoyette 	mutex_init(&ipf_ref_mutex, MUTEX_DEFAULT, IPL_NONE);
   2227      1.13  pgoyette 	ipf_active = 0;
   2228      1.13  pgoyette 
   2229      1.17  pgoyette #ifdef _MODULE
   2230      1.13  pgoyette 	/*
   2231      1.18  pgoyette 	 * Insert ourself into the cdevsw list.
   2232      1.13  pgoyette 	 */
   2233      1.13  pgoyette 	error = devsw_attach("ipl", NULL, &ipl_bmaj, &ipl_cdevsw, &ipl_cmaj);
   2234      1.13  pgoyette 	if (error)
   2235      1.13  pgoyette 		ipl_fini(opaque);
   2236      1.18  pgoyette #endif
   2237      1.13  pgoyette 
   2238      1.13  pgoyette 	return error;
   2239      1.13  pgoyette }
   2240      1.13  pgoyette 
   2241      1.13  pgoyette static int
   2242      1.13  pgoyette ipl_fini(void *opaque)
   2243      1.13  pgoyette {
   2244      1.13  pgoyette 
   2245      1.17  pgoyette #ifdef _MODULE
   2246      1.13  pgoyette 	(void)devsw_detach(NULL, &ipl_cdevsw);
   2247      1.17  pgoyette #endif
   2248      1.13  pgoyette 
   2249      1.13  pgoyette 	/*
   2250      1.13  pgoyette 	 * Grab the mutex, verify that there are no references
   2251      1.13  pgoyette 	 * and that there are no running filters.  If either
   2252      1.13  pgoyette 	 * of these exists, reinsert our cdevsw entry and return
   2253      1.13  pgoyette 	 * an error.
   2254      1.13  pgoyette 	 */
   2255      1.13  pgoyette 	mutex_enter(&ipf_ref_mutex);
   2256      1.13  pgoyette 	if (ipf_active != 0 || ipfmain.ipf_running > 0) {
   2257      1.17  pgoyette #ifdef _MODULE
   2258      1.13  pgoyette 		(void)devsw_attach("ipl", NULL, &ipl_bmaj,
   2259      1.13  pgoyette 		    &ipl_cdevsw, &ipl_cmaj);
   2260      1.17  pgoyette #endif
   2261      1.13  pgoyette 		mutex_exit(&ipf_ref_mutex);
   2262      1.13  pgoyette 		return EBUSY;
   2263      1.13  pgoyette 	}
   2264      1.13  pgoyette 
   2265      1.13  pgoyette 	/* Clean up the rest of our state before being unloaded */
   2266      1.13  pgoyette 
   2267      1.13  pgoyette 	mutex_exit(&ipf_ref_mutex);
   2268      1.13  pgoyette 	mutex_destroy(&ipf_ref_mutex);
   2269      1.13  pgoyette 	ipf_destroy_all(&ipfmain);
   2270      1.13  pgoyette 	ipf_unload_all();
   2271      1.13  pgoyette 	kauth_unlisten_scope(ipf_listener);
   2272      1.13  pgoyette 
   2273      1.13  pgoyette 	return 0;
   2274      1.13  pgoyette }
   2275      1.13  pgoyette #endif /* (__NetBSD_Version__ >= 799003000) */
   2276