The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD$       */
    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 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
   10 static const char rcsid[] = "@(#)$Id$";
   11 #endif
   12 
   13 #if defined(KERNEL) || defined(_KERNEL)
   14 # undef KERNEL
   15 # undef _KERNEL
   16 # define        KERNEL  1
   17 # define        _KERNEL 1
   18 #endif
   19 #if defined(__FreeBSD__) && \
   20     !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
   21 # include "opt_inet6.h"
   22 #endif
   23 #include <sys/param.h>
   24 #include <sys/eventhandler.h>
   25 #include <sys/conf.h>
   26 #include <sys/errno.h>
   27 #include <sys/types.h>
   28 #include <sys/file.h>
   29 #include <sys/fcntl.h>
   30 #include <sys/filio.h>
   31 #include <sys/time.h>
   32 #include <sys/systm.h>
   33 #include <sys/dirent.h>
   34 #if defined(__FreeBSD__)
   35 # include <sys/jail.h>
   36 #endif
   37 #include <sys/malloc.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/sockopt.h>
   40 #include <sys/socket.h>
   41 #include <sys/selinfo.h>
   42 #include <net/if.h>
   43 #include <net/if_var.h>
   44 #include <net/netisr.h>
   45 #include <net/route.h>
   46 #include <net/route/nhop.h>
   47 #include <netinet/in.h>
   48 #include <netinet/in_fib.h>
   49 #include <netinet/in_pcb.h>
   50 #include <netinet/in_var.h>
   51 #include <netinet/in_systm.h>
   52 #include <netinet/ip.h>
   53 #include <netinet/ip_var.h>
   54 #include <netinet/tcp.h>
   55 #include <netinet/tcp_var.h>
   56 #include <net/vnet.h>
   57 #include <netinet/udp.h>
   58 #include <netinet/tcpip.h>
   59 #include <netinet/ip_icmp.h>
   60 #include "netinet/ip_compat.h"
   61 #ifdef USE_INET6
   62 # include <netinet/icmp6.h>
   63 #endif
   64 #include "netinet/ip_fil.h"
   65 #include "netinet/ip_nat.h"
   66 #include "netinet/ip_frag.h"
   67 #include "netinet/ip_state.h"
   68 #include "netinet/ip_proxy.h"
   69 #include "netinet/ip_auth.h"
   70 #include "netinet/ip_sync.h"
   71 #include "netinet/ip_lookup.h"
   72 #include "netinet/ip_dstlist.h"
   73 #ifdef  IPFILTER_SCAN
   74 # include "netinet/ip_scan.h"
   75 #endif
   76 #include "netinet/ip_pool.h"
   77 #include <sys/malloc.h>
   78 #include <sys/kernel.h>
   79 #ifdef CSUM_DATA_VALID
   80 # include <machine/in_cksum.h>
   81 #endif
   82 extern  int     ip_optcopy(struct ip *, struct ip *);
   83 
   84 #ifdef IPFILTER_M_IPFILTER
   85 MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
   86 #endif
   87 
   88 
   89 static  int     ipf_send_ip(fr_info_t *, mb_t *);
   90 static void     ipf_timer_func(void *arg);
   91 
   92 VNET_DEFINE(ipf_main_softc_t, ipfmain) = {
   93         .ipf_running            = -2,
   94 };
   95 #define V_ipfmain               VNET(ipfmain)
   96 
   97 #include <sys/conf.h>
   98 #include <net/pfil.h>
   99 
  100 VNET_DEFINE_STATIC(eventhandler_tag, ipf_arrivetag);
  101 VNET_DEFINE_STATIC(eventhandler_tag, ipf_departtag);
  102 #define V_ipf_arrivetag         VNET(ipf_arrivetag)
  103 #define V_ipf_departtag         VNET(ipf_departtag)
  104 #if 0
  105 /*
  106  * Disable the "cloner" event handler;  we are getting interface
  107  * events before the firewall is fully initiallized and also no vnet
  108  * information thus leading to uninitialised memory accesses.
  109  * In addition it is unclear why we need it in first place.
  110  * If it turns out to be needed, well need a dedicated event handler
  111  * for it to deal with the ifc and the correct vnet.
  112  */
  113 VNET_DEFINE_STATIC(eventhandler_tag, ipf_clonetag);
  114 #define V_ipf_clonetag          VNET(ipf_clonetag)
  115 #endif
  116 
  117 static void ipf_ifevent(void *arg, struct ifnet *ifp);
  118 
  119 static void ipf_ifevent(void *arg, struct ifnet *ifp)
  120 {
  121 
  122         CURVNET_SET(ifp->if_vnet);
  123         if (V_ipfmain.ipf_running > 0)
  124                 ipf_sync(&V_ipfmain, NULL);
  125         CURVNET_RESTORE();
  126 }
  127 
  128 
  129 
  130 static pfil_return_t
  131 ipf_check_wrapper(struct mbuf **mp, struct ifnet *ifp, int flags,
  132     void *ruleset __unused, struct inpcb *inp)
  133 {
  134         struct ip *ip = mtod(*mp, struct ip *);
  135         pfil_return_t rv;
  136 
  137         CURVNET_SET(ifp->if_vnet);
  138         rv = ipf_check(&V_ipfmain, ip, ip->ip_hl << 2, ifp,
  139             !!(flags & PFIL_OUT), mp);
  140         CURVNET_RESTORE();
  141         return (rv == 0 ? PFIL_PASS : PFIL_DROPPED);
  142 }
  143 
  144 #ifdef USE_INET6
  145 static pfil_return_t
  146 ipf_check_wrapper6(struct mbuf **mp, struct ifnet *ifp, int flags,
  147     void *ruleset __unused, struct inpcb *inp)
  148 {
  149         pfil_return_t rv;
  150 
  151         CURVNET_SET(ifp->if_vnet);
  152         rv = ipf_check(&V_ipfmain, mtod(*mp, struct ip *),
  153             sizeof(struct ip6_hdr), ifp, !!(flags & PFIL_OUT), mp);
  154         CURVNET_RESTORE();
  155 
  156         return (rv == 0 ? PFIL_PASS : PFIL_DROPPED);
  157 }
  158 # endif
  159 #if     defined(IPFILTER_LKM)
  160 int ipf_identify(char *s)
  161 {
  162         if (strcmp(s, "ipl") == 0)
  163                 return (1);
  164         return (0);
  165 }
  166 #endif /* IPFILTER_LKM */
  167 
  168 
  169 static void
  170 ipf_timer_func(void *arg)
  171 {
  172         ipf_main_softc_t *softc = arg;
  173         SPL_INT(s);
  174 
  175         SPL_NET(s);
  176         READ_ENTER(&softc->ipf_global);
  177 
  178         if (softc->ipf_running > 0)
  179                 ipf_slowtimer(softc);
  180 
  181         if (softc->ipf_running == -1 || softc->ipf_running == 1) {
  182 #if 0
  183                 softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
  184 #endif
  185                 callout_init(&softc->ipf_slow_ch, 1);
  186                 callout_reset(&softc->ipf_slow_ch,
  187                         (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
  188                         ipf_timer_func, softc);
  189         }
  190         RWLOCK_EXIT(&softc->ipf_global);
  191         SPL_X(s);
  192 }
  193 
  194 
  195 int
  196 ipfattach(ipf_main_softc_t *softc)
  197 {
  198 #ifdef USE_SPL
  199         int s;
  200 #endif
  201 
  202         SPL_NET(s);
  203         if (softc->ipf_running > 0) {
  204                 SPL_X(s);
  205                 return (EBUSY);
  206         }
  207 
  208         if (ipf_init_all(softc) < 0) {
  209                 SPL_X(s);
  210                 return (EIO);
  211         }
  212 
  213 
  214         bzero((char *)V_ipfmain.ipf_selwait, sizeof(V_ipfmain.ipf_selwait));
  215         softc->ipf_running = 1;
  216 
  217         if (softc->ipf_control_forwarding & 1)
  218                 V_ipforwarding = 1;
  219 
  220         SPL_X(s);
  221 #if 0
  222         softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
  223                                      (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
  224 #endif
  225         callout_init(&softc->ipf_slow_ch, 1);
  226         callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
  227                 ipf_timer_func, softc);
  228         return (0);
  229 }
  230 
  231 
  232 /*
  233  * Disable the filter by removing the hooks from the IP input/output
  234  * stream.
  235  */
  236 int
  237 ipfdetach(ipf_main_softc_t *softc)
  238 {
  239 #ifdef USE_SPL
  240         int s;
  241 #endif
  242 
  243         if (softc->ipf_control_forwarding & 2)
  244                 V_ipforwarding = 0;
  245 
  246         SPL_NET(s);
  247 
  248 #if 0
  249         if (softc->ipf_slow_ch.callout != NULL)
  250                 untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
  251         bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
  252 #endif
  253         callout_drain(&softc->ipf_slow_ch);
  254 
  255         ipf_fini_all(softc);
  256 
  257         softc->ipf_running = -2;
  258 
  259         SPL_X(s);
  260 
  261         return (0);
  262 }
  263 
  264 
  265 /*
  266  * Filter ioctl interface.
  267  */
  268 int
  269 ipfioctl(struct cdev *dev, ioctlcmd_t cmd, caddr_t data,
  270         int mode, struct thread *p)
  271 #define p_cred  td_ucred
  272 #define p_uid   td_ucred->cr_ruid
  273 {
  274         int error = 0, unit = 0;
  275         SPL_INT(s);
  276 
  277         CURVNET_SET(TD_TO_VNET(p));
  278         if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
  279         {
  280                 V_ipfmain.ipf_interror = 130001;
  281                 CURVNET_RESTORE();
  282                 return (EPERM);
  283         }
  284 
  285         if (jailed_without_vnet(p->p_cred)) {
  286                 V_ipfmain.ipf_interror = 130018;
  287                 CURVNET_RESTORE();
  288                 return (EOPNOTSUPP);
  289         }
  290 
  291         unit = GET_MINOR(dev);
  292         if ((IPL_LOGMAX < unit) || (unit < 0)) {
  293                 V_ipfmain.ipf_interror = 130002;
  294                 CURVNET_RESTORE();
  295                 return (ENXIO);
  296         }
  297 
  298         if (V_ipfmain.ipf_running <= 0) {
  299                 if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
  300                         V_ipfmain.ipf_interror = 130003;
  301                         CURVNET_RESTORE();
  302                         return (EIO);
  303                 }
  304                 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
  305                     cmd != SIOCIPFSET && cmd != SIOCFRENB &&
  306                     cmd != SIOCGETFS && cmd != SIOCGETFF &&
  307                     cmd != SIOCIPFINTERROR) {
  308                         V_ipfmain.ipf_interror = 130004;
  309                         CURVNET_RESTORE();
  310                         return (EIO);
  311                 }
  312         }
  313 
  314         SPL_NET(s);
  315 
  316         error = ipf_ioctlswitch(&V_ipfmain, unit, data, cmd, mode, p->p_uid, p);
  317         CURVNET_RESTORE();
  318         if (error != -1) {
  319                 SPL_X(s);
  320                 return (error);
  321         }
  322 
  323         SPL_X(s);
  324 
  325         return (error);
  326 }
  327 
  328 
  329 /*
  330  * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
  331  * requires a large amount of setting up and isn't any more efficient.
  332  */
  333 int
  334 ipf_send_reset(fr_info_t *fin)
  335 {
  336         struct tcphdr *tcp, *tcp2;
  337         int tlen = 0, hlen;
  338         struct mbuf *m;
  339 #ifdef USE_INET6
  340         ip6_t *ip6;
  341 #endif
  342         ip_t *ip;
  343 
  344         tcp = fin->fin_dp;
  345         if (tcp->th_flags & TH_RST)
  346                 return (-1);            /* feedback loop */
  347 
  348         if (ipf_checkl4sum(fin) == -1)
  349                 return (-1);
  350 
  351         tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
  352                         ((tcp->th_flags & TH_SYN) ? 1 : 0) +
  353                         ((tcp->th_flags & TH_FIN) ? 1 : 0);
  354 
  355 #ifdef USE_INET6
  356         hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
  357 #else
  358         hlen = sizeof(ip_t);
  359 #endif
  360 #ifdef MGETHDR
  361         MGETHDR(m, M_NOWAIT, MT_HEADER);
  362 #else
  363         MGET(m, M_NOWAIT, MT_HEADER);
  364 #endif
  365         if (m == NULL)
  366                 return (-1);
  367         if (sizeof(*tcp2) + hlen > MLEN) {
  368                 if (!(MCLGET(m, M_NOWAIT))) {
  369                         FREE_MB_T(m);
  370                         return (-1);
  371                 }
  372         }
  373 
  374         m->m_len = sizeof(*tcp2) + hlen;
  375         m->m_data += max_linkhdr;
  376         m->m_pkthdr.len = m->m_len;
  377         m->m_pkthdr.rcvif = (struct ifnet *)0;
  378         ip = mtod(m, struct ip *);
  379         bzero((char *)ip, hlen);
  380 #ifdef USE_INET6
  381         ip6 = (ip6_t *)ip;
  382 #endif
  383         tcp2 = (struct tcphdr *)((char *)ip + hlen);
  384         tcp2->th_sport = tcp->th_dport;
  385         tcp2->th_dport = tcp->th_sport;
  386 
  387         if (tcp->th_flags & TH_ACK) {
  388                 tcp2->th_seq = tcp->th_ack;
  389                 tcp2->th_flags = TH_RST;
  390                 tcp2->th_ack = 0;
  391         } else {
  392                 tcp2->th_seq = 0;
  393                 tcp2->th_ack = ntohl(tcp->th_seq);
  394                 tcp2->th_ack += tlen;
  395                 tcp2->th_ack = htonl(tcp2->th_ack);
  396                 tcp2->th_flags = TH_RST|TH_ACK;
  397         }
  398         TCP_X2_A(tcp2, 0);
  399         TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
  400         tcp2->th_win = tcp->th_win;
  401         tcp2->th_sum = 0;
  402         tcp2->th_urp = 0;
  403 
  404 #ifdef USE_INET6
  405         if (fin->fin_v == 6) {
  406                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
  407                 ip6->ip6_plen = htons(sizeof(struct tcphdr));
  408                 ip6->ip6_nxt = IPPROTO_TCP;
  409                 ip6->ip6_hlim = 0;
  410                 ip6->ip6_src = fin->fin_dst6.in6;
  411                 ip6->ip6_dst = fin->fin_src6.in6;
  412                 tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
  413                                          sizeof(*ip6), sizeof(*tcp2));
  414                 return (ipf_send_ip(fin, m));
  415         }
  416 #endif
  417         ip->ip_p = IPPROTO_TCP;
  418         ip->ip_len = htons(sizeof(struct tcphdr));
  419         ip->ip_src.s_addr = fin->fin_daddr;
  420         ip->ip_dst.s_addr = fin->fin_saddr;
  421         tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
  422         ip->ip_len = htons(hlen + sizeof(*tcp2));
  423         return (ipf_send_ip(fin, m));
  424 }
  425 
  426 
  427 /*
  428  * ip_len must be in network byte order when called.
  429  */
  430 static int
  431 ipf_send_ip(fr_info_t *fin, mb_t *m)
  432 {
  433         fr_info_t fnew;
  434         ip_t *ip, *oip;
  435         int hlen;
  436 
  437         ip = mtod(m, ip_t *);
  438         bzero((char *)&fnew, sizeof(fnew));
  439         fnew.fin_main_soft = fin->fin_main_soft;
  440 
  441         IP_V_A(ip, fin->fin_v);
  442         switch (fin->fin_v)
  443         {
  444         case 4 :
  445                 oip = fin->fin_ip;
  446                 hlen = sizeof(*oip);
  447                 fnew.fin_v = 4;
  448                 fnew.fin_p = ip->ip_p;
  449                 fnew.fin_plen = ntohs(ip->ip_len);
  450                 IP_HL_A(ip, sizeof(*oip) >> 2);
  451                 ip->ip_tos = oip->ip_tos;
  452                 ip->ip_id = fin->fin_ip->ip_id;
  453                 ip->ip_off = htons(V_path_mtu_discovery ? IP_DF : 0);
  454                 ip->ip_ttl = V_ip_defttl;
  455                 ip->ip_sum = 0;
  456                 break;
  457 #ifdef USE_INET6
  458         case 6 :
  459         {
  460                 ip6_t *ip6 = (ip6_t *)ip;
  461 
  462                 ip6->ip6_vfc = 0x60;
  463                 ip6->ip6_hlim = IPDEFTTL;
  464 
  465                 hlen = sizeof(*ip6);
  466                 fnew.fin_p = ip6->ip6_nxt;
  467                 fnew.fin_v = 6;
  468                 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
  469                 break;
  470         }
  471 #endif
  472         default :
  473                 return (EINVAL);
  474         }
  475 #ifdef IPSEC_SUPPORT
  476         m->m_pkthdr.rcvif = NULL;
  477 #endif
  478 
  479         fnew.fin_ifp = fin->fin_ifp;
  480         fnew.fin_flx = FI_NOCKSUM;
  481         fnew.fin_m = m;
  482         fnew.fin_ip = ip;
  483         fnew.fin_mp = &m;
  484         fnew.fin_hlen = hlen;
  485         fnew.fin_dp = (char *)ip + hlen;
  486         (void) ipf_makefrip(hlen, ip, &fnew);
  487 
  488         return (ipf_fastroute(m, &m, &fnew, NULL));
  489 }
  490 
  491 
  492 int
  493 ipf_send_icmp_err(int type, fr_info_t *fin, int dst)
  494 {
  495         int err, hlen, xtra, iclen, ohlen, avail, code;
  496         struct in_addr dst4;
  497         struct icmp *icmp;
  498         struct mbuf *m;
  499         i6addr_t dst6;
  500         void *ifp;
  501 #ifdef USE_INET6
  502         ip6_t *ip6;
  503 #endif
  504         ip_t *ip, *ip2;
  505 
  506         if ((type < 0) || (type >= ICMP_MAXTYPE))
  507                 return (-1);
  508 
  509         code = fin->fin_icode;
  510 #ifdef USE_INET6
  511         /* See NetBSD ip_fil_netbsd.c r1.4: */
  512         if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
  513                 return (-1);
  514 #endif
  515 
  516         if (ipf_checkl4sum(fin) == -1)
  517                 return (-1);
  518 #ifdef MGETHDR
  519         MGETHDR(m, M_NOWAIT, MT_HEADER);
  520 #else
  521         MGET(m, M_NOWAIT, MT_HEADER);
  522 #endif
  523         if (m == NULL)
  524                 return (-1);
  525         avail = MHLEN;
  526 
  527         xtra = 0;
  528         hlen = 0;
  529         ohlen = 0;
  530         dst4.s_addr = 0;
  531         ifp = fin->fin_ifp;
  532         if (fin->fin_v == 4) {
  533                 if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
  534                         switch (ntohs(fin->fin_data[0]) >> 8)
  535                         {
  536                         case ICMP_ECHO :
  537                         case ICMP_TSTAMP :
  538                         case ICMP_IREQ :
  539                         case ICMP_MASKREQ :
  540                                 break;
  541                         default :
  542                                 FREE_MB_T(m);
  543                                 return (0);
  544                         }
  545 
  546                 if (dst == 0) {
  547                         if (ipf_ifpaddr(&V_ipfmain, 4, FRI_NORMAL, ifp,
  548                                         &dst6, NULL) == -1) {
  549                                 FREE_MB_T(m);
  550                                 return (-1);
  551                         }
  552                         dst4 = dst6.in4;
  553                 } else
  554                         dst4.s_addr = fin->fin_daddr;
  555 
  556                 hlen = sizeof(ip_t);
  557                 ohlen = fin->fin_hlen;
  558                 iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
  559                 if (fin->fin_hlen < fin->fin_plen)
  560                         xtra = MIN(fin->fin_dlen, 8);
  561                 else
  562                         xtra = 0;
  563         }
  564 
  565 #ifdef USE_INET6
  566         else if (fin->fin_v == 6) {
  567                 hlen = sizeof(ip6_t);
  568                 ohlen = sizeof(ip6_t);
  569                 iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
  570                 type = icmptoicmp6types[type];
  571                 if (type == ICMP6_DST_UNREACH)
  572                         code = icmptoicmp6unreach[code];
  573 
  574                 if (iclen + max_linkhdr + fin->fin_plen > avail) {
  575                         if (!(MCLGET(m, M_NOWAIT))) {
  576                                 FREE_MB_T(m);
  577                                 return (-1);
  578                         }
  579                         avail = MCLBYTES;
  580                 }
  581                 xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
  582                 xtra = MIN(xtra, IPV6_MMTU - iclen);
  583                 if (dst == 0) {
  584                         if (ipf_ifpaddr(&V_ipfmain, 6, FRI_NORMAL, ifp,
  585                                         &dst6, NULL) == -1) {
  586                                 FREE_MB_T(m);
  587                                 return (-1);
  588                         }
  589                 } else
  590                         dst6 = fin->fin_dst6;
  591         }
  592 #endif
  593         else {
  594                 FREE_MB_T(m);
  595                 return (-1);
  596         }
  597 
  598         avail -= (max_linkhdr + iclen);
  599         if (avail < 0) {
  600                 FREE_MB_T(m);
  601                 return (-1);
  602         }
  603         if (xtra > avail)
  604                 xtra = avail;
  605         iclen += xtra;
  606         m->m_data += max_linkhdr;
  607         m->m_pkthdr.rcvif = (struct ifnet *)0;
  608         m->m_pkthdr.len = iclen;
  609         m->m_len = iclen;
  610         ip = mtod(m, ip_t *);
  611         icmp = (struct icmp *)((char *)ip + hlen);
  612         ip2 = (ip_t *)&icmp->icmp_ip;
  613 
  614         icmp->icmp_type = type;
  615         icmp->icmp_code = fin->fin_icode;
  616         icmp->icmp_cksum = 0;
  617 #ifdef icmp_nextmtu
  618         if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
  619                 if (fin->fin_mtu != 0) {
  620                         icmp->icmp_nextmtu = htons(fin->fin_mtu);
  621 
  622                 } else if (ifp != NULL) {
  623                         icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
  624 
  625                 } else {        /* make up a number... */
  626                         icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
  627                 }
  628         }
  629 #endif
  630 
  631         bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
  632 
  633 #ifdef USE_INET6
  634         ip6 = (ip6_t *)ip;
  635         if (fin->fin_v == 6) {
  636                 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
  637                 ip6->ip6_plen = htons(iclen - hlen);
  638                 ip6->ip6_nxt = IPPROTO_ICMPV6;
  639                 ip6->ip6_hlim = 0;
  640                 ip6->ip6_src = dst6.in6;
  641                 ip6->ip6_dst = fin->fin_src6.in6;
  642                 if (xtra > 0)
  643                         bcopy((char *)fin->fin_ip + ohlen,
  644                               (char *)&icmp->icmp_ip + ohlen, xtra);
  645                 icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
  646                                              sizeof(*ip6), iclen - hlen);
  647         } else
  648 #endif
  649         {
  650                 ip->ip_p = IPPROTO_ICMP;
  651                 ip->ip_src.s_addr = dst4.s_addr;
  652                 ip->ip_dst.s_addr = fin->fin_saddr;
  653 
  654                 if (xtra > 0)
  655                         bcopy((char *)fin->fin_ip + ohlen,
  656                               (char *)&icmp->icmp_ip + ohlen, xtra);
  657                 icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
  658                                              sizeof(*icmp) + 8);
  659                 ip->ip_len = htons(iclen);
  660                 ip->ip_p = IPPROTO_ICMP;
  661         }
  662         err = ipf_send_ip(fin, m);
  663         return (err);
  664 }
  665 
  666 
  667 
  668 
  669 /*
  670  * m0 - pointer to mbuf where the IP packet starts
  671  * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
  672  */
  673 int
  674 ipf_fastroute(mb_t *m0, mb_t **mpp, fr_info_t *fin, frdest_t *fdp)
  675 {
  676         register struct ip *ip, *mhip;
  677         register struct mbuf *m = *mpp;
  678         int len, off, error = 0, hlen, code;
  679         struct ifnet *ifp, *sifp;
  680         struct route ro;
  681         struct sockaddr_in *dst;
  682         const struct sockaddr *gw;
  683         struct nhop_object *nh;
  684         u_long fibnum = 0;
  685         u_short ip_off;
  686         frdest_t node;
  687         frentry_t *fr;
  688 
  689 #ifdef M_WRITABLE
  690         /*
  691         * HOT FIX/KLUDGE:
  692         *
  693         * If the mbuf we're about to send is not writable (because of
  694         * a cluster reference, for example) we'll need to make a copy
  695         * of it since this routine modifies the contents.
  696         *
  697         * If you have non-crappy network hardware that can transmit data
  698         * from the mbuf, rather than making a copy, this is gonna be a
  699         * problem.
  700         */
  701         if (M_WRITABLE(m) == 0) {
  702                 m0 = m_dup(m, M_NOWAIT);
  703                 if (m0 != NULL) {
  704                         FREE_MB_T(m);
  705                         m = m0;
  706                         *mpp = m;
  707                 } else {
  708                         error = ENOBUFS;
  709                         FREE_MB_T(m);
  710                         goto done;
  711                 }
  712         }
  713 #endif
  714 
  715 #ifdef USE_INET6
  716         if (fin->fin_v == 6) {
  717                 /*
  718                  * currently "to <if>" and "to <if>:ip#" are not supported
  719                  * for IPv6
  720                  */
  721                 return (ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL));
  722         }
  723 #endif
  724 
  725         hlen = fin->fin_hlen;
  726         ip = mtod(m0, struct ip *);
  727         ifp = NULL;
  728 
  729         /*
  730          * Route packet.
  731          */
  732         bzero(&ro, sizeof (ro));
  733         dst = (struct sockaddr_in *)&ro.ro_dst;
  734         dst->sin_family = AF_INET;
  735         dst->sin_addr = ip->ip_dst;
  736         dst->sin_len = sizeof(dst);
  737         gw = (const struct sockaddr *)dst;
  738 
  739         fr = fin->fin_fr;
  740         if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
  741             (fdp->fd_type == FRD_DSTLIST)) {
  742                 if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
  743                         fdp = &node;
  744         }
  745 
  746         if (fdp != NULL)
  747                 ifp = fdp->fd_ptr;
  748         else
  749                 ifp = fin->fin_ifp;
  750 
  751         if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
  752                 error = -2;
  753                 goto bad;
  754         }
  755 
  756         if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
  757                 dst->sin_addr = fdp->fd_ip;
  758 
  759         fibnum = M_GETFIB(m0);
  760         NET_EPOCH_ASSERT();
  761         nh = fib4_lookup(fibnum, dst->sin_addr, 0, NHR_NONE, 0);
  762         if (nh == NULL) {
  763                 if (in_localaddr(ip->ip_dst))
  764                         error = EHOSTUNREACH;
  765                 else
  766                         error = ENETUNREACH;
  767                 goto bad;
  768         }
  769 
  770         if (ifp == NULL)
  771                 ifp = nh->nh_ifp;
  772         if (nh->nh_flags & NHF_GATEWAY) {
  773                 gw = &nh->gw_sa;
  774                 ro.ro_flags |= RT_HAS_GW;
  775         }
  776 
  777         /*
  778          * For input packets which are being "fastrouted", they won't
  779          * go back through output filtering and miss their chance to get
  780          * NAT'd and counted.  Duplicated packets aren't considered to be
  781          * part of the normal packet stream, so do not NAT them or pass
  782          * them through stateful checking, etc.
  783          */
  784         if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
  785                 sifp = fin->fin_ifp;
  786                 fin->fin_ifp = ifp;
  787                 fin->fin_out = 1;
  788                 (void) ipf_acctpkt(fin, NULL);
  789                 fin->fin_fr = NULL;
  790                 if (!fr || !(fr->fr_flags & FR_RETMASK)) {
  791                         u_32_t pass;
  792 
  793                         (void) ipf_state_check(fin, &pass);
  794                 }
  795 
  796                 switch (ipf_nat_checkout(fin, NULL))
  797                 {
  798                 case 0 :
  799                         break;
  800                 case 1 :
  801                         ip->ip_sum = 0;
  802                         break;
  803                 case -1 :
  804                         error = -1;
  805                         goto bad;
  806                         break;
  807                 }
  808 
  809                 fin->fin_ifp = sifp;
  810                 fin->fin_out = 0;
  811         } else
  812                 ip->ip_sum = 0;
  813         /*
  814          * If small enough for interface, can just send directly.
  815          */
  816         if (ntohs(ip->ip_len) <= ifp->if_mtu) {
  817                 if (!ip->ip_sum)
  818                         ip->ip_sum = in_cksum(m, hlen);
  819                 error = (*ifp->if_output)(ifp, m, gw, &ro);
  820                 goto done;
  821         }
  822         /*
  823          * Too large for interface; fragment if possible.
  824          * Must be able to put at least 8 bytes per fragment.
  825          */
  826         ip_off = ntohs(ip->ip_off);
  827         if (ip_off & IP_DF) {
  828                 error = EMSGSIZE;
  829                 goto bad;
  830         }
  831         len = (ifp->if_mtu - hlen) &~ 7;
  832         if (len < 8) {
  833                 error = EMSGSIZE;
  834                 goto bad;
  835         }
  836 
  837     {
  838         int mhlen, firstlen = len;
  839         struct mbuf **mnext = &m->m_act;
  840 
  841         /*
  842          * Loop through length of segment after first fragment,
  843          * make new header and copy data of each part and link onto chain.
  844          */
  845         m0 = m;
  846         mhlen = sizeof (struct ip);
  847         for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
  848 #ifdef MGETHDR
  849                 MGETHDR(m, M_NOWAIT, MT_HEADER);
  850 #else
  851                 MGET(m, M_NOWAIT, MT_HEADER);
  852 #endif
  853                 if (m == NULL) {
  854                         m = m0;
  855                         error = ENOBUFS;
  856                         goto bad;
  857                 }
  858                 m->m_data += max_linkhdr;
  859                 mhip = mtod(m, struct ip *);
  860                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
  861                 if (hlen > sizeof (struct ip)) {
  862                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
  863                         IP_HL_A(mhip, mhlen >> 2);
  864                 }
  865                 m->m_len = mhlen;
  866                 mhip->ip_off = ((off - hlen) >> 3) + ip_off;
  867                 if (off + len >= ntohs(ip->ip_len))
  868                         len = ntohs(ip->ip_len) - off;
  869                 else
  870                         mhip->ip_off |= IP_MF;
  871                 mhip->ip_len = htons((u_short)(len + mhlen));
  872                 *mnext = m;
  873                 m->m_next = m_copym(m0, off, len, M_NOWAIT);
  874                 if (m->m_next == 0) {
  875                         error = ENOBUFS;        /* ??? */
  876                         goto sendorfree;
  877                 }
  878                 m->m_pkthdr.len = mhlen + len;
  879                 m->m_pkthdr.rcvif = NULL;
  880                 mhip->ip_off = htons((u_short)mhip->ip_off);
  881                 mhip->ip_sum = 0;
  882                 mhip->ip_sum = in_cksum(m, mhlen);
  883                 mnext = &m->m_act;
  884         }
  885         /*
  886          * Update first fragment by trimming what's been copied out
  887          * and updating header, then send each fragment (in order).
  888          */
  889         m_adj(m0, hlen + firstlen - ip->ip_len);
  890         ip->ip_len = htons((u_short)(hlen + firstlen));
  891         ip->ip_off = htons((u_short)IP_MF);
  892         ip->ip_sum = 0;
  893         ip->ip_sum = in_cksum(m0, hlen);
  894 sendorfree:
  895         for (m = m0; m; m = m0) {
  896                 m0 = m->m_act;
  897                 m->m_act = 0;
  898                 if (error == 0)
  899                         error = (*ifp->if_output)(ifp, m, gw, &ro);
  900                 else
  901                         FREE_MB_T(m);
  902         }
  903     }
  904 done:
  905         if (!error)
  906                 V_ipfmain.ipf_frouteok[0]++;
  907         else
  908                 V_ipfmain.ipf_frouteok[1]++;
  909 
  910         return (0);
  911 bad:
  912         if (error == EMSGSIZE) {
  913                 sifp = fin->fin_ifp;
  914                 code = fin->fin_icode;
  915                 fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
  916                 fin->fin_ifp = ifp;
  917                 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
  918                 fin->fin_ifp = sifp;
  919                 fin->fin_icode = code;
  920         }
  921         FREE_MB_T(m);
  922         goto done;
  923 }
  924 
  925 
  926 int
  927 ipf_verifysrc(fin)
  928         fr_info_t *fin;
  929 {
  930         struct nhop_object *nh;
  931 
  932         NET_EPOCH_ASSERT();
  933         nh = fib4_lookup(RT_DEFAULT_FIB, fin->fin_src, 0, NHR_NONE, 0);
  934         if (nh == NULL)
  935                 return (0);
  936         return (fin->fin_ifp == nh->nh_ifp);
  937 }
  938 
  939 
  940 /*
  941  * return the first IP Address associated with an interface
  942  */
  943 int
  944 ipf_ifpaddr(ipf_main_softc_t *softc, int v, int atype, void *ifptr,
  945         i6addr_t *inp, i6addr_t *inpmask)
  946 {
  947 #ifdef USE_INET6
  948         struct in6_addr *ia6 = NULL;
  949 #endif
  950         struct sockaddr *sock, *mask;
  951         struct sockaddr_in *sin;
  952         struct ifaddr *ifa;
  953         struct ifnet *ifp;
  954 
  955         if ((ifptr == NULL) || (ifptr == (void *)-1))
  956                 return (-1);
  957 
  958         sin = NULL;
  959         ifp = ifptr;
  960 
  961         if (v == 4)
  962                 inp->in4.s_addr = 0;
  963 #ifdef USE_INET6
  964         else if (v == 6)
  965                 bzero((char *)inp, sizeof(*inp));
  966 #endif
  967         ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
  968 
  969         sock = ifa->ifa_addr;
  970         while (sock != NULL && ifa != NULL) {
  971                 sin = (struct sockaddr_in *)sock;
  972                 if ((v == 4) && (sin->sin_family == AF_INET))
  973                         break;
  974 #ifdef USE_INET6
  975                 if ((v == 6) && (sin->sin_family == AF_INET6)) {
  976                         ia6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
  977                         if (!IN6_IS_ADDR_LINKLOCAL(ia6) &&
  978                             !IN6_IS_ADDR_LOOPBACK(ia6))
  979                                 break;
  980                 }
  981 #endif
  982                 ifa = CK_STAILQ_NEXT(ifa, ifa_link);
  983                 if (ifa != NULL)
  984                         sock = ifa->ifa_addr;
  985         }
  986 
  987         if (ifa == NULL || sin == NULL)
  988                 return (-1);
  989 
  990         mask = ifa->ifa_netmask;
  991         if (atype == FRI_BROADCAST)
  992                 sock = ifa->ifa_broadaddr;
  993         else if (atype == FRI_PEERADDR)
  994                 sock = ifa->ifa_dstaddr;
  995 
  996         if (sock == NULL)
  997                 return (-1);
  998 
  999 #ifdef USE_INET6
 1000         if (v == 6) {
 1001                 return (ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
 1002                                          (struct sockaddr_in6 *)mask,
 1003                                          inp, inpmask));
 1004         }
 1005 #endif
 1006         return (ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
 1007                                  (struct sockaddr_in *)mask,
 1008                                  &inp->in4, &inpmask->in4));
 1009 }
 1010 
 1011 
 1012 u_32_t
 1013 ipf_newisn(fin)
 1014         fr_info_t *fin;
 1015 {
 1016         u_32_t newiss;
 1017         newiss = arc4random();
 1018         return (newiss);
 1019 }
 1020 
 1021 
 1022 int
 1023 ipf_checkv4sum(fr_info_t *fin)
 1024 {
 1025 #ifdef CSUM_DATA_VALID
 1026         int manual = 0;
 1027         u_short sum;
 1028         ip_t *ip;
 1029         mb_t *m;
 1030 
 1031         if ((fin->fin_flx & FI_NOCKSUM) != 0)
 1032                 return (0);
 1033 
 1034         if ((fin->fin_flx & FI_SHORT) != 0)
 1035                 return (1);
 1036 
 1037         if (fin->fin_cksum != FI_CK_NEEDED)
 1038                 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
 1039 
 1040         m = fin->fin_m;
 1041         if (m == NULL) {
 1042                 manual = 1;
 1043                 goto skipauto;
 1044         }
 1045         ip = fin->fin_ip;
 1046 
 1047         if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
 1048             CSUM_IP_CHECKED) {
 1049                 fin->fin_cksum = FI_CK_BAD;
 1050                 fin->fin_flx |= FI_BAD;
 1051                 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));
 1052                 return (-1);
 1053         }
 1054         if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
 1055                 /* Depending on the driver, UDP may have zero checksum */
 1056                 if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
 1057                     (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
 1058                         udphdr_t *udp = fin->fin_dp;
 1059                         if (udp->uh_sum == 0) {
 1060                                 /*
 1061                                  * we're good no matter what the hardware
 1062                                  * checksum flags and csum_data say (handling
 1063                                  * of csum_data for zero UDP checksum is not
 1064                                  * consistent across all drivers)
 1065                                  */
 1066                                 fin->fin_cksum = 1;
 1067                                 return (0);
 1068                         }
 1069                 }
 1070 
 1071                 if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
 1072                         sum = m->m_pkthdr.csum_data;
 1073                 else
 1074                         sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
 1075                                         htonl(m->m_pkthdr.csum_data +
 1076                                         fin->fin_dlen + fin->fin_p));
 1077                 sum ^= 0xffff;
 1078                 if (sum != 0) {
 1079                         fin->fin_cksum = FI_CK_BAD;
 1080                         fin->fin_flx |= FI_BAD;
 1081                         DT2(ipf_fi_bad_checkv4sum_sum, fr_info_t *, fin, u_int, sum);
 1082                 } else {
 1083                         fin->fin_cksum = FI_CK_SUMOK;
 1084                         return (0);
 1085                 }
 1086         } else {
 1087                 if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
 1088                         fin->fin_cksum = FI_CK_L4FULL;
 1089                         return (0);
 1090                 } else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
 1091                            m->m_pkthdr.csum_flags == CSUM_UDP ||
 1092                            m->m_pkthdr.csum_flags == CSUM_IP) {
 1093                         fin->fin_cksum = FI_CK_L4PART;
 1094                         return (0);
 1095                 } else {
 1096                         manual = 1;
 1097                 }
 1098         }
 1099 skipauto:
 1100         if (manual != 0) {
 1101                 if (ipf_checkl4sum(fin) == -1) {
 1102                         fin->fin_flx |= FI_BAD;
 1103                         DT2(ipf_fi_bad_checkv4sum_manual, fr_info_t *, fin, u_int, manual);
 1104                         return (-1);
 1105                 }
 1106         }
 1107 #else
 1108         if (ipf_checkl4sum(fin) == -1) {
 1109                 fin->fin_flx |= FI_BAD;
 1110                 DT2(ipf_fi_bad_checkv4sum_checkl4sum, fr_info_t *, fin, u_int, -1);
 1111                 return (-1);
 1112         }
 1113 #endif
 1114         return (0);
 1115 }
 1116 
 1117 
 1118 #ifdef USE_INET6
 1119 int
 1120 ipf_checkv6sum(fr_info_t *fin)
 1121 {
 1122         if ((fin->fin_flx & FI_NOCKSUM) != 0) {
 1123                 DT(ipf_checkv6sum_fi_nocksum);
 1124                 return (0);
 1125         }
 1126 
 1127         if ((fin->fin_flx & FI_SHORT) != 0) {
 1128                 DT(ipf_checkv6sum_fi_short);
 1129                 return (1);
 1130         }
 1131 
 1132         if (fin->fin_cksum != FI_CK_NEEDED) {
 1133                 DT(ipf_checkv6sum_fi_ck_needed);
 1134                 return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
 1135         }
 1136 
 1137         if (ipf_checkl4sum(fin) == -1) {
 1138                 fin->fin_flx |= FI_BAD;
 1139                 DT2(ipf_fi_bad_checkv6sum_checkl4sum, fr_info_t *, fin, u_int, -1);
 1140                 return (-1);
 1141         }
 1142         return (0);
 1143 }
 1144 #endif /* USE_INET6 */
 1145 
 1146 
 1147 size_t
 1148 mbufchainlen(struct mbuf *m0)
 1149 {
 1150         size_t len;
 1151 
 1152         if ((m0->m_flags & M_PKTHDR) != 0) {
 1153                 len = m0->m_pkthdr.len;
 1154         } else {
 1155                 struct mbuf *m;
 1156 
 1157                 for (m = m0, len = 0; m != NULL; m = m->m_next)
 1158                         len += m->m_len;
 1159         }
 1160         return (len);
 1161 }
 1162 
 1163 
 1164 /* ------------------------------------------------------------------------ */
 1165 /* Function:    ipf_pullup                                                  */
 1166 /* Returns:     NULL == pullup failed, else pointer to protocol header      */
 1167 /* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
 1168 /*              fin(I) - pointer to packet information                      */
 1169 /*              len(I) - number of bytes to pullup                          */
 1170 /*                                                                          */
 1171 /* Attempt to move at least len bytes (from the start of the buffer) into a */
 1172 /* single buffer for ease of access.  Operating system native functions are */
 1173 /* used to manage buffers - if necessary.  If the entire packet ends up in  */
 1174 /* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
 1175 /* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
 1176 /* and ONLY if the pullup succeeds.                                         */
 1177 /*                                                                          */
 1178 /* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
 1179 /* of buffers that starts at *fin->fin_mp.                                  */
 1180 /* ------------------------------------------------------------------------ */
 1181 void *
 1182 ipf_pullup(mb_t *xmin, fr_info_t *fin, int len)
 1183 {
 1184         int dpoff, ipoff;
 1185         mb_t *m = xmin;
 1186         char *ip;
 1187 
 1188         if (m == NULL)
 1189                 return (NULL);
 1190 
 1191         ip = (char *)fin->fin_ip;
 1192         if ((fin->fin_flx & FI_COALESCE) != 0)
 1193                 return (ip);
 1194 
 1195         ipoff = fin->fin_ipoff;
 1196         if (fin->fin_dp != NULL)
 1197                 dpoff = (char *)fin->fin_dp - (char *)ip;
 1198         else
 1199                 dpoff = 0;
 1200 
 1201         if (M_LEN(m) < len) {
 1202                 mb_t *n = *fin->fin_mp;
 1203                 /*
 1204                  * Assume that M_PKTHDR is set and just work with what is left
 1205                  * rather than check..
 1206                  * Should not make any real difference, anyway.
 1207                  */
 1208                 if (m != n) {
 1209                         /*
 1210                          * Record the mbuf that points to the mbuf that we're
 1211                          * about to go to work on so that we can update the
 1212                          * m_next appropriately later.
 1213                          */
 1214                         for (; n->m_next != m; n = n->m_next)
 1215                                 ;
 1216                 } else {
 1217                         n = NULL;
 1218                 }
 1219 
 1220 #ifdef MHLEN
 1221                 if (len > MHLEN)
 1222 #else
 1223                 if (len > MLEN)
 1224 #endif
 1225                 {
 1226 #ifdef HAVE_M_PULLDOWN
 1227                         if (m_pulldown(m, 0, len, NULL) == NULL)
 1228                                 m = NULL;
 1229 #else
 1230                         FREE_MB_T(*fin->fin_mp);
 1231                         m = NULL;
 1232                         n = NULL;
 1233 #endif
 1234                 } else
 1235                 {
 1236                         m = m_pullup(m, len);
 1237                 }
 1238                 if (n != NULL)
 1239                         n->m_next = m;
 1240                 if (m == NULL) {
 1241                         /*
 1242                          * When n is non-NULL, it indicates that m pointed to
 1243                          * a sub-chain (tail) of the mbuf and that the head
 1244                          * of this chain has not yet been free'd.
 1245                          */
 1246                         if (n != NULL) {
 1247                                 FREE_MB_T(*fin->fin_mp);
 1248                         }
 1249 
 1250                         *fin->fin_mp = NULL;
 1251                         fin->fin_m = NULL;
 1252                         return (NULL);
 1253                 }
 1254 
 1255                 if (n == NULL)
 1256                         *fin->fin_mp = m;
 1257 
 1258                 while (M_LEN(m) == 0) {
 1259                         m = m->m_next;
 1260                 }
 1261                 fin->fin_m = m;
 1262                 ip = MTOD(m, char *) + ipoff;
 1263 
 1264                 fin->fin_ip = (ip_t *)ip;
 1265                 if (fin->fin_dp != NULL)
 1266                         fin->fin_dp = (char *)fin->fin_ip + dpoff;
 1267                 if (fin->fin_fraghdr != NULL)
 1268                         fin->fin_fraghdr = (char *)ip +
 1269                                            ((char *)fin->fin_fraghdr -
 1270                                             (char *)fin->fin_ip);
 1271         }
 1272 
 1273         if (len == fin->fin_plen)
 1274                 fin->fin_flx |= FI_COALESCE;
 1275         return (ip);
 1276 }
 1277 
 1278 
 1279 int
 1280 ipf_inject(fr_info_t *fin, mb_t *m)
 1281 {
 1282         struct epoch_tracker et;
 1283         int error = 0;
 1284 
 1285         NET_EPOCH_ENTER(et);
 1286         if (fin->fin_out == 0) {
 1287                 netisr_dispatch(NETISR_IP, m);
 1288         } else {
 1289                 fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
 1290                 fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
 1291                 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
 1292         }
 1293         NET_EPOCH_EXIT(et);
 1294 
 1295         return (error);
 1296 }
 1297 
 1298 VNET_DEFINE_STATIC(pfil_hook_t, ipf_inet_hook);
 1299 VNET_DEFINE_STATIC(pfil_hook_t, ipf_inet6_hook);
 1300 #define V_ipf_inet_hook         VNET(ipf_inet_hook)
 1301 #define V_ipf_inet6_hook        VNET(ipf_inet6_hook)
 1302 
 1303 int ipf_pfil_unhook(void) {
 1304 
 1305         pfil_remove_hook(V_ipf_inet_hook);
 1306 
 1307 #ifdef USE_INET6
 1308         pfil_remove_hook(V_ipf_inet6_hook);
 1309 #endif
 1310 
 1311         return (0);
 1312 }
 1313 
 1314 int ipf_pfil_hook(void) {
 1315         struct pfil_hook_args pha;
 1316         struct pfil_link_args pla;
 1317         int error, error6;
 1318 
 1319         pha.pa_version = PFIL_VERSION;
 1320         pha.pa_flags = PFIL_IN | PFIL_OUT;
 1321         pha.pa_modname = "ipfilter";
 1322         pha.pa_rulname = "default-ip4";
 1323         pha.pa_func = ipf_check_wrapper;
 1324         pha.pa_ruleset = NULL;
 1325         pha.pa_type = PFIL_TYPE_IP4;
 1326         V_ipf_inet_hook = pfil_add_hook(&pha);
 1327 
 1328 #ifdef USE_INET6
 1329         pha.pa_rulname = "default-ip6";
 1330         pha.pa_func = ipf_check_wrapper6;
 1331         pha.pa_type = PFIL_TYPE_IP6;
 1332         V_ipf_inet6_hook = pfil_add_hook(&pha);
 1333 #endif
 1334 
 1335         pla.pa_version = PFIL_VERSION;
 1336         pla.pa_flags = PFIL_IN | PFIL_OUT |
 1337             PFIL_HEADPTR | PFIL_HOOKPTR;
 1338         pla.pa_head = V_inet_pfil_head;
 1339         pla.pa_hook = V_ipf_inet_hook;
 1340         error = pfil_link(&pla);
 1341 
 1342         error6 = 0;
 1343 #ifdef USE_INET6
 1344         pla.pa_head = V_inet6_pfil_head;
 1345         pla.pa_hook = V_ipf_inet6_hook;
 1346         error6 = pfil_link(&pla);
 1347 #endif
 1348 
 1349         if (error || error6)
 1350                 error = ENODEV;
 1351         else
 1352                 error = 0;
 1353 
 1354         return (error);
 1355 }
 1356 
 1357 void
 1358 ipf_event_reg(void)
 1359 {
 1360         V_ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
 1361                                                ipf_ifevent, NULL, \
 1362                                                EVENTHANDLER_PRI_ANY);
 1363         V_ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
 1364                                                ipf_ifevent, NULL, \
 1365                                                EVENTHANDLER_PRI_ANY);
 1366 #if 0
 1367         V_ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
 1368                                                NULL, EVENTHANDLER_PRI_ANY);
 1369 #endif
 1370 }
 1371 
 1372 void
 1373 ipf_event_dereg(void)
 1374 {
 1375         if (V_ipf_arrivetag != NULL) {
 1376                 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, V_ipf_arrivetag);
 1377         }
 1378         if (V_ipf_departtag != NULL) {
 1379                 EVENTHANDLER_DEREGISTER(ifnet_departure_event, V_ipf_departtag);
 1380         }
 1381 #if 0
 1382         if (V_ipf_clonetag != NULL) {
 1383                 EVENTHANDLER_DEREGISTER(if_clone_event, V_ipf_clonetag);
 1384         }
 1385 #endif
 1386 }
 1387 
 1388 
 1389 u_32_t
 1390 ipf_random(void)
 1391 {
 1392         return (arc4random());
 1393 }
 1394 
 1395 
 1396 u_int
 1397 ipf_pcksum(fr_info_t *fin, int hlen, u_int sum)
 1398 {
 1399         struct mbuf *m;
 1400         u_int sum2;
 1401         int off;
 1402 
 1403         m = fin->fin_m;
 1404         off = (char *)fin->fin_dp - (char *)fin->fin_ip;
 1405         m->m_data += hlen;
 1406         m->m_len -= hlen;
 1407         sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
 1408         m->m_len += hlen;
 1409         m->m_data -= hlen;
 1410 
 1411         /*
 1412          * Both sum and sum2 are partial sums, so combine them together.
 1413          */
 1414         sum += ~sum2 & 0xffff;
 1415         while (sum > 0xffff)
 1416                 sum = (sum & 0xffff) + (sum >> 16);
 1417         sum2 = ~sum & 0xffff;
 1418         return (sum2);
 1419 }
 1420 
 1421 #ifdef  USE_INET6
 1422 u_int
 1423 ipf_pcksum6(struct mbuf *m, ip6_t *ip6, u_int32_t off, u_int32_t len)
 1424 {
 1425 #ifdef  _KERNEL
 1426         int sum;
 1427 
 1428         if (m->m_len < sizeof(struct ip6_hdr)) {
 1429                 return (0xffff);
 1430         }
 1431 
 1432         sum = in6_cksum(m, ip6->ip6_nxt, off, len);
 1433         return (sum);
 1434 #else
 1435         u_short *sp;
 1436         u_int sum;
 1437 
 1438         sp = (u_short *)&ip6->ip6_src;
 1439         sum = *sp++;   /* ip6_src */
 1440         sum += *sp++;
 1441         sum += *sp++;
 1442         sum += *sp++;
 1443         sum += *sp++;
 1444         sum += *sp++;
 1445         sum += *sp++;
 1446         sum += *sp++;
 1447         sum += *sp++;   /* ip6_dst */
 1448         sum += *sp++;
 1449         sum += *sp++;
 1450         sum += *sp++;
 1451         sum += *sp++;
 1452         sum += *sp++;
 1453         sum += *sp++;
 1454         sum += *sp++;
 1455         return (ipf_pcksum(fin, off, sum));
 1456 #endif
 1457 }
 1458 #endif
 1459 
 1460 void
 1461 ipf_fbsd_kenv_get(ipf_main_softc_t *softc)
 1462 {
 1463         TUNABLE_INT_FETCH("net.inet.ipf.large_nat",
 1464                 &softc->ipf_large_nat);
 1465 }

Cache object: 1da565a7c667160e0a4dbfa8047dc0e6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.