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-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 /*-
    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$");
   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 #define ERROUT(x) { error = (x); goto done; }
   79 
   80 static const struct ng_parse_struct_field ng_checksum_config_type_fields[]
   81         = NG_CHECKSUM_CONFIG_TYPE;
   82 static const struct ng_parse_type ng_checksum_config_type = {
   83         &ng_parse_struct_type,
   84         &ng_checksum_config_type_fields
   85 };
   86 
   87 static const struct ng_parse_struct_field ng_checksum_stats_fields[]
   88         = NG_CHECKSUM_STATS_TYPE;
   89 static const struct ng_parse_type ng_checksum_stats_type = {
   90         &ng_parse_struct_type,
   91         &ng_checksum_stats_fields
   92 };
   93 
   94 static const struct ng_cmdlist ng_checksum_cmdlist[] = {
   95         {
   96                 NGM_CHECKSUM_COOKIE,
   97                 NGM_CHECKSUM_GETDLT,
   98                 "getdlt",
   99                 NULL,
  100                 &ng_parse_uint8_type
  101         },
  102         {
  103                 NGM_CHECKSUM_COOKIE,
  104                 NGM_CHECKSUM_SETDLT,
  105                 "setdlt",
  106                 &ng_parse_uint8_type,
  107                 NULL
  108         },
  109         {
  110                 NGM_CHECKSUM_COOKIE,
  111                 NGM_CHECKSUM_GETCONFIG,
  112                 "getconfig",
  113                 NULL,
  114                 &ng_checksum_config_type
  115         },
  116         {
  117                 NGM_CHECKSUM_COOKIE,
  118                 NGM_CHECKSUM_SETCONFIG,
  119                 "setconfig",
  120                 &ng_checksum_config_type,
  121                 NULL
  122         },
  123         {
  124                 NGM_CHECKSUM_COOKIE,
  125                 NGM_CHECKSUM_GET_STATS,
  126                 "getstats",
  127                 NULL,
  128                 &ng_checksum_stats_type
  129         },
  130         {
  131                 NGM_CHECKSUM_COOKIE,
  132                 NGM_CHECKSUM_CLR_STATS,
  133                 "clrstats",
  134                 NULL,
  135                 NULL
  136         },
  137         {
  138                 NGM_CHECKSUM_COOKIE,
  139                 NGM_CHECKSUM_GETCLR_STATS,
  140                 "getclrstats",
  141                 NULL,
  142                 &ng_checksum_stats_type
  143         },
  144         { 0 }
  145 };
  146 
  147 static struct ng_type typestruct = {
  148         .version =      NG_ABI_VERSION,
  149         .name =         NG_CHECKSUM_NODE_TYPE,
  150         .constructor =  ng_checksum_constructor,
  151         .rcvmsg =       ng_checksum_rcvmsg,
  152         .shutdown =     ng_checksum_shutdown,
  153         .newhook =      ng_checksum_newhook,
  154         .rcvdata =      ng_checksum_rcvdata,
  155         .disconnect =   ng_checksum_disconnect,
  156         .cmdlist =      ng_checksum_cmdlist,
  157 };
  158 
  159 NETGRAPH_INIT(checksum, &typestruct);
  160 
  161 static int
  162 ng_checksum_constructor(node_p node)
  163 {
  164         priv_p priv;
  165 
  166         priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK|M_ZERO);
  167         priv->dlt = DLT_RAW;
  168 
  169         NG_NODE_SET_PRIVATE(node, priv);
  170 
  171         return (0);
  172 }
  173 
  174 static int
  175 ng_checksum_newhook(node_p node, hook_p hook, const char *name)
  176 {
  177         const priv_p priv = NG_NODE_PRIVATE(node);
  178 
  179         if (strncmp(name, NG_CHECKSUM_HOOK_IN, strlen(NG_CHECKSUM_HOOK_IN)) == 0) {
  180                 priv->in = hook;
  181         } else if (strncmp(name, NG_CHECKSUM_HOOK_OUT, strlen(NG_CHECKSUM_HOOK_OUT)) == 0) {
  182                 priv->out = hook;
  183         } else
  184                 return (EINVAL);
  185 
  186         return (0);
  187 }
  188 
  189 static int
  190 ng_checksum_rcvmsg(node_p node, item_p item, hook_p lasthook)
  191 {
  192         const priv_p priv = NG_NODE_PRIVATE(node);
  193         struct ng_checksum_config *conf, *newconf;
  194         struct ng_mesg *msg;
  195         struct ng_mesg *resp = NULL;
  196         int error = 0;
  197 
  198         NGI_GET_MSG(item, msg);
  199 
  200         if  (msg->header.typecookie != NGM_CHECKSUM_COOKIE)
  201                 ERROUT(EINVAL);
  202 
  203         switch (msg->header.cmd)
  204         {
  205                 case NGM_CHECKSUM_GETDLT:
  206                         NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
  207 
  208                         if (resp == NULL)
  209                                 ERROUT(ENOMEM);
  210 
  211                         *((uint8_t *) resp->data) = priv->dlt;
  212 
  213                         break;
  214 
  215                 case NGM_CHECKSUM_SETDLT:
  216                         if (msg->header.arglen != sizeof(uint8_t))
  217                                 ERROUT(EINVAL);
  218 
  219                         switch (*(uint8_t *) msg->data)
  220                         {
  221                                 case DLT_EN10MB:
  222                                 case DLT_RAW:
  223                                         priv->dlt = *(uint8_t *) msg->data;
  224                                         break;
  225 
  226                                 default:
  227                                         ERROUT(EINVAL);
  228                         }
  229 
  230                         break;
  231 
  232                 case NGM_CHECKSUM_GETCONFIG:
  233                         if (priv->conf == NULL)
  234                                 ERROUT(0);
  235 
  236                         NG_MKRESPONSE(resp, msg, sizeof(struct ng_checksum_config), M_WAITOK);
  237 
  238                         if (resp == NULL)
  239                                 ERROUT(ENOMEM);
  240 
  241                         bcopy(priv->conf, resp->data, sizeof(struct ng_checksum_config));
  242 
  243                         break;
  244 
  245                 case NGM_CHECKSUM_SETCONFIG:
  246                         conf = (struct ng_checksum_config *) msg->data;
  247 
  248                         if (msg->header.arglen != sizeof(struct ng_checksum_config))
  249                                 ERROUT(EINVAL);
  250 
  251                         conf->csum_flags &= NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6;
  252                         conf->csum_offload &= NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6;
  253 
  254                         newconf = malloc(sizeof(struct ng_checksum_config), M_NETGRAPH, M_WAITOK|M_ZERO);
  255 
  256                         bcopy(conf, newconf, sizeof(struct ng_checksum_config));
  257 
  258                         if (priv->conf)
  259                                 free(priv->conf, M_NETGRAPH);
  260 
  261                         priv->conf = newconf;
  262 
  263                         break;
  264 
  265                 case NGM_CHECKSUM_GET_STATS:
  266                 case NGM_CHECKSUM_CLR_STATS:
  267                 case NGM_CHECKSUM_GETCLR_STATS:
  268                         if (msg->header.cmd != NGM_CHECKSUM_CLR_STATS) {
  269                                 NG_MKRESPONSE(resp, msg, sizeof(struct ng_checksum_stats), M_WAITOK);
  270 
  271                                 if (resp == NULL)
  272                                         ERROUT(ENOMEM);
  273 
  274                                 bcopy(&(priv->stats), resp->data, sizeof(struct ng_checksum_stats));
  275                         }
  276 
  277                         if (msg->header.cmd != NGM_CHECKSUM_GET_STATS)
  278                                 bzero(&(priv->stats), sizeof(struct ng_checksum_stats));
  279 
  280                         break;
  281 
  282                 default:
  283                         ERROUT(EINVAL);
  284         }
  285 
  286 done:
  287         NG_RESPOND_MSG(error, node, item, resp);
  288         NG_FREE_MSG(msg);
  289 
  290         return (error);
  291 }
  292 
  293 #define PULLUP_CHECK(mbuf, length) do {                                 \
  294         pullup_len += length;                                           \
  295         if (((mbuf)->m_pkthdr.len < pullup_len) ||                      \
  296             (pullup_len > MHLEN)) {                                     \
  297                 return (EINVAL);                                        \
  298         }                                                               \
  299         if ((mbuf)->m_len < pullup_len &&                               \
  300             (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {        \
  301                 return (ENOBUFS);                                       \
  302         }                                                               \
  303 } while (0)
  304 
  305 #ifdef INET
  306 static int
  307 checksum_ipv4(priv_p priv, struct mbuf *m, int l3_offset)
  308 {
  309         struct ip *ip4;
  310         int pullup_len;
  311         int hlen, plen;
  312         int processed = 0;
  313 
  314         pullup_len = l3_offset;
  315 
  316         PULLUP_CHECK(m, sizeof(struct ip));
  317         ip4 = (struct ip *) mtodo(m, l3_offset);
  318 
  319         if (ip4->ip_v != IPVERSION)
  320                 return (EOPNOTSUPP);
  321 
  322         hlen = ip4->ip_hl << 2;
  323         plen = ntohs(ip4->ip_len);
  324 
  325         if (hlen < sizeof(struct ip) || m->m_pkthdr.len < l3_offset + plen)
  326                 return (EINVAL);
  327 
  328         if (m->m_pkthdr.csum_flags & CSUM_IP) {
  329                 ip4->ip_sum = 0;
  330 
  331                 if ((priv->conf->csum_offload & CSUM_IP) == 0) {
  332                         if (hlen == sizeof(struct ip))
  333                                 ip4->ip_sum = in_cksum_hdr(ip4);
  334                         else
  335                                 ip4->ip_sum = in_cksum_skip(m, l3_offset + hlen, l3_offset);
  336 
  337                         m->m_pkthdr.csum_flags &= ~CSUM_IP;
  338                 }
  339 
  340                 processed = 1;
  341         }
  342 
  343         pullup_len = l3_offset + hlen;
  344 
  345         /* We can not calculate a checksum fragmented packets */
  346         if (ip4->ip_off & htons(IP_MF|IP_OFFMASK)) {
  347                 m->m_pkthdr.csum_flags &= ~(CSUM_TCP|CSUM_UDP);
  348                 return (0);
  349         }
  350 
  351         switch (ip4->ip_p)
  352         {
  353                 case IPPROTO_TCP:
  354                         if (m->m_pkthdr.csum_flags & CSUM_TCP) {
  355                                 struct tcphdr *th;
  356 
  357                                 PULLUP_CHECK(m, sizeof(struct tcphdr));
  358                                 th = (struct tcphdr *) mtodo(m, l3_offset + hlen);
  359 
  360                                 th->th_sum = in_pseudo(ip4->ip_src.s_addr,
  361                                     ip4->ip_dst.s_addr, htons(ip4->ip_p + plen - hlen));
  362 
  363                                 if ((priv->conf->csum_offload & CSUM_TCP) == 0) {
  364                                         th->th_sum = in_cksum_skip(m, l3_offset + plen, l3_offset + hlen);
  365                                         m->m_pkthdr.csum_flags &= ~CSUM_TCP;
  366                                 }
  367 
  368                                 processed = 1;
  369                         }
  370 
  371                         m->m_pkthdr.csum_flags &= ~CSUM_UDP;
  372                         break;
  373 
  374                 case IPPROTO_UDP:
  375                         if (m->m_pkthdr.csum_flags & CSUM_UDP) {
  376                                 struct udphdr *uh;
  377 
  378                                 PULLUP_CHECK(m, sizeof(struct udphdr));
  379                                 uh = (struct udphdr *) mtodo(m, l3_offset + hlen);
  380 
  381                                 uh->uh_sum = in_pseudo(ip4->ip_src.s_addr,
  382                                     ip4->ip_dst.s_addr, htons(ip4->ip_p + plen - hlen));
  383 
  384                                 if ((priv->conf->csum_offload & CSUM_UDP) == 0) {
  385                                         uh->uh_sum = in_cksum_skip(m,
  386                                             l3_offset + plen, l3_offset + hlen);
  387 
  388                                         if (uh->uh_sum == 0)
  389                                                 uh->uh_sum = 0xffff;
  390 
  391                                         m->m_pkthdr.csum_flags &= ~CSUM_UDP;
  392                                 }
  393 
  394                                 processed = 1;
  395                         }
  396 
  397                         m->m_pkthdr.csum_flags &= ~CSUM_TCP;
  398                         break;
  399 
  400                 default:
  401                         m->m_pkthdr.csum_flags &= ~(CSUM_TCP|CSUM_UDP);
  402                         break;
  403         }
  404 
  405         m->m_pkthdr.csum_flags &= ~NG_CHECKSUM_CSUM_IPV6;
  406 
  407         if (processed)
  408                 priv->stats.processed++;
  409 
  410         return (0);
  411 }
  412 #endif /* INET */
  413 
  414 #ifdef INET6
  415 static int
  416 checksum_ipv6(priv_p priv, struct mbuf *m, int l3_offset)
  417 {
  418         struct ip6_hdr *ip6;
  419         struct ip6_ext *ip6e = NULL;
  420         int pullup_len;
  421         int hlen, plen;
  422         int nxt;
  423         int processed = 0;
  424 
  425         pullup_len = l3_offset;
  426 
  427         PULLUP_CHECK(m, sizeof(struct ip6_hdr));
  428         ip6 = (struct ip6_hdr *) mtodo(m, l3_offset);
  429 
  430         if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
  431                 return (EOPNOTSUPP);
  432 
  433         hlen = sizeof(struct ip6_hdr);
  434         plen = ntohs(ip6->ip6_plen) + hlen;
  435 
  436         if (m->m_pkthdr.len < l3_offset + plen)
  437                 return (EINVAL);
  438 
  439         nxt = ip6->ip6_nxt;
  440 
  441         for (;;) {
  442                 switch (nxt)
  443                 {
  444                         case IPPROTO_DSTOPTS:
  445                         case IPPROTO_HOPOPTS:
  446                         case IPPROTO_ROUTING:
  447                                 PULLUP_CHECK(m, sizeof(struct ip6_ext));
  448                                 ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen);
  449                                 nxt = ip6e->ip6e_nxt;
  450                                 hlen += (ip6e->ip6e_len + 1) << 3;
  451                                 pullup_len = l3_offset + hlen;
  452                                 break;
  453 
  454                         case IPPROTO_AH:
  455                                 PULLUP_CHECK(m, sizeof(struct ip6_ext));
  456                                 ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen);
  457                                 nxt = ip6e->ip6e_nxt;
  458                                 hlen += (ip6e->ip6e_len + 2) << 2;
  459                                 pullup_len = l3_offset + hlen;
  460                                 break;
  461 
  462                         case IPPROTO_FRAGMENT:
  463                                 /* We can not calculate a checksum fragmented packets */
  464                                 m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6);
  465                                 return (0);
  466 
  467                         default:
  468                                 goto loopend;
  469                 }
  470 
  471                 if (nxt == 0)
  472                         return (EINVAL);
  473         }
  474 
  475 loopend:
  476 
  477         switch (nxt)
  478         {
  479                 case IPPROTO_TCP:
  480                         if (m->m_pkthdr.csum_flags & CSUM_TCP_IPV6) {
  481                                 struct tcphdr *th;
  482 
  483                                 PULLUP_CHECK(m, sizeof(struct tcphdr));
  484                                 th = (struct tcphdr *) mtodo(m, l3_offset + hlen);
  485 
  486                                 th->th_sum = in6_cksum_pseudo(ip6, plen - hlen, nxt, 0);
  487 
  488                                 if ((priv->conf->csum_offload & CSUM_TCP_IPV6) == 0) {
  489                                         th->th_sum = in_cksum_skip(m, l3_offset + plen, l3_offset + hlen);
  490                                         m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
  491                                 }
  492 
  493                                 processed = 1;
  494                         }
  495 
  496                         m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
  497                         break;
  498 
  499                 case IPPROTO_UDP:
  500                         if (m->m_pkthdr.csum_flags & CSUM_UDP_IPV6) {
  501                                 struct udphdr *uh;
  502 
  503                                 PULLUP_CHECK(m, sizeof(struct udphdr));
  504                                 uh = (struct udphdr *) mtodo(m, l3_offset + hlen);
  505 
  506                                 uh->uh_sum = in6_cksum_pseudo(ip6, plen - hlen, nxt, 0);
  507 
  508                                 if ((priv->conf->csum_offload & CSUM_UDP_IPV6) == 0) {
  509                                         uh->uh_sum = in_cksum_skip(m,
  510                                             l3_offset + plen, l3_offset + hlen);
  511 
  512                                         if (uh->uh_sum == 0)
  513                                                 uh->uh_sum = 0xffff;
  514 
  515                                         m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
  516                                 }
  517 
  518                                 processed = 1;
  519                         }
  520 
  521                         m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
  522                         break;
  523 
  524                 default:
  525                         m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6);
  526                         break;
  527         }
  528 
  529         m->m_pkthdr.csum_flags &= ~NG_CHECKSUM_CSUM_IPV4;
  530 
  531         if (processed)
  532                 priv->stats.processed++;
  533 
  534         return (0);
  535 }
  536 #endif /* INET6 */
  537 
  538 #undef  PULLUP_CHECK
  539 
  540 static int
  541 ng_checksum_rcvdata(hook_p hook, item_p item)
  542 {
  543         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  544         struct mbuf *m;
  545         hook_p out;
  546         int error = 0;
  547 
  548         priv->stats.received++;
  549 
  550         NGI_GET_M(item, m);
  551 
  552 #define PULLUP_CHECK(mbuf, length) do {                                 \
  553         pullup_len += length;                                           \
  554         if (((mbuf)->m_pkthdr.len < pullup_len) ||                      \
  555             (pullup_len > MHLEN)) {                                     \
  556                 error = EINVAL;                                         \
  557                 goto bypass;                                            \
  558         }                                                               \
  559         if ((mbuf)->m_len < pullup_len &&                               \
  560             (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {        \
  561                 error = ENOBUFS;                                        \
  562                 goto drop;                                              \
  563         }                                                               \
  564 } while (0)
  565 
  566         if (!(priv->conf && hook == priv->in && m && (m->m_flags & M_PKTHDR)))
  567                 goto bypass;
  568 
  569         m->m_pkthdr.csum_flags |= priv->conf->csum_flags;
  570 
  571         if (m->m_pkthdr.csum_flags & (NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6))
  572         {
  573                 struct ether_header *eh;
  574                 struct ng_checksum_vlan_header *vh;
  575                 int pullup_len = 0;
  576                 uint16_t etype;
  577 
  578                 m = m_unshare(m, M_NOWAIT);
  579 
  580                 if (m == NULL)
  581                         ERROUT(ENOMEM);
  582 
  583                 switch (priv->dlt)
  584                 {
  585                         case DLT_EN10MB:
  586                                 PULLUP_CHECK(m, sizeof(struct ether_header));
  587                                 eh = mtod(m, struct ether_header *);
  588                                 etype = ntohs(eh->ether_type);
  589 
  590                                 for (;;) {      /* QinQ support */
  591                                         switch (etype)
  592                                         {
  593                                                 case 0x8100:
  594                                                 case 0x88A8:
  595                                                 case 0x9100:
  596                                                         PULLUP_CHECK(m, sizeof(struct ng_checksum_vlan_header));
  597                                                         vh = (struct ng_checksum_vlan_header *) mtodo(m,
  598                                                             pullup_len - sizeof(struct ng_checksum_vlan_header));
  599                                                         etype = ntohs(vh->etype);
  600                                                         break;
  601 
  602                                                 default:
  603                                                         goto loopend;
  604                                         }
  605                                 }
  606 loopend:
  607 #ifdef INET
  608                                 if (etype == ETHERTYPE_IP &&
  609                                     (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV4)) {
  610                                         error = checksum_ipv4(priv, m, pullup_len);
  611                                         if (error == ENOBUFS)
  612                                                 goto drop;
  613                                 } else
  614 #endif
  615 #ifdef INET6
  616                                 if (etype == ETHERTYPE_IPV6 &&
  617                                     (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV6)) {
  618                                         error = checksum_ipv6(priv, m, pullup_len);
  619                                         if (error == ENOBUFS)
  620                                                 goto drop;
  621                                 } else
  622 #endif
  623                                 {
  624                                         m->m_pkthdr.csum_flags &=
  625                                             ~(NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6);
  626                                 }
  627 
  628                                 break;
  629 
  630                         case DLT_RAW:
  631 #ifdef INET
  632                                 if (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV4)
  633                                 {
  634                                         error = checksum_ipv4(priv, m, pullup_len);
  635 
  636                                         if (error == 0)
  637                                                 goto bypass;
  638                                         else if (error == ENOBUFS)
  639                                                 goto drop;
  640                                 }
  641 #endif
  642 #ifdef INET6
  643                                 if (m->m_pkthdr.csum_flags & NG_CHECKSUM_CSUM_IPV6)
  644                                 {
  645                                         error = checksum_ipv6(priv, m, pullup_len);
  646 
  647                                         if (error == 0)
  648                                                 goto bypass;
  649                                         else if (error == ENOBUFS)
  650                                                 goto drop;
  651                                 }
  652 #endif
  653                                 if (error)
  654                                         m->m_pkthdr.csum_flags &=
  655                                             ~(NG_CHECKSUM_CSUM_IPV4|NG_CHECKSUM_CSUM_IPV6);
  656 
  657                                 break;
  658 
  659                         default:
  660                                 ERROUT(EINVAL);
  661                 }
  662         }
  663 
  664 #undef  PULLUP_CHECK
  665 
  666 bypass:
  667         out = NULL;
  668 
  669         if (hook == priv->in) {
  670                 /* return frames on 'in' hook if 'out' not connected */
  671                 out = priv->out ? priv->out : priv->in;
  672         } else if (hook == priv->out && priv->in) {
  673                 /* pass frames on 'out' hook if 'in' connected */
  674                 out = priv->in;
  675         }
  676 
  677         if (out == NULL)
  678                 ERROUT(0);
  679 
  680         NG_FWD_NEW_DATA(error, item, out, m);
  681 
  682         return (error);
  683 
  684 done:
  685         NG_FREE_M(m);
  686 drop:
  687         NG_FREE_ITEM(item);
  688 
  689         priv->stats.dropped++;
  690 
  691         return (error);
  692 }
  693 
  694 static int
  695 ng_checksum_shutdown(node_p node)
  696 {
  697         const priv_p priv = NG_NODE_PRIVATE(node);
  698 
  699         NG_NODE_SET_PRIVATE(node, NULL);
  700         NG_NODE_UNREF(node);
  701 
  702         if (priv->conf)
  703                 free(priv->conf, M_NETGRAPH);
  704 
  705         free(priv, M_NETGRAPH);
  706 
  707         return (0);
  708 }
  709 
  710 static int
  711 ng_checksum_disconnect(hook_p hook)
  712 {
  713         priv_p priv;
  714 
  715         priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  716 
  717         if (hook == priv->in)
  718                 priv->in = NULL;
  719 
  720         if (hook == priv->out)
  721                 priv->out = NULL;
  722 
  723         if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
  724             NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */
  725                 ng_rmnode_self(NG_HOOK_NODE(hook));
  726 
  727         return (0);
  728 }

Cache object: 0313f9bc136b9f022c0870b6396a6643


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