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/netgraph/ng_checksum.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/11.1/sys/netgraph/ng_checksum.c 309385 2016-12-02 05:36:37Z julian $");
   30 
   31 #include "opt_inet.h"
   32 #include "opt_inet6.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/endian.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/socket.h>
   41 
   42 #include <net/bpf.h>
   43 #include <net/ethernet.h>
   44 #include <net/if.h>
   45 #include <net/if_vlan_var.h>
   46 
   47 #include <netinet/in.h>
   48 #include <netinet/ip.h>
   49 #include <netinet/ip6.h>
   50 #include <netinet/tcp.h>
   51 #include <netinet/udp.h>
   52 #include <machine/in_cksum.h>
   53 
   54 #include <netgraph/ng_message.h>
   55 #include <netgraph/ng_parse.h>
   56 #include <netgraph/netgraph.h>
   57 
   58 #include <netgraph/ng_checksum.h>
   59 
   60 /* private data */
   61 struct ng_checksum_priv {
   62         hook_p in;
   63         hook_p out;
   64         uint8_t dlt;    /* DLT_XXX from bpf.h */
   65         struct ng_checksum_config *conf;
   66         struct ng_checksum_stats stats;
   67 };
   68 
   69 typedef struct ng_checksum_priv *priv_p;
   70 
   71 /* Netgraph methods */
   72 static ng_constructor_t ng_checksum_constructor;
   73 static ng_rcvmsg_t      ng_checksum_rcvmsg;
   74 static ng_shutdown_t    ng_checksum_shutdown;
   75 static ng_newhook_t     ng_checksum_newhook;
   76 static ng_rcvdata_t     ng_checksum_rcvdata;
   77 static ng_disconnect_t  ng_checksum_disconnect;
   78 
   79 #define ERROUT(x) { error = (x); goto done; }
   80 
   81 static const struct ng_parse_struct_field ng_checksum_config_type_fields[]
   82         = NG_CHECKSUM_CONFIG_TYPE;
   83 static const struct ng_parse_type ng_checksum_config_type = {
   84         &ng_parse_struct_type,
   85         &ng_checksum_config_type_fields
   86 };
   87 
   88 static const struct ng_parse_struct_field ng_checksum_stats_fields[]
   89         = NG_CHECKSUM_STATS_TYPE;
   90 static const struct ng_parse_type ng_checksum_stats_type = {
   91         &ng_parse_struct_type,
   92         &ng_checksum_stats_fields
   93 };
   94 
   95 static const struct ng_cmdlist ng_checksum_cmdlist[] = {
   96         {
   97                 NGM_CHECKSUM_COOKIE,
   98                 NGM_CHECKSUM_GETDLT,
   99                 "getdlt",
  100                 NULL,
  101                 &ng_parse_uint8_type
  102         },
  103         {
  104                 NGM_CHECKSUM_COOKIE,
  105                 NGM_CHECKSUM_SETDLT,
  106                 "setdlt",
  107                 &ng_parse_uint8_type,
  108                 NULL
  109         },
  110         {
  111                 NGM_CHECKSUM_COOKIE,
  112                 NGM_CHECKSUM_GETCONFIG,
  113                 "getconfig",
  114                 NULL,
  115                 &ng_checksum_config_type
  116         },
  117         {
  118                 NGM_CHECKSUM_COOKIE,
  119                 NGM_CHECKSUM_SETCONFIG,
  120                 "setconfig",
  121                 &ng_checksum_config_type,
  122                 NULL
  123         },
  124         {
  125                 NGM_CHECKSUM_COOKIE,
  126                 NGM_CHECKSUM_GET_STATS,
  127                 "getstats",
  128                 NULL,
  129                 &ng_checksum_stats_type
  130         },
  131         {
  132                 NGM_CHECKSUM_COOKIE,
  133                 NGM_CHECKSUM_CLR_STATS,
  134                 "clrstats",
  135                 NULL,
  136                 NULL
  137         },
  138         {
  139                 NGM_CHECKSUM_COOKIE,
  140                 NGM_CHECKSUM_GETCLR_STATS,
  141                 "getclrstats",
  142                 NULL,
  143                 &ng_checksum_stats_type
  144         },
  145         { 0 }
  146 };
  147 
  148 static struct ng_type typestruct = {
  149         .version =      NG_ABI_VERSION,
  150         .name =         NG_CHECKSUM_NODE_TYPE,
  151         .constructor =  ng_checksum_constructor,
  152         .rcvmsg =       ng_checksum_rcvmsg,
  153         .shutdown =     ng_checksum_shutdown,
  154         .newhook =      ng_checksum_newhook,
  155         .rcvdata =      ng_checksum_rcvdata,
  156         .disconnect =   ng_checksum_disconnect,
  157         .cmdlist =      ng_checksum_cmdlist,
  158 };
  159 
  160 NETGRAPH_INIT(checksum, &typestruct);
  161 
  162 static int
  163 ng_checksum_constructor(node_p node)
  164 {
  165         priv_p priv;
  166 
  167         priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK|M_ZERO);
  168         priv->dlt = DLT_RAW;
  169 
  170         NG_NODE_SET_PRIVATE(node, priv);
  171 
  172         return (0);
  173 }
  174 
  175 static int
  176 ng_checksum_newhook(node_p node, hook_p hook, const char *name)
  177 {
  178         const priv_p priv = NG_NODE_PRIVATE(node);
  179 
  180         if (strncmp(name, NG_CHECKSUM_HOOK_IN, strlen(NG_CHECKSUM_HOOK_IN)) == 0) {
  181                 priv->in = hook;
  182         } else if (strncmp(name, NG_CHECKSUM_HOOK_OUT, strlen(NG_CHECKSUM_HOOK_OUT)) == 0) {
  183                 priv->out = hook;
  184         } else
  185                 return (EINVAL);
  186 
  187         return (0);
  188 }
  189 
  190 static int
  191 ng_checksum_rcvmsg(node_p node, item_p item, hook_p lasthook)
  192 {
  193         const priv_p priv = NG_NODE_PRIVATE(node);
  194         struct ng_checksum_config *conf, *newconf;
  195         struct ng_mesg *msg;
  196         struct ng_mesg *resp = NULL;
  197         int error = 0;
  198 
  199         NGI_GET_MSG(item, msg);
  200 
  201         if  (msg->header.typecookie != NGM_CHECKSUM_COOKIE)
  202                 ERROUT(EINVAL);
  203 
  204         switch (msg->header.cmd)
  205         {
  206                 case NGM_CHECKSUM_GETDLT:
  207                         NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
  208 
  209                         if (resp == NULL)
  210                                 ERROUT(ENOMEM);
  211 
  212                         *((uint8_t *) resp->data) = priv->dlt;
  213 
  214                         break;
  215 
  216                 case NGM_CHECKSUM_SETDLT:
  217                         if (msg->header.arglen != sizeof(uint8_t))
  218                                 ERROUT(EINVAL);
  219 
  220                         switch (*(uint8_t *) msg->data)
  221                         {
  222                                 case DLT_EN10MB:
  223                                 case DLT_RAW:
  224                                         priv->dlt = *(uint8_t *) msg->data;
  225                                         break;
  226 
  227                                 default:
  228                                         ERROUT(EINVAL);
  229                         }
  230 
  231                         break;
  232 
  233                 case NGM_CHECKSUM_GETCONFIG:
  234                         if (priv->conf == NULL)
  235                                 ERROUT(0);
  236 
  237                         NG_MKRESPONSE(resp, msg, sizeof(struct ng_checksum_config), M_WAITOK);
  238 
  239                         if (resp == NULL)
  240                                 ERROUT(ENOMEM);
  241 
  242                         bcopy(priv->conf, resp->data, sizeof(struct ng_checksum_config));
  243 
  244                         break;
  245 
  246                 case NGM_CHECKSUM_SETCONFIG:
  247                         conf = (struct ng_checksum_config *) msg->data;
  248 
  249                         if (msg->header.arglen != sizeof(struct ng_checksum_config))
  250                                 ERROUT(EINVAL);
  251 
  252                         conf->csum_flags &= NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6;
  253                         conf->csum_offload &= NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6;
  254 
  255                         newconf = malloc(sizeof(struct ng_checksum_config), M_NETGRAPH, M_WAITOK|M_ZERO);
  256 
  257                         bcopy(conf, newconf, sizeof(struct ng_checksum_config));
  258 
  259                         if (priv->conf)
  260                                 free(priv->conf, M_NETGRAPH);
  261 
  262                         priv->conf = newconf;
  263 
  264                         break;
  265 
  266                 case NGM_CHECKSUM_GET_STATS:
  267                 case NGM_CHECKSUM_CLR_STATS:
  268                 case NGM_CHECKSUM_GETCLR_STATS:
  269                         if (msg->header.cmd != NGM_CHECKSUM_CLR_STATS) {
  270                                 NG_MKRESPONSE(resp, msg, sizeof(struct ng_checksum_stats), M_WAITOK);
  271 
  272                                 if (resp == NULL)
  273                                         ERROUT(ENOMEM);
  274 
  275                                 bcopy(&(priv->stats), resp->data, sizeof(struct ng_checksum_stats));
  276                         }
  277 
  278                         if (msg->header.cmd != NGM_CHECKSUM_GET_STATS)
  279                                 bzero(&(priv->stats), sizeof(struct ng_checksum_stats));
  280 
  281                         break;
  282 
  283                 default:
  284                         ERROUT(EINVAL);
  285         }
  286 
  287 done:
  288         NG_RESPOND_MSG(error, node, item, resp);
  289         NG_FREE_MSG(msg);
  290 
  291         return (error);
  292 }
  293 
  294 #define PULLUP_CHECK(mbuf, length) do {                                 \
  295         pullup_len += length;                                           \
  296         if (((mbuf)->m_pkthdr.len < pullup_len) ||                      \
  297             (pullup_len > MHLEN)) {                                     \
  298                 return (EINVAL);                                        \
  299         }                                                               \
  300         if ((mbuf)->m_len < pullup_len &&                               \
  301             (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {        \
  302                 return (ENOBUFS);                                       \
  303         }                                                               \
  304 } while (0)
  305 
  306 #ifdef INET
  307 static int
  308 checksum_ipv4(priv_p priv, struct mbuf *m, int l3_offset)
  309 {
  310         struct ip *ip4;
  311         int pullup_len;
  312         int hlen, plen;
  313         int processed = 0;
  314 
  315         pullup_len = l3_offset;
  316 
  317         PULLUP_CHECK(m, sizeof(struct ip));
  318         ip4 = (struct ip *) mtodo(m, l3_offset);
  319 
  320         if (ip4->ip_v != IPVERSION)
  321                 return (EOPNOTSUPP);
  322 
  323         hlen = ip4->ip_hl << 2;
  324         plen = ntohs(ip4->ip_len);
  325 
  326         if (hlen < sizeof(struct ip) || m->m_pkthdr.len < l3_offset + plen)
  327                 return (EINVAL);
  328 
  329         if (m->m_pkthdr.csum_flags & CSUM_IP) {
  330                 ip4->ip_sum = 0;
  331 
  332                 if ((priv->conf->csum_offload & CSUM_IP) == 0) {
  333                         if (hlen == sizeof(struct ip))
  334                                 ip4->ip_sum = in_cksum_hdr(ip4);
  335                         else
  336                                 ip4->ip_sum = in_cksum_skip(m, l3_offset + hlen, l3_offset);
  337 
  338                         m->m_pkthdr.csum_flags &= ~CSUM_IP;
  339                 }
  340 
  341                 processed = 1;
  342         }
  343 
  344         pullup_len = l3_offset + hlen;
  345 
  346         /* We can not calculate a checksum fragmented packets */
  347         if (ip4->ip_off & htons(IP_MF|IP_OFFMASK)) {
  348                 m->m_pkthdr.csum_flags &= ~(CSUM_TCP|CSUM_UDP);
  349                 return (0);
  350         }
  351 
  352         switch (ip4->ip_p)
  353         {
  354                 case IPPROTO_TCP:
  355                         if (m->m_pkthdr.csum_flags & CSUM_TCP) {
  356                                 struct tcphdr *th;
  357 
  358                                 PULLUP_CHECK(m, sizeof(struct tcphdr));
  359                                 th = (struct tcphdr *) mtodo(m, l3_offset + hlen);
  360 
  361                                 th->th_sum = in_pseudo(ip4->ip_src.s_addr,
  362                                     ip4->ip_dst.s_addr, htons(ip4->ip_p + plen - hlen));
  363 
  364                                 if ((priv->conf->csum_offload & CSUM_TCP) == 0) {
  365                                         th->th_sum = in_cksum_skip(m, l3_offset + plen, l3_offset + hlen);
  366                                         m->m_pkthdr.csum_flags &= ~CSUM_TCP;
  367                                 }
  368 
  369                                 processed = 1;
  370                         }
  371 
  372                         m->m_pkthdr.csum_flags &= ~CSUM_UDP;
  373                         break;
  374 
  375                 case IPPROTO_UDP:
  376                         if (m->m_pkthdr.csum_flags & CSUM_UDP) {
  377                                 struct udphdr *uh;
  378 
  379                                 PULLUP_CHECK(m, sizeof(struct udphdr));
  380                                 uh = (struct udphdr *) mtodo(m, l3_offset + hlen);
  381 
  382                                 uh->uh_sum = in_pseudo(ip4->ip_src.s_addr,
  383                                     ip4->ip_dst.s_addr, htons(ip4->ip_p + plen - hlen));
  384 
  385                                 if ((priv->conf->csum_offload & CSUM_UDP) == 0) {
  386                                         uh->uh_sum = in_cksum_skip(m,
  387                                             l3_offset + plen, l3_offset + hlen);
  388 
  389                                         if (uh->uh_sum == 0)
  390                                                 uh->uh_sum = 0xffff;
  391 
  392                                         m->m_pkthdr.csum_flags &= ~CSUM_UDP;
  393                                 }
  394 
  395                                 processed = 1;
  396                         }
  397 
  398                         m->m_pkthdr.csum_flags &= ~CSUM_TCP;
  399                         break;
  400 
  401                 default:
  402                         m->m_pkthdr.csum_flags &= ~(CSUM_TCP|CSUM_UDP);
  403                         break;
  404         }
  405 
  406         m->m_pkthdr.csum_flags &= ~NG_CHECKSUM_CSUM_IPV6;
  407 
  408         if (processed)
  409                 priv->stats.processed++;
  410 
  411         return (0);
  412 }
  413 #endif /* INET */
  414 
  415 #ifdef INET6
  416 static int
  417 checksum_ipv6(priv_p priv, struct mbuf *m, int l3_offset)
  418 {
  419         struct ip6_hdr *ip6;
  420         struct ip6_ext *ip6e = NULL;
  421         int pullup_len;
  422         int hlen, plen;
  423         int nxt;
  424         int processed = 0;
  425 
  426         pullup_len = l3_offset;
  427 
  428         PULLUP_CHECK(m, sizeof(struct ip6_hdr));
  429         ip6 = (struct ip6_hdr *) mtodo(m, l3_offset);
  430 
  431         if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
  432                 return (EOPNOTSUPP);
  433 
  434         hlen = sizeof(struct ip6_hdr);
  435         plen = ntohs(ip6->ip6_plen) + hlen;
  436 
  437         if (m->m_pkthdr.len < l3_offset + plen)
  438                 return (EINVAL);
  439 
  440         nxt = ip6->ip6_nxt;
  441 
  442         for (;;) {
  443                 switch (nxt)
  444                 {
  445                         case IPPROTO_DSTOPTS:
  446                         case IPPROTO_HOPOPTS:
  447                         case IPPROTO_ROUTING:
  448                                 PULLUP_CHECK(m, sizeof(struct ip6_ext));
  449                                 ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen);
  450                                 nxt = ip6e->ip6e_nxt;
  451                                 hlen += (ip6e->ip6e_len + 1) << 3;
  452                                 pullup_len = l3_offset + hlen;
  453                                 break;
  454 
  455                         case IPPROTO_AH:
  456                                 PULLUP_CHECK(m, sizeof(struct ip6_ext));
  457                                 ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen);
  458                                 nxt = ip6e->ip6e_nxt;
  459                                 hlen += (ip6e->ip6e_len + 2) << 2;
  460                                 pullup_len = l3_offset + hlen;
  461                                 break;
  462 
  463                         case IPPROTO_FRAGMENT:
  464                                 /* We can not calculate a checksum fragmented packets */
  465                                 m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6);
  466                                 return (0);
  467 
  468                         default:
  469                                 goto loopend;
  470                 }
  471 
  472                 if (nxt == 0)
  473                         return (EINVAL);
  474         }
  475 
  476 loopend:
  477 
  478         switch (nxt)
  479         {
  480                 case IPPROTO_TCP:
  481                         if (m->m_pkthdr.csum_flags & CSUM_TCP_IPV6) {
  482                                 struct tcphdr *th;
  483 
  484                                 PULLUP_CHECK(m, sizeof(struct tcphdr));
  485                                 th = (struct tcphdr *) mtodo(m, l3_offset + hlen);
  486 
  487                                 th->th_sum = in6_cksum_pseudo(ip6, plen - hlen, nxt, 0);
  488 
  489                                 if ((priv->conf->csum_offload & CSUM_TCP_IPV6) == 0) {
  490                                         th->th_sum = in_cksum_skip(m, l3_offset + plen, l3_offset + hlen);
  491                                         m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
  492                                 }
  493 
  494                                 processed = 1;
  495                         }
  496 
  497                         m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
  498                         break;
  499 
  500                 case IPPROTO_UDP:
  501                         if (m->m_pkthdr.csum_flags & CSUM_UDP_IPV6) {
  502                                 struct udphdr *uh;
  503 
  504                                 PULLUP_CHECK(m, sizeof(struct udphdr));
  505                                 uh = (struct udphdr *) mtodo(m, l3_offset + hlen);
  506 
  507                                 uh->uh_sum = in6_cksum_pseudo(ip6, plen - hlen, nxt, 0);
  508 
  509                                 if ((priv->conf->csum_offload & CSUM_UDP_IPV6) == 0) {
  510                                         uh->uh_sum = in_cksum_skip(m,
  511                                             l3_offset + plen, l3_offset + hlen);
  512 
  513                                         if (uh->uh_sum == 0)
  514                                                 uh->uh_sum = 0xffff;
  515 
  516                                         m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
  517                                 }
  518 
  519                                 processed = 1;
  520                         }
  521 
  522                         m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
  523                         break;
  524 
  525                 default:
  526                         m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6);
  527                         break;
  528         }
  529 
  530         m->m_pkthdr.csum_flags &= ~NG_CHECKSUM_CSUM_IPV4;
  531 
  532         if (processed)
  533                 priv->stats.processed++;
  534 
  535         return (0);
  536 }
  537 #endif /* INET6 */
  538 
  539 #undef  PULLUP_CHECK
  540 
  541 static int
  542 ng_checksum_rcvdata(hook_p hook, item_p item)
  543 {
  544         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  545         struct mbuf *m;
  546         hook_p out;
  547         int error = 0;
  548 
  549         priv->stats.received++;
  550 
  551         NGI_GET_M(item, m);
  552 
  553 #define PULLUP_CHECK(mbuf, length) do {                                 \
  554         pullup_len += length;                                           \
  555         if (((mbuf)->m_pkthdr.len < pullup_len) ||                      \
  556             (pullup_len > MHLEN)) {                                     \
  557                 error = EINVAL;                                         \
  558                 goto bypass;                                            \
  559         }                                                               \
  560         if ((mbuf)->m_len < pullup_len &&                               \
  561             (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {        \
  562                 error = ENOBUFS;                                        \
  563                 goto drop;                                              \
  564         }                                                               \
  565 } while (0)
  566 
  567         if (!(priv->conf && hook == priv->in && m && (m->m_flags & M_PKTHDR)))
  568                 goto bypass;
  569 
  570         m->m_pkthdr.csum_flags |= priv->conf->csum_flags;
  571 
  572         if (m->m_pkthdr.csum_flags & (NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6))
  573         {
  574                 struct ether_header *eh;
  575                 struct ng_checksum_vlan_header *vh;
  576                 int pullup_len = 0;
  577                 uint16_t etype;
  578 
  579                 m = m_unshare(m, M_NOWAIT);
  580 
  581                 if (m == NULL)
  582                         ERROUT(ENOMEM);
  583 
  584                 switch (priv->dlt)
  585                 {
  586                         case DLT_EN10MB:
  587                                 PULLUP_CHECK(m, sizeof(struct ether_header));
  588                                 eh = mtod(m, struct ether_header *);
  589                                 etype = ntohs(eh->ether_type);
  590 
  591                                 for (;;) {      /* QinQ support */
  592                                         switch (etype)
  593                                         {
  594                                                 case 0x8100:
  595                                                 case 0x88A8:
  596                                                 case 0x9100:
  597                                                         PULLUP_CHECK(m, sizeof(struct ng_checksum_vlan_header));
  598                                                         vh = (struct ng_checksum_vlan_header *) mtodo(m,
  599                                                             pullup_len - sizeof(struct ng_checksum_vlan_header));
  600                                                         etype = ntohs(vh->etype);
  601                                                         break;
  602 
  603                                                 default:
  604                                                         goto loopend;
  605                                         }
  606                                 }
  607 loopend:
  608 #ifdef INET
  609                                 if (etype == ETHERTYPE_IP &&
  610                                     (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV4)) {
  611                                         error = checksum_ipv4(priv, m, pullup_len);
  612                                         if (error == ENOBUFS)
  613                                                 goto drop;
  614                                 } else
  615 #endif
  616 #ifdef INET6
  617                                 if (etype == ETHERTYPE_IPV6 &&
  618                                     (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV6)) {
  619                                         error = checksum_ipv6(priv, m, pullup_len);
  620                                         if (error == ENOBUFS)
  621                                                 goto drop;
  622                                 } else
  623 #endif
  624                                 {
  625                                         m->m_pkthdr.csum_flags &=
  626                                             ~(NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6);
  627                                 }
  628 
  629                                 break;
  630 
  631                         case DLT_RAW:
  632 #ifdef INET
  633                                 if (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV4)
  634                                 {
  635                                         error = checksum_ipv4(priv, m, pullup_len);
  636 
  637                                         if (error == 0)
  638                                                 goto bypass;
  639                                         else if (error == ENOBUFS)
  640                                                 goto drop;
  641                                 }
  642 #endif
  643 #ifdef INET6
  644                                 if (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV6)
  645                                 {
  646                                         error = checksum_ipv6(priv, m, pullup_len);
  647 
  648                                         if (error == 0)
  649                                                 goto bypass;
  650                                         else if (error == ENOBUFS)
  651                                                 goto drop;
  652                                 }
  653 #endif
  654                                 if (error)
  655                                         m->m_pkthdr.csum_flags &=
  656                                             ~(NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6);
  657 
  658                                 break;
  659 
  660                         default:
  661                                 ERROUT(EINVAL);
  662                 }
  663         }
  664 
  665 #undef  PULLUP_CHECK
  666 
  667 bypass:
  668         out = NULL;
  669 
  670         if (hook == priv->in) {
  671                 /* return frames on 'in' hook if 'out' not connected */
  672                 out = priv->out ? priv->out : priv->in;
  673         } else if (hook == priv->out && priv->in) {
  674                 /* pass frames on 'out' hook if 'in' connected */
  675                 out = priv->in;
  676         }
  677 
  678         if (out == NULL)
  679                 ERROUT(0);
  680 
  681         NG_FWD_NEW_DATA(error, item, out, m);
  682 
  683         return (error);
  684 
  685 done:
  686 drop:
  687         NG_FREE_ITEM(item);
  688         NG_FREE_M(m);
  689 
  690         priv->stats.dropped++;
  691 
  692         return (error);
  693 }
  694 
  695 static int
  696 ng_checksum_shutdown(node_p node)
  697 {
  698         const priv_p priv = NG_NODE_PRIVATE(node);
  699 
  700         NG_NODE_SET_PRIVATE(node, NULL);
  701         NG_NODE_UNREF(node);
  702 
  703         if (priv->conf)
  704                 free(priv->conf, M_NETGRAPH);
  705 
  706         free(priv, M_NETGRAPH);
  707 
  708         return (0);
  709 }
  710 
  711 static int
  712 ng_checksum_disconnect(hook_p hook)
  713 {
  714         priv_p priv;
  715 
  716         priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  717 
  718         if (hook == priv->in)
  719                 priv->in = NULL;
  720 
  721         if (hook == priv->out)
  722                 priv->out = NULL;
  723 
  724         if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
  725             NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */
  726                 ng_rmnode_self(NG_HOOK_NODE(hook));
  727 
  728         return (0);
  729 }

Cache object: cffcd0a98639c96e515d3ee2ee661b4f


[ 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.