1145516Sdarrenr/* $FreeBSD: stable/11/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 369277 2021-02-16 00:48:38Z cy $ */ 2145516Sdarrenr 3145516Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145516Sdarrenr * 6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145516Sdarrenr */ 8145516Sdarrenr#if !defined(lint) 9145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10255332Scystatic const char rcsid[] = "@(#)$Id$"; 11145516Sdarrenr#endif 12145516Sdarrenr 13145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 14145516Sdarrenr# undef KERNEL 15145516Sdarrenr# undef _KERNEL 16145516Sdarrenr# define KERNEL 1 17145516Sdarrenr# define _KERNEL 1 18145516Sdarrenr#endif 19369277Scy#if defined(__FreeBSD__) && \ 20145516Sdarrenr !defined(KLD_MODULE) && !defined(IPFILTER_LKM) 21145516Sdarrenr# include "opt_inet6.h" 22145516Sdarrenr#endif 23145516Sdarrenr#include <sys/param.h> 24145516Sdarrenr#include <sys/errno.h> 25145516Sdarrenr#include <sys/types.h> 26145516Sdarrenr#include <sys/file.h> 27350577Scy#include <sys/fcntl.h> 28350577Scy#include <sys/filio.h> 29145516Sdarrenr#include <sys/time.h> 30145516Sdarrenr#include <sys/systm.h> 31369246Scy#include <sys/dirent.h> 32369277Scy#if defined(__FreeBSD__) 33369246Scy# include <sys/jail.h> 34274744Srodrigc#endif 35350577Scy#include <sys/malloc.h> 36350577Scy#include <sys/mbuf.h> 37350577Scy#include <sys/sockopt.h> 38145516Sdarrenr#include <sys/socket.h> 39350577Scy#include <sys/selinfo.h> 40350577Scy#include <netinet/tcp_var.h> 41145516Sdarrenr#include <net/if.h> 42350577Scy#include <net/if_var.h> 43350577Scy#include <net/netisr.h> 44145516Sdarrenr#include <net/route.h> 45145516Sdarrenr#include <netinet/in.h> 46293628Smelifaro#include <netinet/in_fib.h> 47145516Sdarrenr#include <netinet/in_var.h> 48145516Sdarrenr#include <netinet/in_systm.h> 49145516Sdarrenr#include <netinet/ip.h> 50145516Sdarrenr#include <netinet/ip_var.h> 51145516Sdarrenr#include <netinet/tcp.h> 52274744Srodrigc#include <net/vnet.h> 53145516Sdarrenr#include <netinet/udp.h> 54145516Sdarrenr#include <netinet/tcpip.h> 55145516Sdarrenr#include <netinet/ip_icmp.h> 56145516Sdarrenr#include "netinet/ip_compat.h" 57145516Sdarrenr#ifdef USE_INET6 58145516Sdarrenr# include <netinet/icmp6.h> 59145516Sdarrenr#endif 60145516Sdarrenr#include "netinet/ip_fil.h" 61145516Sdarrenr#include "netinet/ip_nat.h" 62145516Sdarrenr#include "netinet/ip_frag.h" 63145516Sdarrenr#include "netinet/ip_state.h" 64145516Sdarrenr#include "netinet/ip_proxy.h" 65145516Sdarrenr#include "netinet/ip_auth.h" 66145516Sdarrenr#include "netinet/ip_sync.h" 67255332Scy#include "netinet/ip_lookup.h" 68255332Scy#include "netinet/ip_dstlist.h" 69145516Sdarrenr#ifdef IPFILTER_SCAN 70369246Scy# include "netinet/ip_scan.h" 71145516Sdarrenr#endif 72145516Sdarrenr#include "netinet/ip_pool.h" 73350577Scy#include <sys/malloc.h> 74145516Sdarrenr#include <sys/kernel.h> 75145516Sdarrenr#ifdef CSUM_DATA_VALID 76369246Scy# include <machine/in_cksum.h> 77145516Sdarrenr#endif 78369245Sgit2svnextern int ip_optcopy(struct ip *, struct ip *); 79145516Sdarrenr 80369246Scy#ifdef IPFILTER_M_IPFILTER 81151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures"); 82369246Scy#endif 83145516Sdarrenr 84145516Sdarrenr 85369245Sgit2svnstatic int ipf_send_ip(fr_info_t *, mb_t *); 86369245Sgit2svnstatic void ipf_timer_func(void *arg); 87145516Sdarrenr 88302298SbzVNET_DEFINE(ipf_main_softc_t, ipfmain) = { 89302298Sbz .ipf_running = -2, 90302298Sbz}; 91302298Sbz#define V_ipfmain VNET(ipfmain) 92145516Sdarrenr 93369246Scy#include <sys/conf.h> 94369246Scy#include <net/pfil.h> 95145516Sdarrenr 96350669Scystatic eventhandler_tag ipf_arrivetag, ipf_departtag; 97302298Sbz#if 0 98302298Sbz/* 99302298Sbz * Disable the "cloner" event handler; we are getting interface 100302298Sbz * events before the firewall is fully initiallized and also no vnet 101302298Sbz * information thus leading to uninitialised memory accesses. 102302298Sbz * In addition it is unclear why we need it in first place. 103302298Sbz * If it turns out to be needed, well need a dedicated event handler 104302298Sbz * for it to deal with the ifc and the correct vnet. 105302298Sbz */ 106350669Scystatic eventhandler_tag ipf_clonetag; 107302298Sbz#endif 108145516Sdarrenr 109302298Sbzstatic void ipf_ifevent(void *arg, struct ifnet *ifp); 110153876Sguido 111302298Sbzstatic void ipf_ifevent(arg, ifp) 112255332Scy void *arg; 113302298Sbz struct ifnet *ifp; 114153876Sguido{ 115302298Sbz 116302298Sbz CURVNET_SET(ifp->if_vnet); 117302298Sbz if (V_ipfmain.ipf_running > 0) 118302298Sbz ipf_sync(&V_ipfmain, NULL); 119302298Sbz CURVNET_RESTORE(); 120153876Sguido} 121153876Sguido 122153876Sguido 123145516Sdarrenr 124145516Sdarrenrstatic int 125255332Scyipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 126145516Sdarrenr{ 127145516Sdarrenr struct ip *ip = mtod(*mp, struct ip *); 128255332Scy int rv; 129255332Scy 130255332Scy /* 131255332Scy * IPFilter expects evreything in network byte order 132255332Scy */ 133255332Scy#if (__FreeBSD_version < 1000019) 134255332Scy ip->ip_len = htons(ip->ip_len); 135255332Scy ip->ip_off = htons(ip->ip_off); 136255332Scy#endif 137302298Sbz CURVNET_SET(ifp->if_vnet); 138302298Sbz rv = ipf_check(&V_ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), 139255332Scy mp); 140302298Sbz CURVNET_RESTORE(); 141255332Scy#if (__FreeBSD_version < 1000019) 142255332Scy if ((rv == 0) && (*mp != NULL)) { 143255332Scy ip = mtod(*mp, struct ip *); 144255332Scy ip->ip_len = ntohs(ip->ip_len); 145255332Scy ip->ip_off = ntohs(ip->ip_off); 146255332Scy } 147255332Scy#endif 148255332Scy return rv; 149145516Sdarrenr} 150145516Sdarrenr 151145516Sdarrenr# ifdef USE_INET6 152145516Sdarrenr# include <netinet/ip6.h> 153145516Sdarrenr 154145516Sdarrenrstatic int 155255332Scyipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) 156145516Sdarrenr{ 157302298Sbz int error; 158302298Sbz 159302298Sbz CURVNET_SET(ifp->if_vnet); 160302298Sbz error = ipf_check(&V_ipfmain, mtod(*mp, struct ip *), 161302298Sbz sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp); 162302298Sbz CURVNET_RESTORE(); 163302298Sbz return (error); 164145516Sdarrenr} 165145516Sdarrenr# endif 166145516Sdarrenr#if defined(IPFILTER_LKM) 167255332Scyint ipf_identify(s) 168255332Scy char *s; 169145516Sdarrenr{ 170145516Sdarrenr if (strcmp(s, "ipl") == 0) 171145516Sdarrenr return 1; 172145516Sdarrenr return 0; 173145516Sdarrenr} 174145516Sdarrenr#endif /* IPFILTER_LKM */ 175145516Sdarrenr 176145516Sdarrenr 177255332Scystatic void 178255332Scyipf_timer_func(arg) 179255332Scy void *arg; 180145516Sdarrenr{ 181255332Scy ipf_main_softc_t *softc = arg; 182255332Scy SPL_INT(s); 183255332Scy 184255332Scy SPL_NET(s); 185255332Scy READ_ENTER(&softc->ipf_global); 186255332Scy 187255332Scy if (softc->ipf_running > 0) 188255332Scy ipf_slowtimer(softc); 189255332Scy 190255332Scy if (softc->ipf_running == -1 || softc->ipf_running == 1) { 191255755Scy#if 0 192255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2); 193255332Scy#endif 194283291Sjkim callout_init(&softc->ipf_slow_ch, 1); 195255755Scy callout_reset(&softc->ipf_slow_ch, 196255755Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 197255755Scy ipf_timer_func, softc); 198255332Scy } 199255332Scy RWLOCK_EXIT(&softc->ipf_global); 200255332Scy SPL_X(s); 201255332Scy} 202255332Scy 203255332Scy 204255332Scyint 205255332Scyipfattach(softc) 206255332Scy ipf_main_softc_t *softc; 207255332Scy{ 208145516Sdarrenr#ifdef USE_SPL 209145516Sdarrenr int s; 210145516Sdarrenr#endif 211145516Sdarrenr 212145516Sdarrenr SPL_NET(s); 213255332Scy if (softc->ipf_running > 0) { 214145516Sdarrenr SPL_X(s); 215145516Sdarrenr return EBUSY; 216145516Sdarrenr } 217145516Sdarrenr 218255332Scy if (ipf_init_all(softc) < 0) { 219145516Sdarrenr SPL_X(s); 220145516Sdarrenr return EIO; 221145516Sdarrenr } 222145516Sdarrenr 223145516Sdarrenr 224302298Sbz bzero((char *)V_ipfmain.ipf_selwait, sizeof(V_ipfmain.ipf_selwait)); 225255332Scy softc->ipf_running = 1; 226145516Sdarrenr 227255332Scy if (softc->ipf_control_forwarding & 1) 228181803Sbz V_ipforwarding = 1; 229145516Sdarrenr 230145516Sdarrenr SPL_X(s); 231255755Scy#if 0 232255332Scy softc->ipf_slow_ch = timeout(ipf_timer_func, softc, 233255332Scy (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); 234255755Scy#endif 235283291Sjkim callout_init(&softc->ipf_slow_ch, 1); 236255755Scy callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT, 237255755Scy ipf_timer_func, softc); 238145516Sdarrenr return 0; 239145516Sdarrenr} 240145516Sdarrenr 241145516Sdarrenr 242145516Sdarrenr/* 243145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output 244145516Sdarrenr * stream. 245145516Sdarrenr */ 246255332Scyint 247255332Scyipfdetach(softc) 248255332Scy ipf_main_softc_t *softc; 249145516Sdarrenr{ 250145516Sdarrenr#ifdef USE_SPL 251145516Sdarrenr int s; 252145516Sdarrenr#endif 253255332Scy 254255332Scy if (softc->ipf_control_forwarding & 2) 255181803Sbz V_ipforwarding = 0; 256145516Sdarrenr 257145516Sdarrenr SPL_NET(s); 258145516Sdarrenr 259255755Scy#if 0 260255332Scy if (softc->ipf_slow_ch.callout != NULL) 261255332Scy untimeout(ipf_timer_func, softc, softc->ipf_slow_ch); 262255332Scy bzero(&softc->ipf_slow, sizeof(softc->ipf_slow)); 263255755Scy#endif 264255755Scy callout_drain(&softc->ipf_slow_ch); 265145516Sdarrenr 266255332Scy ipf_fini_all(softc); 267145516Sdarrenr 268255332Scy softc->ipf_running = -2; 269145516Sdarrenr 270145516Sdarrenr SPL_X(s); 271145516Sdarrenr 272145516Sdarrenr return 0; 273145516Sdarrenr} 274145516Sdarrenr 275145516Sdarrenr 276145516Sdarrenr/* 277145516Sdarrenr * Filter ioctl interface. 278145516Sdarrenr */ 279255332Scyint 280341378Scyipfioctl(dev, cmd, data, mode, p) 281255332Scy struct thread *p; 282369246Scy#define p_cred td_ucred 283369246Scy#define p_uid td_ucred->cr_ruid 284255332Scy struct cdev *dev; 285255332Scy ioctlcmd_t cmd; 286255332Scy caddr_t data; 287255332Scy int mode; 288145516Sdarrenr{ 289170268Sdarrenr int error = 0, unit = 0; 290170268Sdarrenr SPL_INT(s); 291145516Sdarrenr 292302298Sbz CURVNET_SET(TD_TO_VNET(p)); 293255332Scy if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE)) 294255332Scy { 295302298Sbz V_ipfmain.ipf_interror = 130001; 296302298Sbz CURVNET_RESTORE(); 297145516Sdarrenr return EPERM; 298255332Scy } 299145516Sdarrenr 300145516Sdarrenr unit = GET_MINOR(dev); 301255332Scy if ((IPL_LOGMAX < unit) || (unit < 0)) { 302302298Sbz V_ipfmain.ipf_interror = 130002; 303302298Sbz CURVNET_RESTORE(); 304145516Sdarrenr return ENXIO; 305255332Scy } 306145516Sdarrenr 307302298Sbz if (V_ipfmain.ipf_running <= 0) { 308255332Scy if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) { 309302298Sbz V_ipfmain.ipf_interror = 130003; 310302298Sbz CURVNET_RESTORE(); 311145516Sdarrenr return EIO; 312255332Scy } 313145516Sdarrenr if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 314173181Sdarrenr cmd != SIOCIPFSET && cmd != SIOCFRENB && 315255332Scy cmd != SIOCGETFS && cmd != SIOCGETFF && 316255332Scy cmd != SIOCIPFINTERROR) { 317302298Sbz V_ipfmain.ipf_interror = 130004; 318302298Sbz CURVNET_RESTORE(); 319145516Sdarrenr return EIO; 320255332Scy } 321145516Sdarrenr } 322145516Sdarrenr 323145516Sdarrenr SPL_NET(s); 324145516Sdarrenr 325302298Sbz error = ipf_ioctlswitch(&V_ipfmain, unit, data, cmd, mode, p->p_uid, p); 326274744Srodrigc CURVNET_RESTORE(); 327145516Sdarrenr if (error != -1) { 328145516Sdarrenr SPL_X(s); 329145516Sdarrenr return error; 330145516Sdarrenr } 331145516Sdarrenr 332145516Sdarrenr SPL_X(s); 333161356Sguido 334145516Sdarrenr return error; 335145516Sdarrenr} 336145516Sdarrenr 337145516Sdarrenr 338145516Sdarrenr/* 339255332Scy * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that 340145516Sdarrenr * requires a large amount of setting up and isn't any more efficient. 341145516Sdarrenr */ 342255332Scyint 343255332Scyipf_send_reset(fin) 344255332Scy fr_info_t *fin; 345145516Sdarrenr{ 346145516Sdarrenr struct tcphdr *tcp, *tcp2; 347145516Sdarrenr int tlen = 0, hlen; 348145516Sdarrenr struct mbuf *m; 349145516Sdarrenr#ifdef USE_INET6 350145516Sdarrenr ip6_t *ip6; 351145516Sdarrenr#endif 352145516Sdarrenr ip_t *ip; 353145516Sdarrenr 354145516Sdarrenr tcp = fin->fin_dp; 355145516Sdarrenr if (tcp->th_flags & TH_RST) 356145516Sdarrenr return -1; /* feedback loop */ 357145516Sdarrenr 358255332Scy if (ipf_checkl4sum(fin) == -1) 359145516Sdarrenr return -1; 360145516Sdarrenr 361145516Sdarrenr tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + 362145516Sdarrenr ((tcp->th_flags & TH_SYN) ? 1 : 0) + 363145516Sdarrenr ((tcp->th_flags & TH_FIN) ? 1 : 0); 364145516Sdarrenr 365145516Sdarrenr#ifdef USE_INET6 366145516Sdarrenr hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); 367145516Sdarrenr#else 368145516Sdarrenr hlen = sizeof(ip_t); 369145516Sdarrenr#endif 370145516Sdarrenr#ifdef MGETHDR 371260715Sglebius MGETHDR(m, M_NOWAIT, MT_HEADER); 372145516Sdarrenr#else 373260715Sglebius MGET(m, M_NOWAIT, MT_HEADER); 374145516Sdarrenr#endif 375145516Sdarrenr if (m == NULL) 376145516Sdarrenr return -1; 377145516Sdarrenr if (sizeof(*tcp2) + hlen > MLEN) { 378276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 379145516Sdarrenr FREE_MB_T(m); 380145516Sdarrenr return -1; 381145516Sdarrenr } 382145516Sdarrenr } 383145516Sdarrenr 384145516Sdarrenr m->m_len = sizeof(*tcp2) + hlen; 385145516Sdarrenr m->m_data += max_linkhdr; 386145516Sdarrenr m->m_pkthdr.len = m->m_len; 387145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 388145516Sdarrenr ip = mtod(m, struct ip *); 389145516Sdarrenr bzero((char *)ip, hlen); 390145516Sdarrenr#ifdef USE_INET6 391145516Sdarrenr ip6 = (ip6_t *)ip; 392145516Sdarrenr#endif 393145516Sdarrenr tcp2 = (struct tcphdr *)((char *)ip + hlen); 394145516Sdarrenr tcp2->th_sport = tcp->th_dport; 395145516Sdarrenr tcp2->th_dport = tcp->th_sport; 396145516Sdarrenr 397145516Sdarrenr if (tcp->th_flags & TH_ACK) { 398145516Sdarrenr tcp2->th_seq = tcp->th_ack; 399145516Sdarrenr tcp2->th_flags = TH_RST; 400145516Sdarrenr tcp2->th_ack = 0; 401145516Sdarrenr } else { 402145516Sdarrenr tcp2->th_seq = 0; 403145516Sdarrenr tcp2->th_ack = ntohl(tcp->th_seq); 404145516Sdarrenr tcp2->th_ack += tlen; 405145516Sdarrenr tcp2->th_ack = htonl(tcp2->th_ack); 406145516Sdarrenr tcp2->th_flags = TH_RST|TH_ACK; 407145516Sdarrenr } 408145516Sdarrenr TCP_X2_A(tcp2, 0); 409145516Sdarrenr TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); 410145516Sdarrenr tcp2->th_win = tcp->th_win; 411145516Sdarrenr tcp2->th_sum = 0; 412145516Sdarrenr tcp2->th_urp = 0; 413145516Sdarrenr 414145516Sdarrenr#ifdef USE_INET6 415145516Sdarrenr if (fin->fin_v == 6) { 416145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 417145516Sdarrenr ip6->ip6_plen = htons(sizeof(struct tcphdr)); 418145516Sdarrenr ip6->ip6_nxt = IPPROTO_TCP; 419145516Sdarrenr ip6->ip6_hlim = 0; 420255332Scy ip6->ip6_src = fin->fin_dst6.in6; 421255332Scy ip6->ip6_dst = fin->fin_src6.in6; 422145516Sdarrenr tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, 423145516Sdarrenr sizeof(*ip6), sizeof(*tcp2)); 424255332Scy return ipf_send_ip(fin, m); 425145516Sdarrenr } 426145516Sdarrenr#endif 427145516Sdarrenr ip->ip_p = IPPROTO_TCP; 428145516Sdarrenr ip->ip_len = htons(sizeof(struct tcphdr)); 429145516Sdarrenr ip->ip_src.s_addr = fin->fin_daddr; 430145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 431145516Sdarrenr tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); 432255332Scy ip->ip_len = htons(hlen + sizeof(*tcp2)); 433255332Scy return ipf_send_ip(fin, m); 434145516Sdarrenr} 435145516Sdarrenr 436145516Sdarrenr 437255332Scy/* 438255332Scy * ip_len must be in network byte order when called. 439255332Scy */ 440255332Scystatic int 441255332Scyipf_send_ip(fin, m) 442255332Scy fr_info_t *fin; 443255332Scy mb_t *m; 444145516Sdarrenr{ 445145516Sdarrenr fr_info_t fnew; 446145516Sdarrenr ip_t *ip, *oip; 447145516Sdarrenr int hlen; 448145516Sdarrenr 449145516Sdarrenr ip = mtod(m, ip_t *); 450145516Sdarrenr bzero((char *)&fnew, sizeof(fnew)); 451255332Scy fnew.fin_main_soft = fin->fin_main_soft; 452145516Sdarrenr 453145516Sdarrenr IP_V_A(ip, fin->fin_v); 454145516Sdarrenr switch (fin->fin_v) 455145516Sdarrenr { 456145516Sdarrenr case 4 : 457255332Scy oip = fin->fin_ip; 458255332Scy hlen = sizeof(*oip); 459145516Sdarrenr fnew.fin_v = 4; 460255332Scy fnew.fin_p = ip->ip_p; 461255332Scy fnew.fin_plen = ntohs(ip->ip_len); 462145516Sdarrenr IP_HL_A(ip, sizeof(*oip) >> 2); 463145516Sdarrenr ip->ip_tos = oip->ip_tos; 464145516Sdarrenr ip->ip_id = fin->fin_ip->ip_id; 465341740Scy ip->ip_off = htons(V_path_mtu_discovery ? IP_DF : 0); 466181803Sbz ip->ip_ttl = V_ip_defttl; 467145516Sdarrenr ip->ip_sum = 0; 468145516Sdarrenr break; 469145516Sdarrenr#ifdef USE_INET6 470145516Sdarrenr case 6 : 471145516Sdarrenr { 472145516Sdarrenr ip6_t *ip6 = (ip6_t *)ip; 473145516Sdarrenr 474145516Sdarrenr ip6->ip6_vfc = 0x60; 475145516Sdarrenr ip6->ip6_hlim = IPDEFTTL; 476145516Sdarrenr 477255332Scy hlen = sizeof(*ip6); 478255332Scy fnew.fin_p = ip6->ip6_nxt; 479145516Sdarrenr fnew.fin_v = 6; 480255332Scy fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 481145516Sdarrenr break; 482145516Sdarrenr } 483145516Sdarrenr#endif 484145516Sdarrenr default : 485145516Sdarrenr return EINVAL; 486145516Sdarrenr } 487145516Sdarrenr#ifdef IPSEC 488145516Sdarrenr m->m_pkthdr.rcvif = NULL; 489145516Sdarrenr#endif 490145516Sdarrenr 491145516Sdarrenr fnew.fin_ifp = fin->fin_ifp; 492145516Sdarrenr fnew.fin_flx = FI_NOCKSUM; 493145516Sdarrenr fnew.fin_m = m; 494145516Sdarrenr fnew.fin_ip = ip; 495255332Scy fnew.fin_mp = &m; 496145516Sdarrenr fnew.fin_hlen = hlen; 497145516Sdarrenr fnew.fin_dp = (char *)ip + hlen; 498255332Scy (void) ipf_makefrip(hlen, ip, &fnew); 499145516Sdarrenr 500255332Scy return ipf_fastroute(m, &m, &fnew, NULL); 501145516Sdarrenr} 502145516Sdarrenr 503145516Sdarrenr 504255332Scyint 505255332Scyipf_send_icmp_err(type, fin, dst) 506255332Scy int type; 507255332Scy fr_info_t *fin; 508255332Scy int dst; 509145516Sdarrenr{ 510145516Sdarrenr int err, hlen, xtra, iclen, ohlen, avail, code; 511145516Sdarrenr struct in_addr dst4; 512145516Sdarrenr struct icmp *icmp; 513145516Sdarrenr struct mbuf *m; 514255332Scy i6addr_t dst6; 515145516Sdarrenr void *ifp; 516145516Sdarrenr#ifdef USE_INET6 517145516Sdarrenr ip6_t *ip6; 518145516Sdarrenr#endif 519145516Sdarrenr ip_t *ip, *ip2; 520145516Sdarrenr 521172776Sdarrenr if ((type < 0) || (type >= ICMP_MAXTYPE)) 522145516Sdarrenr return -1; 523145516Sdarrenr 524145516Sdarrenr code = fin->fin_icode; 525145516Sdarrenr#ifdef USE_INET6 526341615Scy /* See NetBSD ip_fil_netbsd.c r1.4: */ 527255332Scy if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int))) 528145516Sdarrenr return -1; 529145516Sdarrenr#endif 530145516Sdarrenr 531255332Scy if (ipf_checkl4sum(fin) == -1) 532145516Sdarrenr return -1; 533145516Sdarrenr#ifdef MGETHDR 534260715Sglebius MGETHDR(m, M_NOWAIT, MT_HEADER); 535145516Sdarrenr#else 536260715Sglebius MGET(m, M_NOWAIT, MT_HEADER); 537145516Sdarrenr#endif 538145516Sdarrenr if (m == NULL) 539145516Sdarrenr return -1; 540145516Sdarrenr avail = MHLEN; 541145516Sdarrenr 542145516Sdarrenr xtra = 0; 543145516Sdarrenr hlen = 0; 544145516Sdarrenr ohlen = 0; 545255332Scy dst4.s_addr = 0; 546145516Sdarrenr ifp = fin->fin_ifp; 547145516Sdarrenr if (fin->fin_v == 4) { 548255332Scy if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT)) 549145516Sdarrenr switch (ntohs(fin->fin_data[0]) >> 8) 550145516Sdarrenr { 551145516Sdarrenr case ICMP_ECHO : 552145516Sdarrenr case ICMP_TSTAMP : 553145516Sdarrenr case ICMP_IREQ : 554145516Sdarrenr case ICMP_MASKREQ : 555145516Sdarrenr break; 556145516Sdarrenr default : 557145516Sdarrenr FREE_MB_T(m); 558145516Sdarrenr return 0; 559145516Sdarrenr } 560145516Sdarrenr 561145516Sdarrenr if (dst == 0) { 562302298Sbz if (ipf_ifpaddr(&V_ipfmain, 4, FRI_NORMAL, ifp, 563255332Scy &dst6, NULL) == -1) { 564145516Sdarrenr FREE_MB_T(m); 565145516Sdarrenr return -1; 566145516Sdarrenr } 567255332Scy dst4 = dst6.in4; 568145516Sdarrenr } else 569145516Sdarrenr dst4.s_addr = fin->fin_daddr; 570145516Sdarrenr 571145516Sdarrenr hlen = sizeof(ip_t); 572145516Sdarrenr ohlen = fin->fin_hlen; 573255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 574145516Sdarrenr if (fin->fin_hlen < fin->fin_plen) 575145516Sdarrenr xtra = MIN(fin->fin_dlen, 8); 576145516Sdarrenr else 577145516Sdarrenr xtra = 0; 578145516Sdarrenr } 579145516Sdarrenr 580145516Sdarrenr#ifdef USE_INET6 581145516Sdarrenr else if (fin->fin_v == 6) { 582145516Sdarrenr hlen = sizeof(ip6_t); 583145516Sdarrenr ohlen = sizeof(ip6_t); 584255332Scy iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen; 585145516Sdarrenr type = icmptoicmp6types[type]; 586145516Sdarrenr if (type == ICMP6_DST_UNREACH) 587145516Sdarrenr code = icmptoicmp6unreach[code]; 588145516Sdarrenr 589255332Scy if (iclen + max_linkhdr + fin->fin_plen > avail) { 590276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 591145516Sdarrenr FREE_MB_T(m); 592145516Sdarrenr return -1; 593145516Sdarrenr } 594145516Sdarrenr avail = MCLBYTES; 595145516Sdarrenr } 596255332Scy xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr); 597255332Scy xtra = MIN(xtra, IPV6_MMTU - iclen); 598145516Sdarrenr if (dst == 0) { 599302298Sbz if (ipf_ifpaddr(&V_ipfmain, 6, FRI_NORMAL, ifp, 600255332Scy &dst6, NULL) == -1) { 601145516Sdarrenr FREE_MB_T(m); 602145516Sdarrenr return -1; 603145516Sdarrenr } 604145516Sdarrenr } else 605145516Sdarrenr dst6 = fin->fin_dst6; 606145516Sdarrenr } 607145516Sdarrenr#endif 608145516Sdarrenr else { 609145516Sdarrenr FREE_MB_T(m); 610145516Sdarrenr return -1; 611145516Sdarrenr } 612145516Sdarrenr 613145516Sdarrenr avail -= (max_linkhdr + iclen); 614145516Sdarrenr if (avail < 0) { 615145516Sdarrenr FREE_MB_T(m); 616145516Sdarrenr return -1; 617145516Sdarrenr } 618145516Sdarrenr if (xtra > avail) 619145516Sdarrenr xtra = avail; 620145516Sdarrenr iclen += xtra; 621145516Sdarrenr m->m_data += max_linkhdr; 622145516Sdarrenr m->m_pkthdr.rcvif = (struct ifnet *)0; 623145516Sdarrenr m->m_pkthdr.len = iclen; 624145516Sdarrenr m->m_len = iclen; 625145516Sdarrenr ip = mtod(m, ip_t *); 626145516Sdarrenr icmp = (struct icmp *)((char *)ip + hlen); 627145516Sdarrenr ip2 = (ip_t *)&icmp->icmp_ip; 628145516Sdarrenr 629145516Sdarrenr icmp->icmp_type = type; 630145516Sdarrenr icmp->icmp_code = fin->fin_icode; 631145516Sdarrenr icmp->icmp_cksum = 0; 632145516Sdarrenr#ifdef icmp_nextmtu 633255332Scy if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) { 634255332Scy if (fin->fin_mtu != 0) { 635255332Scy icmp->icmp_nextmtu = htons(fin->fin_mtu); 636255332Scy 637255332Scy } else if (ifp != NULL) { 638255332Scy icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp)); 639255332Scy 640255332Scy } else { /* make up a number... */ 641255332Scy icmp->icmp_nextmtu = htons(fin->fin_plen - 20); 642255332Scy } 643255332Scy } 644145516Sdarrenr#endif 645145516Sdarrenr 646145516Sdarrenr bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); 647145516Sdarrenr 648145516Sdarrenr#ifdef USE_INET6 649145516Sdarrenr ip6 = (ip6_t *)ip; 650145516Sdarrenr if (fin->fin_v == 6) { 651145516Sdarrenr ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 652145516Sdarrenr ip6->ip6_plen = htons(iclen - hlen); 653145516Sdarrenr ip6->ip6_nxt = IPPROTO_ICMPV6; 654145516Sdarrenr ip6->ip6_hlim = 0; 655255332Scy ip6->ip6_src = dst6.in6; 656255332Scy ip6->ip6_dst = fin->fin_src6.in6; 657145516Sdarrenr if (xtra > 0) 658145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 659145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 660145516Sdarrenr icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, 661145516Sdarrenr sizeof(*ip6), iclen - hlen); 662145516Sdarrenr } else 663145516Sdarrenr#endif 664145516Sdarrenr { 665145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 666145516Sdarrenr ip->ip_src.s_addr = dst4.s_addr; 667145516Sdarrenr ip->ip_dst.s_addr = fin->fin_saddr; 668145516Sdarrenr 669145516Sdarrenr if (xtra > 0) 670145516Sdarrenr bcopy((char *)fin->fin_ip + ohlen, 671145516Sdarrenr (char *)&icmp->icmp_ip + ohlen, xtra); 672145516Sdarrenr icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 673145516Sdarrenr sizeof(*icmp) + 8); 674255332Scy ip->ip_len = htons(iclen); 675145516Sdarrenr ip->ip_p = IPPROTO_ICMP; 676145516Sdarrenr } 677255332Scy err = ipf_send_ip(fin, m); 678145516Sdarrenr return err; 679145516Sdarrenr} 680145516Sdarrenr 681145516Sdarrenr 682145516Sdarrenr 683145516Sdarrenr 684173181Sdarrenr/* 685173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts 686173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain 687173181Sdarrenr */ 688255332Scyint 689255332Scyipf_fastroute(m0, mpp, fin, fdp) 690255332Scy mb_t *m0, **mpp; 691255332Scy fr_info_t *fin; 692255332Scy frdest_t *fdp; 693145516Sdarrenr{ 694145516Sdarrenr register struct ip *ip, *mhip; 695173181Sdarrenr register struct mbuf *m = *mpp; 696145516Sdarrenr int len, off, error = 0, hlen, code; 697145516Sdarrenr struct ifnet *ifp, *sifp; 698293628Smelifaro struct sockaddr_in dst; 699293628Smelifaro struct nhop4_extended nh4; 700293628Smelifaro u_long fibnum = 0; 701145516Sdarrenr u_short ip_off; 702255332Scy frdest_t node; 703145516Sdarrenr frentry_t *fr; 704145516Sdarrenr 705145516Sdarrenr#ifdef M_WRITABLE 706145516Sdarrenr /* 707145516Sdarrenr * HOT FIX/KLUDGE: 708145516Sdarrenr * 709145516Sdarrenr * If the mbuf we're about to send is not writable (because of 710145516Sdarrenr * a cluster reference, for example) we'll need to make a copy 711145516Sdarrenr * of it since this routine modifies the contents. 712145516Sdarrenr * 713145516Sdarrenr * If you have non-crappy network hardware that can transmit data 714145516Sdarrenr * from the mbuf, rather than making a copy, this is gonna be a 715145516Sdarrenr * problem. 716145516Sdarrenr */ 717145516Sdarrenr if (M_WRITABLE(m) == 0) { 718260715Sglebius m0 = m_dup(m, M_NOWAIT); 719298030Scy if (m0 != NULL) { 720145516Sdarrenr FREE_MB_T(m); 721145516Sdarrenr m = m0; 722145516Sdarrenr *mpp = m; 723145516Sdarrenr } else { 724145516Sdarrenr error = ENOBUFS; 725145516Sdarrenr FREE_MB_T(m); 726161356Sguido goto done; 727145516Sdarrenr } 728145516Sdarrenr } 729145516Sdarrenr#endif 730145516Sdarrenr 731145516Sdarrenr#ifdef USE_INET6 732145516Sdarrenr if (fin->fin_v == 6) { 733145516Sdarrenr /* 734145516Sdarrenr * currently "to <if>" and "to <if>:ip#" are not supported 735145516Sdarrenr * for IPv6 736145516Sdarrenr */ 737255332Scy return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 738145516Sdarrenr } 739145516Sdarrenr#endif 740145516Sdarrenr 741145516Sdarrenr hlen = fin->fin_hlen; 742145516Sdarrenr ip = mtod(m0, struct ip *); 743255332Scy ifp = NULL; 744145516Sdarrenr 745145516Sdarrenr /* 746145516Sdarrenr * Route packet. 747145516Sdarrenr */ 748293628Smelifaro bzero(&dst, sizeof (dst)); 749293628Smelifaro dst.sin_family = AF_INET; 750293628Smelifaro dst.sin_addr = ip->ip_dst; 751293628Smelifaro dst.sin_len = sizeof(dst); 752145516Sdarrenr 753145516Sdarrenr fr = fin->fin_fr; 754255332Scy if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && 755255332Scy (fdp->fd_type == FRD_DSTLIST)) { 756255332Scy if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0) 757255332Scy fdp = &node; 758255332Scy } 759255332Scy 760145516Sdarrenr if (fdp != NULL) 761255332Scy ifp = fdp->fd_ptr; 762145516Sdarrenr else 763145516Sdarrenr ifp = fin->fin_ifp; 764145516Sdarrenr 765255332Scy if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) { 766145516Sdarrenr error = -2; 767145516Sdarrenr goto bad; 768145516Sdarrenr } 769145516Sdarrenr 770161356Sguido if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) 771293628Smelifaro dst.sin_addr = fdp->fd_ip; 772145516Sdarrenr 773293628Smelifaro fibnum = M_GETFIB(m0); 774293628Smelifaro if (fib4_lookup_nh_ext(fibnum, dst.sin_addr, NHR_REF, 0, &nh4) != 0) { 775145516Sdarrenr if (in_localaddr(ip->ip_dst)) 776145516Sdarrenr error = EHOSTUNREACH; 777145516Sdarrenr else 778145516Sdarrenr error = ENETUNREACH; 779145516Sdarrenr goto bad; 780145516Sdarrenr } 781145516Sdarrenr 782293628Smelifaro if (ifp == NULL) 783293628Smelifaro ifp = nh4.nh_ifp; 784293628Smelifaro if (nh4.nh_flags & NHF_GATEWAY) 785293628Smelifaro dst.sin_addr = nh4.nh_addr; 786293628Smelifaro 787145516Sdarrenr /* 788145516Sdarrenr * For input packets which are being "fastrouted", they won't 789145516Sdarrenr * go back through output filtering and miss their chance to get 790170268Sdarrenr * NAT'd and counted. Duplicated packets aren't considered to be 791170268Sdarrenr * part of the normal packet stream, so do not NAT them or pass 792170268Sdarrenr * them through stateful checking, etc. 793145516Sdarrenr */ 794170268Sdarrenr if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { 795145516Sdarrenr sifp = fin->fin_ifp; 796145516Sdarrenr fin->fin_ifp = ifp; 797145516Sdarrenr fin->fin_out = 1; 798255332Scy (void) ipf_acctpkt(fin, NULL); 799145516Sdarrenr fin->fin_fr = NULL; 800145516Sdarrenr if (!fr || !(fr->fr_flags & FR_RETMASK)) { 801145516Sdarrenr u_32_t pass; 802145516Sdarrenr 803255332Scy (void) ipf_state_check(fin, &pass); 804145516Sdarrenr } 805145516Sdarrenr 806255332Scy switch (ipf_nat_checkout(fin, NULL)) 807145516Sdarrenr { 808145516Sdarrenr case 0 : 809145516Sdarrenr break; 810145516Sdarrenr case 1 : 811145516Sdarrenr ip->ip_sum = 0; 812145516Sdarrenr break; 813145516Sdarrenr case -1 : 814145516Sdarrenr error = -1; 815173181Sdarrenr goto bad; 816145516Sdarrenr break; 817145516Sdarrenr } 818145516Sdarrenr 819145516Sdarrenr fin->fin_ifp = sifp; 820145516Sdarrenr fin->fin_out = 0; 821145516Sdarrenr } else 822145516Sdarrenr ip->ip_sum = 0; 823145516Sdarrenr /* 824145516Sdarrenr * If small enough for interface, can just send directly. 825145516Sdarrenr */ 826255332Scy if (ntohs(ip->ip_len) <= ifp->if_mtu) { 827145516Sdarrenr if (!ip->ip_sum) 828145516Sdarrenr ip->ip_sum = in_cksum(m, hlen); 829293628Smelifaro error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, 830293628Smelifaro NULL 831255332Scy ); 832145516Sdarrenr goto done; 833145516Sdarrenr } 834145516Sdarrenr /* 835145516Sdarrenr * Too large for interface; fragment if possible. 836145516Sdarrenr * Must be able to put at least 8 bytes per fragment. 837145516Sdarrenr */ 838145516Sdarrenr ip_off = ntohs(ip->ip_off); 839145516Sdarrenr if (ip_off & IP_DF) { 840145516Sdarrenr error = EMSGSIZE; 841145516Sdarrenr goto bad; 842145516Sdarrenr } 843145516Sdarrenr len = (ifp->if_mtu - hlen) &~ 7; 844145516Sdarrenr if (len < 8) { 845145516Sdarrenr error = EMSGSIZE; 846145516Sdarrenr goto bad; 847145516Sdarrenr } 848145516Sdarrenr 849145516Sdarrenr { 850145516Sdarrenr int mhlen, firstlen = len; 851145516Sdarrenr struct mbuf **mnext = &m->m_act; 852145516Sdarrenr 853145516Sdarrenr /* 854145516Sdarrenr * Loop through length of segment after first fragment, 855145516Sdarrenr * make new header and copy data of each part and link onto chain. 856145516Sdarrenr */ 857145516Sdarrenr m0 = m; 858145516Sdarrenr mhlen = sizeof (struct ip); 859255332Scy for (off = hlen + len; off < ntohs(ip->ip_len); off += len) { 860145516Sdarrenr#ifdef MGETHDR 861260715Sglebius MGETHDR(m, M_NOWAIT, MT_HEADER); 862145516Sdarrenr#else 863260715Sglebius MGET(m, M_NOWAIT, MT_HEADER); 864145516Sdarrenr#endif 865298030Scy if (m == NULL) { 866145516Sdarrenr m = m0; 867145516Sdarrenr error = ENOBUFS; 868145516Sdarrenr goto bad; 869145516Sdarrenr } 870145516Sdarrenr m->m_data += max_linkhdr; 871145516Sdarrenr mhip = mtod(m, struct ip *); 872145516Sdarrenr bcopy((char *)ip, (char *)mhip, sizeof(*ip)); 873145516Sdarrenr if (hlen > sizeof (struct ip)) { 874145516Sdarrenr mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 875145516Sdarrenr IP_HL_A(mhip, mhlen >> 2); 876145516Sdarrenr } 877145516Sdarrenr m->m_len = mhlen; 878145516Sdarrenr mhip->ip_off = ((off - hlen) >> 3) + ip_off; 879255332Scy if (off + len >= ntohs(ip->ip_len)) 880255332Scy len = ntohs(ip->ip_len) - off; 881145516Sdarrenr else 882145516Sdarrenr mhip->ip_off |= IP_MF; 883145516Sdarrenr mhip->ip_len = htons((u_short)(len + mhlen)); 884161356Sguido *mnext = m; 885145516Sdarrenr m->m_next = m_copy(m0, off, len); 886145516Sdarrenr if (m->m_next == 0) { 887145516Sdarrenr error = ENOBUFS; /* ??? */ 888145516Sdarrenr goto sendorfree; 889145516Sdarrenr } 890145516Sdarrenr m->m_pkthdr.len = mhlen + len; 891145516Sdarrenr m->m_pkthdr.rcvif = NULL; 892145516Sdarrenr mhip->ip_off = htons((u_short)mhip->ip_off); 893145516Sdarrenr mhip->ip_sum = 0; 894145516Sdarrenr mhip->ip_sum = in_cksum(m, mhlen); 895145516Sdarrenr mnext = &m->m_act; 896145516Sdarrenr } 897145516Sdarrenr /* 898145516Sdarrenr * Update first fragment by trimming what's been copied out 899145516Sdarrenr * and updating header, then send each fragment (in order). 900145516Sdarrenr */ 901145516Sdarrenr m_adj(m0, hlen + firstlen - ip->ip_len); 902145516Sdarrenr ip->ip_len = htons((u_short)(hlen + firstlen)); 903145516Sdarrenr ip->ip_off = htons((u_short)IP_MF); 904145516Sdarrenr ip->ip_sum = 0; 905145516Sdarrenr ip->ip_sum = in_cksum(m0, hlen); 906145516Sdarrenrsendorfree: 907145516Sdarrenr for (m = m0; m; m = m0) { 908145516Sdarrenr m0 = m->m_act; 909145516Sdarrenr m->m_act = 0; 910145516Sdarrenr if (error == 0) 911145516Sdarrenr error = (*ifp->if_output)(ifp, m, 912293628Smelifaro (struct sockaddr *)&dst, 913293628Smelifaro NULL 914255332Scy ); 915145516Sdarrenr else 916145516Sdarrenr FREE_MB_T(m); 917145516Sdarrenr } 918255332Scy } 919145516Sdarrenrdone: 920145516Sdarrenr if (!error) 921302298Sbz V_ipfmain.ipf_frouteok[0]++; 922145516Sdarrenr else 923302298Sbz V_ipfmain.ipf_frouteok[1]++; 924145516Sdarrenr 925145516Sdarrenr return 0; 926145516Sdarrenrbad: 927145516Sdarrenr if (error == EMSGSIZE) { 928145516Sdarrenr sifp = fin->fin_ifp; 929145516Sdarrenr code = fin->fin_icode; 930145516Sdarrenr fin->fin_icode = ICMP_UNREACH_NEEDFRAG; 931145516Sdarrenr fin->fin_ifp = ifp; 932255332Scy (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1); 933145516Sdarrenr fin->fin_ifp = sifp; 934145516Sdarrenr fin->fin_icode = code; 935145516Sdarrenr } 936145516Sdarrenr FREE_MB_T(m); 937145516Sdarrenr goto done; 938145516Sdarrenr} 939145516Sdarrenr 940145516Sdarrenr 941255332Scyint 942255332Scyipf_verifysrc(fin) 943255332Scy fr_info_t *fin; 944145516Sdarrenr{ 945293628Smelifaro struct nhop4_basic nh4; 946145516Sdarrenr 947293628Smelifaro if (fib4_lookup_nh_basic(0, fin->fin_src, 0, 0, &nh4) != 0) 948293628Smelifaro return (0); 949293628Smelifaro return (fin->fin_ifp == nh4.nh_ifp); 950145516Sdarrenr} 951145516Sdarrenr 952145516Sdarrenr 953145516Sdarrenr/* 954145516Sdarrenr * return the first IP Address associated with an interface 955145516Sdarrenr */ 956255332Scyint 957255332Scyipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask) 958255332Scy ipf_main_softc_t *softc; 959255332Scy int v, atype; 960255332Scy void *ifptr; 961255332Scy i6addr_t *inp, *inpmask; 962145516Sdarrenr{ 963145516Sdarrenr#ifdef USE_INET6 964145516Sdarrenr struct in6_addr *inp6 = NULL; 965145516Sdarrenr#endif 966145516Sdarrenr struct sockaddr *sock, *mask; 967145516Sdarrenr struct sockaddr_in *sin; 968145516Sdarrenr struct ifaddr *ifa; 969145516Sdarrenr struct ifnet *ifp; 970145516Sdarrenr 971145516Sdarrenr if ((ifptr == NULL) || (ifptr == (void *)-1)) 972145516Sdarrenr return -1; 973145516Sdarrenr 974145516Sdarrenr sin = NULL; 975145516Sdarrenr ifp = ifptr; 976145516Sdarrenr 977145516Sdarrenr if (v == 4) 978255332Scy inp->in4.s_addr = 0; 979145516Sdarrenr#ifdef USE_INET6 980145516Sdarrenr else if (v == 6) 981255332Scy bzero((char *)inp, sizeof(*inp)); 982145516Sdarrenr#endif 983145516Sdarrenr ifa = TAILQ_FIRST(&ifp->if_addrhead); 984145516Sdarrenr 985145516Sdarrenr sock = ifa->ifa_addr; 986145516Sdarrenr while (sock != NULL && ifa != NULL) { 987145516Sdarrenr sin = (struct sockaddr_in *)sock; 988145516Sdarrenr if ((v == 4) && (sin->sin_family == AF_INET)) 989145516Sdarrenr break; 990145516Sdarrenr#ifdef USE_INET6 991145516Sdarrenr if ((v == 6) && (sin->sin_family == AF_INET6)) { 992145516Sdarrenr inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; 993145516Sdarrenr if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 994145516Sdarrenr !IN6_IS_ADDR_LOOPBACK(inp6)) 995145516Sdarrenr break; 996145516Sdarrenr } 997145516Sdarrenr#endif 998145516Sdarrenr ifa = TAILQ_NEXT(ifa, ifa_link); 999145516Sdarrenr if (ifa != NULL) 1000145516Sdarrenr sock = ifa->ifa_addr; 1001145516Sdarrenr } 1002145516Sdarrenr 1003145516Sdarrenr if (ifa == NULL || sin == NULL) 1004145516Sdarrenr return -1; 1005145516Sdarrenr 1006145516Sdarrenr mask = ifa->ifa_netmask; 1007145516Sdarrenr if (atype == FRI_BROADCAST) 1008145516Sdarrenr sock = ifa->ifa_broadaddr; 1009145516Sdarrenr else if (atype == FRI_PEERADDR) 1010145516Sdarrenr sock = ifa->ifa_dstaddr; 1011145516Sdarrenr 1012161356Sguido if (sock == NULL) 1013161356Sguido return -1; 1014161356Sguido 1015145516Sdarrenr#ifdef USE_INET6 1016145516Sdarrenr if (v == 6) { 1017255332Scy return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, 1018255332Scy (struct sockaddr_in6 *)mask, 1019255332Scy inp, inpmask); 1020145516Sdarrenr } 1021145516Sdarrenr#endif 1022255332Scy return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock, 1023255332Scy (struct sockaddr_in *)mask, 1024255332Scy &inp->in4, &inpmask->in4); 1025145516Sdarrenr} 1026145516Sdarrenr 1027145516Sdarrenr 1028255332Scyu_32_t 1029255332Scyipf_newisn(fin) 1030255332Scy fr_info_t *fin; 1031145516Sdarrenr{ 1032145516Sdarrenr u_32_t newiss; 1033145516Sdarrenr newiss = arc4random(); 1034145516Sdarrenr return newiss; 1035145516Sdarrenr} 1036145516Sdarrenr 1037145516Sdarrenr 1038255332ScyINLINE int 1039255332Scyipf_checkv4sum(fin) 1040255332Scy fr_info_t *fin; 1041145516Sdarrenr{ 1042145516Sdarrenr#ifdef CSUM_DATA_VALID 1043145516Sdarrenr int manual = 0; 1044145516Sdarrenr u_short sum; 1045145516Sdarrenr ip_t *ip; 1046145516Sdarrenr mb_t *m; 1047145516Sdarrenr 1048145516Sdarrenr if ((fin->fin_flx & FI_NOCKSUM) != 0) 1049255332Scy return 0; 1050145516Sdarrenr 1051255332Scy if ((fin->fin_flx & FI_SHORT) != 0) 1052255332Scy return 1; 1053172776Sdarrenr 1054255332Scy if (fin->fin_cksum != FI_CK_NEEDED) 1055255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1056255332Scy 1057145516Sdarrenr m = fin->fin_m; 1058145516Sdarrenr if (m == NULL) { 1059145516Sdarrenr manual = 1; 1060145516Sdarrenr goto skipauto; 1061145516Sdarrenr } 1062145516Sdarrenr ip = fin->fin_ip; 1063145516Sdarrenr 1064255332Scy if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) == 1065255332Scy CSUM_IP_CHECKED) { 1066255332Scy fin->fin_cksum = FI_CK_BAD; 1067255332Scy fin->fin_flx |= FI_BAD; 1068297632Scy DT2(ipf_fi_bad_checkv4sum_csum_ip_checked, fr_info_t *, fin, u_int, m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)); 1069255332Scy return -1; 1070255332Scy } 1071145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 1072288910Scy /* Depending on the driver, UDP may have zero checksum */ 1073288910Scy if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx & 1074288910Scy (FI_FRAG|FI_SHORT|FI_BAD)) == 0) { 1075288910Scy udphdr_t *udp = fin->fin_dp; 1076288910Scy if (udp->uh_sum == 0) { 1077288910Scy /* 1078288910Scy * we're good no matter what the hardware 1079288910Scy * checksum flags and csum_data say (handling 1080288910Scy * of csum_data for zero UDP checksum is not 1081288910Scy * consistent across all drivers) 1082288910Scy */ 1083288910Scy fin->fin_cksum = 1; 1084288910Scy return 0; 1085288910Scy } 1086288910Scy } 1087288910Scy 1088145516Sdarrenr if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 1089145516Sdarrenr sum = m->m_pkthdr.csum_data; 1090145516Sdarrenr else 1091145516Sdarrenr sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 1092145516Sdarrenr htonl(m->m_pkthdr.csum_data + 1093255332Scy fin->fin_dlen + fin->fin_p)); 1094145516Sdarrenr sum ^= 0xffff; 1095172776Sdarrenr if (sum != 0) { 1096255332Scy fin->fin_cksum = FI_CK_BAD; 1097145516Sdarrenr fin->fin_flx |= FI_BAD; 1098297632Scy DT2(ipf_fi_bad_checkv4sum_sum, fr_info_t *, fin, u_int, sum); 1099172776Sdarrenr } else { 1100255332Scy fin->fin_cksum = FI_CK_SUMOK; 1101255332Scy return 0; 1102172776Sdarrenr } 1103255332Scy } else { 1104255332Scy if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) { 1105255332Scy fin->fin_cksum = FI_CK_L4FULL; 1106255332Scy return 0; 1107255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_TCP || 1108255332Scy m->m_pkthdr.csum_flags == CSUM_UDP) { 1109255332Scy fin->fin_cksum = FI_CK_L4PART; 1110255332Scy return 0; 1111255332Scy } else if (m->m_pkthdr.csum_flags == CSUM_IP) { 1112255332Scy fin->fin_cksum = FI_CK_L4PART; 1113255332Scy return 0; 1114255332Scy } else { 1115255332Scy manual = 1; 1116255332Scy } 1117255332Scy } 1118145516Sdarrenrskipauto: 1119255332Scy if (manual != 0) { 1120255332Scy if (ipf_checkl4sum(fin) == -1) { 1121145516Sdarrenr fin->fin_flx |= FI_BAD; 1122297632Scy DT2(ipf_fi_bad_checkv4sum_manual, fr_info_t *, fin, u_int, manual); 1123255332Scy return -1; 1124255332Scy } 1125255332Scy } 1126145516Sdarrenr#else 1127255332Scy if (ipf_checkl4sum(fin) == -1) { 1128145516Sdarrenr fin->fin_flx |= FI_BAD; 1129297632Scy DT2(ipf_fi_bad_checkv4sum_checkl4sum, fr_info_t *, fin, u_int, -1); 1130255332Scy return -1; 1131255332Scy } 1132145516Sdarrenr#endif 1133255332Scy return 0; 1134145516Sdarrenr} 1135145516Sdarrenr 1136145516Sdarrenr 1137145516Sdarrenr#ifdef USE_INET6 1138255332ScyINLINE int 1139255332Scyipf_checkv6sum(fin) 1140255332Scy fr_info_t *fin; 1141145516Sdarrenr{ 1142299870Scy if ((fin->fin_flx & FI_NOCKSUM) != 0) { 1143297632Scy DT(ipf_checkv6sum_fi_nocksum); 1144255332Scy return 0; 1145299870Scy } 1146255332Scy 1147299870Scy if ((fin->fin_flx & FI_SHORT) != 0) { 1148297632Scy DT(ipf_checkv6sum_fi_short); 1149255332Scy return 1; 1150299870Scy } 1151255332Scy 1152299870Scy if (fin->fin_cksum != FI_CK_NEEDED) { 1153297632Scy DT(ipf_checkv6sum_fi_ck_needed); 1154255332Scy return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1; 1155299870Scy } 1156255332Scy 1157255332Scy if (ipf_checkl4sum(fin) == -1) { 1158145516Sdarrenr fin->fin_flx |= FI_BAD; 1159297632Scy DT2(ipf_fi_bad_checkv6sum_checkl4sum, fr_info_t *, fin, u_int, -1); 1160255332Scy return -1; 1161255332Scy } 1162255332Scy return 0; 1163145516Sdarrenr} 1164145516Sdarrenr#endif /* USE_INET6 */ 1165145516Sdarrenr 1166145516Sdarrenr 1167255332Scysize_t 1168255332Scymbufchainlen(m0) 1169255332Scy struct mbuf *m0; 1170346982Scy{ 1171145516Sdarrenr size_t len; 1172145516Sdarrenr 1173145516Sdarrenr if ((m0->m_flags & M_PKTHDR) != 0) { 1174145516Sdarrenr len = m0->m_pkthdr.len; 1175145516Sdarrenr } else { 1176145516Sdarrenr struct mbuf *m; 1177145516Sdarrenr 1178145516Sdarrenr for (m = m0, len = 0; m != NULL; m = m->m_next) 1179145516Sdarrenr len += m->m_len; 1180145516Sdarrenr } 1181145516Sdarrenr return len; 1182145516Sdarrenr} 1183145516Sdarrenr 1184145516Sdarrenr 1185145516Sdarrenr/* ------------------------------------------------------------------------ */ 1186255332Scy/* Function: ipf_pullup */ 1187145516Sdarrenr/* Returns: NULL == pullup failed, else pointer to protocol header */ 1188255332Scy/* Parameters: xmin(I)- pointer to buffer where data packet starts */ 1189145516Sdarrenr/* fin(I) - pointer to packet information */ 1190145516Sdarrenr/* len(I) - number of bytes to pullup */ 1191145516Sdarrenr/* */ 1192145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */ 1193145516Sdarrenr/* single buffer for ease of access. Operating system native functions are */ 1194145516Sdarrenr/* used to manage buffers - if necessary. If the entire packet ends up in */ 1195255332Scy/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */ 1196145516Sdarrenr/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1197145516Sdarrenr/* and ONLY if the pullup succeeds. */ 1198145516Sdarrenr/* */ 1199255332Scy/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */ 1200145516Sdarrenr/* of buffers that starts at *fin->fin_mp. */ 1201145516Sdarrenr/* ------------------------------------------------------------------------ */ 1202255332Scyvoid * 1203255332Scyipf_pullup(xmin, fin, len) 1204255332Scy mb_t *xmin; 1205255332Scy fr_info_t *fin; 1206255332Scy int len; 1207145516Sdarrenr{ 1208255332Scy int dpoff, ipoff; 1209255332Scy mb_t *m = xmin; 1210145516Sdarrenr char *ip; 1211145516Sdarrenr 1212145516Sdarrenr if (m == NULL) 1213145516Sdarrenr return NULL; 1214145516Sdarrenr 1215145516Sdarrenr ip = (char *)fin->fin_ip; 1216145516Sdarrenr if ((fin->fin_flx & FI_COALESCE) != 0) 1217145516Sdarrenr return ip; 1218145516Sdarrenr 1219145516Sdarrenr ipoff = fin->fin_ipoff; 1220145516Sdarrenr if (fin->fin_dp != NULL) 1221145516Sdarrenr dpoff = (char *)fin->fin_dp - (char *)ip; 1222145516Sdarrenr else 1223145516Sdarrenr dpoff = 0; 1224145516Sdarrenr 1225145516Sdarrenr if (M_LEN(m) < len) { 1226255332Scy mb_t *n = *fin->fin_mp; 1227145516Sdarrenr /* 1228145516Sdarrenr * Assume that M_PKTHDR is set and just work with what is left 1229145516Sdarrenr * rather than check.. 1230145516Sdarrenr * Should not make any real difference, anyway. 1231145516Sdarrenr */ 1232255332Scy if (m != n) { 1233255332Scy /* 1234255332Scy * Record the mbuf that points to the mbuf that we're 1235255332Scy * about to go to work on so that we can update the 1236255332Scy * m_next appropriately later. 1237255332Scy */ 1238255332Scy for (; n->m_next != m; n = n->m_next) 1239255332Scy ; 1240255332Scy } else { 1241255332Scy n = NULL; 1242255332Scy } 1243255332Scy 1244255332Scy#ifdef MHLEN 1245145516Sdarrenr if (len > MHLEN) 1246145516Sdarrenr#else 1247145516Sdarrenr if (len > MLEN) 1248145516Sdarrenr#endif 1249145516Sdarrenr { 1250145516Sdarrenr#ifdef HAVE_M_PULLDOWN 1251145516Sdarrenr if (m_pulldown(m, 0, len, NULL) == NULL) 1252145516Sdarrenr m = NULL; 1253145516Sdarrenr#else 1254145516Sdarrenr FREE_MB_T(*fin->fin_mp); 1255145516Sdarrenr m = NULL; 1256255332Scy n = NULL; 1257145516Sdarrenr#endif 1258145516Sdarrenr } else 1259145516Sdarrenr { 1260145516Sdarrenr m = m_pullup(m, len); 1261145516Sdarrenr } 1262255332Scy if (n != NULL) 1263255332Scy n->m_next = m; 1264145516Sdarrenr if (m == NULL) { 1265255332Scy /* 1266255332Scy * When n is non-NULL, it indicates that m pointed to 1267255332Scy * a sub-chain (tail) of the mbuf and that the head 1268255332Scy * of this chain has not yet been free'd. 1269255332Scy */ 1270255332Scy if (n != NULL) { 1271255332Scy FREE_MB_T(*fin->fin_mp); 1272255332Scy } 1273255332Scy 1274255332Scy *fin->fin_mp = NULL; 1275172776Sdarrenr fin->fin_m = NULL; 1276145516Sdarrenr return NULL; 1277145516Sdarrenr } 1278172776Sdarrenr 1279255332Scy if (n == NULL) 1280255332Scy *fin->fin_mp = m; 1281255332Scy 1282172776Sdarrenr while (M_LEN(m) == 0) { 1283172776Sdarrenr m = m->m_next; 1284172776Sdarrenr } 1285172776Sdarrenr fin->fin_m = m; 1286145516Sdarrenr ip = MTOD(m, char *) + ipoff; 1287255332Scy 1288255332Scy fin->fin_ip = (ip_t *)ip; 1289255332Scy if (fin->fin_dp != NULL) 1290255332Scy fin->fin_dp = (char *)fin->fin_ip + dpoff; 1291255332Scy if (fin->fin_fraghdr != NULL) 1292255332Scy fin->fin_fraghdr = (char *)ip + 1293255332Scy ((char *)fin->fin_fraghdr - 1294255332Scy (char *)fin->fin_ip); 1295145516Sdarrenr } 1296145516Sdarrenr 1297145516Sdarrenr if (len == fin->fin_plen) 1298145516Sdarrenr fin->fin_flx |= FI_COALESCE; 1299145516Sdarrenr return ip; 1300145516Sdarrenr} 1301170268Sdarrenr 1302170268Sdarrenr 1303255332Scyint 1304255332Scyipf_inject(fin, m) 1305255332Scy fr_info_t *fin; 1306255332Scy mb_t *m; 1307170268Sdarrenr{ 1308170268Sdarrenr int error = 0; 1309170268Sdarrenr 1310170268Sdarrenr if (fin->fin_out == 0) { 1311170268Sdarrenr netisr_dispatch(NETISR_IP, m); 1312170268Sdarrenr } else { 1313173931Sdarrenr fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len); 1314173931Sdarrenr fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off); 1315170268Sdarrenr error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 1316170268Sdarrenr } 1317170268Sdarrenr 1318170268Sdarrenr return error; 1319170268Sdarrenr} 1320172776Sdarrenr 1321172776Sdarrenrint ipf_pfil_unhook(void) { 1322172776Sdarrenr struct pfil_head *ph_inet; 1323342607Scy#ifdef USE_INET6 1324172776Sdarrenr struct pfil_head *ph_inet6; 1325172776Sdarrenr#endif 1326172776Sdarrenr 1327172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1328172776Sdarrenr if (ph_inet != NULL) 1329255332Scy pfil_remove_hook((void *)ipf_check_wrapper, NULL, 1330172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1331172776Sdarrenr# ifdef USE_INET6 1332172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1333172776Sdarrenr if (ph_inet6 != NULL) 1334255332Scy pfil_remove_hook((void *)ipf_check_wrapper6, NULL, 1335172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1336172776Sdarrenr# endif 1337172776Sdarrenr 1338172776Sdarrenr return (0); 1339172776Sdarrenr} 1340172776Sdarrenr 1341172776Sdarrenrint ipf_pfil_hook(void) { 1342172776Sdarrenr struct pfil_head *ph_inet; 1343342607Scy#ifdef USE_INET6 1344172776Sdarrenr struct pfil_head *ph_inet6; 1345172776Sdarrenr#endif 1346172776Sdarrenr 1347172776Sdarrenr ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 1348172776Sdarrenr# ifdef USE_INET6 1349172776Sdarrenr ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 1350172776Sdarrenr# endif 1351172776Sdarrenr if (ph_inet == NULL 1352172776Sdarrenr# ifdef USE_INET6 1353172776Sdarrenr && ph_inet6 == NULL 1354172776Sdarrenr# endif 1355255332Scy ) { 1356172776Sdarrenr return ENODEV; 1357255332Scy } 1358172776Sdarrenr 1359172776Sdarrenr if (ph_inet != NULL) 1360255332Scy pfil_add_hook((void *)ipf_check_wrapper, NULL, 1361172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet); 1362172776Sdarrenr# ifdef USE_INET6 1363172776Sdarrenr if (ph_inet6 != NULL) 1364255332Scy pfil_add_hook((void *)ipf_check_wrapper6, NULL, 1365172776Sdarrenr PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6); 1366172776Sdarrenr# endif 1367172776Sdarrenr return (0); 1368172776Sdarrenr} 1369172776Sdarrenr 1370172776Sdarrenrvoid 1371172776Sdarrenripf_event_reg(void) 1372172776Sdarrenr{ 1373350669Scy ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ 1374302298Sbz ipf_ifevent, NULL, \ 1375172776Sdarrenr EVENTHANDLER_PRI_ANY); 1376350669Scy ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ 1377302298Sbz ipf_ifevent, NULL, \ 1378172776Sdarrenr EVENTHANDLER_PRI_ANY); 1379302298Sbz#if 0 1380350669Scy ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ 1381302298Sbz NULL, EVENTHANDLER_PRI_ANY); 1382302298Sbz#endif 1383172776Sdarrenr} 1384172776Sdarrenr 1385172776Sdarrenrvoid 1386172776Sdarrenripf_event_dereg(void) 1387172776Sdarrenr{ 1388350669Scy if (ipf_arrivetag != NULL) { 1389350669Scy EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); 1390172776Sdarrenr } 1391350669Scy if (ipf_departtag != NULL) { 1392350669Scy EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); 1393172776Sdarrenr } 1394302298Sbz#if 0 1395350669Scy if (ipf_clonetag != NULL) { 1396350669Scy EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); 1397172776Sdarrenr } 1398302298Sbz#endif 1399172776Sdarrenr} 1400255332Scy 1401255332Scy 1402255332Scyu_32_t 1403255332Scyipf_random() 1404255332Scy{ 1405255332Scy return arc4random(); 1406255332Scy} 1407255332Scy 1408255332Scy 1409255332Scyu_int 1410255332Scyipf_pcksum(fin, hlen, sum) 1411255332Scy fr_info_t *fin; 1412255332Scy int hlen; 1413255332Scy u_int sum; 1414255332Scy{ 1415255332Scy struct mbuf *m; 1416255332Scy u_int sum2; 1417255332Scy int off; 1418255332Scy 1419255332Scy m = fin->fin_m; 1420255332Scy off = (char *)fin->fin_dp - (char *)fin->fin_ip; 1421255332Scy m->m_data += hlen; 1422255332Scy m->m_len -= hlen; 1423255332Scy sum2 = in_cksum(fin->fin_m, fin->fin_plen - off); 1424255332Scy m->m_len += hlen; 1425255332Scy m->m_data -= hlen; 1426255332Scy 1427255332Scy /* 1428255332Scy * Both sum and sum2 are partial sums, so combine them together. 1429255332Scy */ 1430255332Scy sum += ~sum2 & 0xffff; 1431255332Scy while (sum > 0xffff) 1432255332Scy sum = (sum & 0xffff) + (sum >> 16); 1433255332Scy sum2 = ~sum & 0xffff; 1434255332Scy return sum2; 1435255332Scy} 1436355305Scy 1437355305Scy#ifdef USE_INET6 1438355305Scyu_int 1439355795Scyipf_pcksum6(m, ip6, off, len) 1440355795Scy struct mbuf *m; 1441355305Scy ip6_t *ip6; 1442355305Scy u_int32_t off; 1443355305Scy u_int32_t len; 1444355305Scy{ 1445355305Scy#ifdef _KERNEL 1446355305Scy int sum; 1447355305Scy 1448355305Scy if (m->m_len < sizeof(struct ip6_hdr)) { 1449355305Scy return 0xffff; 1450355305Scy } 1451355305Scy 1452355305Scy sum = in6_cksum(m, ip6->ip6_nxt, off, len); 1453355305Scy return(sum); 1454355305Scy#else 1455355305Scy u_short *sp; 1456355305Scy u_int sum; 1457355305Scy 1458355305Scy sp = (u_short *)&ip6->ip6_src; 1459355305Scy sum = *sp++; /* ip6_src */ 1460355305Scy sum += *sp++; 1461355305Scy sum += *sp++; 1462355305Scy sum += *sp++; 1463355305Scy sum += *sp++; 1464355305Scy sum += *sp++; 1465355305Scy sum += *sp++; 1466355305Scy sum += *sp++; 1467355305Scy sum += *sp++; /* ip6_dst */ 1468355305Scy sum += *sp++; 1469355305Scy sum += *sp++; 1470355305Scy sum += *sp++; 1471355305Scy sum += *sp++; 1472355305Scy sum += *sp++; 1473355305Scy sum += *sp++; 1474355305Scy sum += *sp++; 1475355305Scy return(ipf_pcksum(fin, off, sum)); 1476355305Scy#endif 1477355305Scy} 1478355305Scy#endif 1479