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