Annotation of embedaddon/libnet/src/libnet_checksum.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *  $Id: libnet_checksum.c,v 1.13 2004/03/01 20:26:12 mike 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>