File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_checksum.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:14:23 2012 UTC (12 years, 4 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_2_1, HEAD
libnet

    1: /*
    2:  *  $Id: libnet_checksum.c,v 1.1.1.1 2012/02/21 22:14:23 misho Exp $
    3:  *
    4:  *  libnet
    5:  *  libnet_checksum.c - checksum routines
    6:  *
    7:  *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
    8:  *  All rights reserved.
    9:  *
   10:  * Redistribution and use in source and binary forms, with or without
   11:  * modification, are permitted provided that the following conditions
   12:  * are met:
   13:  * 1. Redistributions of source code must retain the above copyright
   14:  *    notice, this list of conditions and the following disclaimer.
   15:  * 2. Redistributions in binary form must reproduce the above copyright
   16:  *    notice, this list of conditions and the following disclaimer in the
   17:  *    documentation and/or other materials provided with the distribution.
   18:  *
   19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29:  * SUCH DAMAGE.
   30:  *
   31:  */
   32: 
   33: #if (HAVE_CONFIG_H)
   34: #include "../include/config.h"
   35: #endif
   36: #if (!(_WIN32) || (__CYGWIN__)) 
   37: #include "../include/libnet.h"
   38: #else
   39: #include "../include/win32/libnet.h"
   40: #endif
   41: int
   42: libnet_in_cksum(u_int16_t *addr, int len)
   43: {
   44:     int sum;
   45: 
   46:     sum = 0;
   47: 
   48:     while (len > 1)
   49:     {
   50:         sum += *addr++;
   51:         len -= 2;
   52:     }
   53:     if (len == 1)
   54:     {
   55:         sum += *(u_int16_t *)addr;
   56:     }
   57: 
   58:     return (sum);
   59: }
   60: 
   61: int
   62: libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode)
   63: {
   64:     libnet_pblock_t *p;
   65: 
   66:     p = libnet_pblock_find(l, ptag);
   67:     if (p == NULL)
   68:     {
   69:         /* err msg set in libnet_pblock_find() */
   70:         return (-1);
   71:     }
   72:     if (mode == LIBNET_ON)
   73:     {
   74:         if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
   75:         {
   76:             return (1);
   77:         }
   78:         else
   79:         {
   80:             (p->flags) |= LIBNET_PBLOCK_DO_CHECKSUM;
   81:             return (1);
   82:         }
   83:     }
   84:     else
   85:     {
   86:         if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
   87:         {
   88:             (p->flags) &= ~LIBNET_PBLOCK_DO_CHECKSUM;
   89:             return (1);
   90:         }
   91:         else
   92:         {
   93:             return (1);
   94:         }
   95:     }
   96: }
   97: 
   98: 
   99: int
  100: libnet_do_checksum(libnet_t *l, u_int8_t *buf, int protocol, int len)
  101: {
  102:     /* will need to update this for ipv6 at some point */
  103:     struct libnet_ipv4_hdr *iph_p;
  104:     struct libnet_ipv6_hdr *ip6h_p;
  105:     int is_ipv6;
  106:     int ip_hl;
  107:     int sum;
  108: 
  109:     is_ipv6 = 0;    /* default to not using IPv6 */
  110:     sum     = 0;
  111:     iph_p   = NULL;
  112:     ip6h_p  = NULL;
  113: 
  114:     if (len == 0)
  115:     {
  116:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  117:             "%s(): header length can't be zero\n", __func__);
  118:         return (-1);
  119:     }
  120: 
  121:     /*
  122:      *  Figure out which IP version we're dealing with.  We'll assume v4
  123:      *  and overlay a header structure to yank out the version.
  124:      */
  125:     iph_p = (struct libnet_ipv4_hdr *)buf;
  126:     if (iph_p && iph_p->ip_v == 6)
  127:     {
  128:         ip6h_p = (struct libnet_ipv6_hdr *)buf;
  129:         is_ipv6 = 1;
  130:         ip_hl   = 40;
  131:     }
  132:     else
  133:     {
  134:         is_ipv6 = 0;
  135:         ip_hl = iph_p->ip_hl << 2;
  136:     }
  137: 
  138:     /*
  139:      *  Dug Song came up with this very cool checksuming implementation
  140:      *  eliminating the need for explicit psuedoheader use.  Check it out.
  141:      */
  142:     switch (protocol)
  143:     {
  144:         /*
  145:          *  Style note: normally I don't advocate declaring variables inside
  146:          *  blocks of control, but it makes good sense here. -- MDS
  147:          */
  148:         case IPPROTO_TCP:
  149:         {
  150:             struct libnet_tcp_hdr *tcph_p =
  151:                 (struct libnet_tcp_hdr *)(buf + ip_hl);
  152: 
  153: #if (STUPID_SOLARIS_CHECKSUM_BUG)
  154:             tcph_p->th_sum = tcph_p->th_off << 2;
  155:             return (1);
  156: #endif /* STUPID_SOLARIS_CHECKSUM_BUG */
  157: #if (HAVE_HPUX11)   
  158:             if (l->injection_type != LIBNET_LINK)
  159:             {
  160:                 /*
  161:                  *  Similiar to the Solaris Checksum bug - but need to add
  162:                  *  the size of the TCP payload (only for raw sockets).
  163:                  */
  164:                 tcph_p->th_sum = (tcph_p->th_off << 2) +
  165:                         (len - (tcph_p->th_off << 2));
  166:                 return (1); 
  167:             }
  168: #endif
  169:             tcph_p->th_sum = 0;
  170:             if (is_ipv6)
  171:             {
  172:                 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
  173:             }
  174:             else
  175:             {
  176:                 sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
  177:             }
  178:             sum += ntohs(IPPROTO_TCP + len);
  179:             sum += libnet_in_cksum((u_int16_t *)tcph_p, len);
  180:             tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
  181:             break;
  182:         }
  183:         case IPPROTO_UDP:
  184:         {
  185:             struct libnet_udp_hdr *udph_p =
  186:                 (struct libnet_udp_hdr *)(buf + ip_hl);
  187:             udph_p->uh_sum = 0;
  188:             if (is_ipv6)
  189:             {
  190:                 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
  191:             }
  192:             else
  193:             {
  194:                 sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
  195:             }
  196:             sum += ntohs(IPPROTO_UDP + len);
  197:             sum += libnet_in_cksum((u_int16_t *)udph_p, len);
  198:             udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
  199:             break;
  200:         }
  201:         case IPPROTO_ICMP:
  202:         {
  203:             struct libnet_icmpv4_hdr *icmph_p =
  204:                 (struct libnet_icmpv4_hdr *)(buf + ip_hl);
  205: 
  206:             icmph_p->icmp_sum = 0;
  207:             if (is_ipv6)
  208:             {
  209:                 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
  210:                 sum += ntohs(IPPROTO_ICMP6 + len);
  211:             }
  212:             sum += libnet_in_cksum((u_int16_t *)icmph_p, len);
  213:             icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
  214:             break;
  215:         }
  216:         case IPPROTO_IGMP:
  217:         {
  218:             struct libnet_igmp_hdr *igmph_p =
  219:                 (struct libnet_igmp_hdr *)(buf + ip_hl);
  220: 
  221:             igmph_p->igmp_sum = 0;
  222:             sum = libnet_in_cksum((u_int16_t *)igmph_p, len);
  223:             igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
  224:             break;
  225:         }
  226: 	case IPPROTO_GRE:
  227: 	{
  228:             /* checksum is always at the same place in GRE header
  229:              * in the multiple RFC version of the protocol ... ouf !!!
  230:              */
  231: 	    struct libnet_gre_hdr *greh_p = 
  232: 		(struct libnet_gre_hdr *)(buf + ip_hl);
  233: 	    u_int16_t fv = ntohs(greh_p->flags_ver);
  234: 	    if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
  235:                 !(fv & (GRE_CSUM|GRE_VERSION_1)))
  236: 	    {
  237: 		snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  238:                 "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n",  __func__, fv);
  239: 		return (-1);
  240: 	    }
  241: 	    sum = libnet_in_cksum((u_int16_t *)greh_p, len);
  242: 	    greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
  243: 	    break;
  244: 	}
  245:         case IPPROTO_OSPF:
  246:         {
  247:             struct libnet_ospf_hdr *oh_p =
  248:                 (struct libnet_ospf_hdr *)(buf + ip_hl);
  249: 
  250:             oh_p->ospf_sum = 0;
  251:             sum += libnet_in_cksum((u_int16_t *)oh_p, len);
  252:             oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
  253:             break;
  254:         }
  255:         case IPPROTO_OSPF_LSA:
  256:         {
  257:             struct libnet_ospf_hdr *oh_p =
  258:                 (struct libnet_ospf_hdr *)(buf + ip_hl);
  259:             struct libnet_lsa_hdr *lsa_p =
  260:                 (struct libnet_lsa_hdr *)(buf + 
  261:                 ip_hl + oh_p->ospf_len);
  262: 
  263:             lsa_p->lsa_sum = 0;
  264:             sum += libnet_in_cksum((u_int16_t *)lsa_p, len);
  265:             lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
  266:             break;
  267: #if 0
  268:             /*
  269:              *  Reworked fletcher checksum taken from RFC 1008.
  270:              */
  271:             int c0, c1;
  272:             struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
  273:             u_int8_t *p, *p1, *p2, *p3;
  274: 
  275:             c0 = 0;
  276:             c1 = 0;
  277: 
  278:             lsa_p->lsa_cksum = 0;
  279: 
  280:             p = buf;
  281:             p1 = buf;
  282:             p3 = buf + len;             /* beginning and end of buf */
  283: 
  284:             while (p1 < p3)
  285:             {
  286:                 p2 = p1 + LIBNET_MODX;
  287:                 if (p2 > p3)
  288:                 {
  289:                     p2 = p3;
  290:                 }
  291:   
  292:                 for (p = p1; p < p2; p++)
  293:                 {
  294:                     c0 += (*p);
  295:                     c1 += c0;
  296:                 }
  297: 
  298:                 c0 %= 255;
  299:                 c1 %= 255;      /* modular 255 */
  300:  
  301:                 p1 = p2;
  302:             }
  303: 
  304: #if AWR_PLEASE_REWORK_THIS
  305:             lsa_p->lsa_cksum[0] = (((len - 17) * c0 - c1) % 255);
  306:             if (lsa_p->lsa_cksum[0] <= 0)
  307:             {
  308:                 lsa_p->lsa_cksum[0] += 255;
  309:             }
  310: 
  311:             lsa_p->lsa_cksum[1] = (510 - c0 - lsa_p->lsa_cksum[0]);
  312:             if (lsa_p->lsa_cksum[1] > 255)
  313:             {
  314:                 lsa_p->lsa_cksum[1] -= 255;
  315:             }
  316: #endif
  317:             break;
  318: #endif
  319:         }
  320:         case IPPROTO_IP:
  321:         {
  322:             iph_p->ip_sum = 0;
  323:             sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl);
  324:             iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
  325:             break;
  326:         }
  327:         case IPPROTO_VRRP:
  328:         {
  329:             struct libnet_vrrp_hdr *vrrph_p =
  330:                 (struct libnet_vrrp_hdr *)(buf + ip_hl);
  331: 
  332:             vrrph_p->vrrp_sum = 0;
  333:             sum = libnet_in_cksum((u_int16_t *)vrrph_p, len);
  334:             vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
  335:             break;
  336:         }
  337:         case LIBNET_PROTO_CDP:
  338:         {   /* XXX - Broken: how can we easily get the entire packet size? */
  339:             struct libnet_cdp_hdr *cdph_p =
  340:                 (struct libnet_cdp_hdr *)buf;
  341: 
  342:             cdph_p->cdp_sum = 0;
  343:             sum = libnet_in_cksum((u_int16_t *)cdph_p, len);
  344:             cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
  345:             break;
  346:         }
  347:         case LIBNET_PROTO_ISL:
  348:         {
  349:            // struct libnet_isl_hdr *islh_p =
  350:            //     (struct libnet_isl_hdr *)buf;
  351:             /*
  352:              *  Need to compute 4 byte CRC for the ethernet frame and for
  353:              *  the ISL frame itself.  Use the libnet_crc function.
  354:              */
  355:         }
  356:         default:
  357:         {
  358:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  359:                 "%s(): unsuported protocol %d\n", __func__, protocol);
  360:             return (-1);
  361:         }
  362:     }
  363:     return (1);
  364: }
  365: 
  366: 
  367: u_int16_t
  368: libnet_ip_check(u_int16_t *addr, int len)
  369: {
  370:     int sum;
  371: 
  372:     sum = libnet_in_cksum(addr, len);
  373:     return (LIBNET_CKSUM_CARRY(sum));
  374: }
  375: 
  376: /* EOF */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>