VirtualBox

Changeset 10966 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Jul 30, 2008 2:40:20 AM (16 years ago)
Author:
vboxsync
Message:

IPRT: some more IP checksumming stuff (hope it works).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/checksum/ipv4.cpp

    r10964 r10966  
    4040 *
    4141 * @returns Checksum.
    42  * @param   pIpHdr      Pointer to the IPv4 header to checksum. Assumes
    43  *                      the caller already checked the minimum size requirement.
     42 * @param   pIpHdr      Pointer to the IPv4 header to checksum, network endian (big).
     43 *                      Assumes the caller already checked the minimum size requirement.
    4444 */
    4545RTDECL(uint16_t) RTNetIPv4Checksum(PCRTNETIPV4 pIpHdr)
    4646{
    4747    uint16_t const *paw = (uint16_t const *)pIpHdr;
    48     int32_t iSum = paw[0]              /* ip_hl */
    49                  + paw[1]              /* ip_len */
    50                  + paw[2]              /* ip_id */
    51                  + paw[3]              /* ip_off */
    52                  + paw[4]              /* ip_ttl */
    53                  /*+ paw[5] == 0 */    /* ip_sum */
    54                  + paw[6]              /* ip_src */
    55                  + paw[7]              /* ip_src:16 */
    56                  + paw[8]              /* ip_dst */
    57                  + paw[9];             /* ip_dst:16 */
     48    int32_t iSum = paw[0]               /* ip_hl */
     49                 + paw[1]               /* ip_len */
     50                 + paw[2]               /* ip_id */
     51                 + paw[3]               /* ip_off */
     52                 + paw[4]               /* ip_ttl */
     53                 /*+ paw[5] == 0 */     /* ip_sum */
     54                 + paw[6]               /* ip_src */
     55                 + paw[7]               /* ip_src:16 */
     56                 + paw[8]               /* ip_dst */
     57                 + paw[9];              /* ip_dst:16 */
    5858    /* any options */
    5959    if (pIpHdr->ip_hl > 20 / 4)
    6060    {
    61         /* this is a bit insane... */
     61        /* this is a bit insane... (identical to the TCP header) */
    6262        switch (pIpHdr->ip_hl)
    6363        {
     
    9090 *
    9191 * @returns true if valid, false if invalid.
    92  * @param   pIpHdr      Pointer to the IPv4 header to validate.
     92 * @param   pIpHdr      Pointer to the IPv4 header to validate. Network endian (big).
    9393 * @param   cbHdrMax    The max header size, or  the max size of what pIpHdr points
    9494 *                      to if you like. Note that an IPv4 header can be up to 60 bytes.
     
    119119
    120120
     121/**
     122 * Calculates the checksum of a pseudo header given an IPv4 header.
     123 *
     124 * @returns 32-bit intermediary checksum value.
     125 * @param   pIpHdr      The IP header (network endian (big)).
     126 */
     127RTDECL(uint32_t) RTNetIPv4PseudoChecksum(PCRTNETIPV4 pIpHdr)
     128{
     129    uint16_t cbPayload = RT_BE2H_U16(pIpHdr->ip_len) - pIpHdr->ip_hl * 4;
     130    uint32_t iSum = pIpHdr->ip_src.au16[0]
     131                  + pIpHdr->ip_src.au16[1]
     132                  + pIpHdr->ip_dst.au16[0]
     133                  + pIpHdr->ip_dst.au16[1]
     134#ifdef RT_BIG_ENDIAN
     135                  + pIpHdr->ip_p
     136#else
     137                  + ((uint32_t)pIpHdr->ip_p << 8)
     138#endif
     139                  + RT_H2BE_U16(cbPayload);
     140    return iSum;
     141}
     142
     143
     144/**
     145 * Calculates the checksum of a pseudo header given the individual components.
     146 *
     147 * @returns 32-bit intermediary checksum value.
     148 * @param   SrcAddr         The source address in host endian.
     149 * @param   DstAddr         The destination address in host endian.
     150 * @param   bProtocol       The protocol number.
     151 * @param   cbPkt           The packet size (host endian of course) (no IPv4 header).
     152 */
     153RTDECL(uint32_t) RTNetIPv4PseudoChecksumBits(RTNETADDRIPV4 SrcAddr, RTNETADDRIPV4 DstAddr, uint8_t bProtocol, uint16_t cbPkt)
     154{
     155    uint32_t iSum = RT_H2BE_U16(SrcAddr.au16[0])
     156                  + RT_H2BE_U16(SrcAddr.au16[1])
     157                  + RT_H2BE_U16(DstAddr.au16[0])
     158                  + RT_H2BE_U16(DstAddr.au16[1])
     159#ifdef RT_BIG_ENDIAN
     160                  + bProtocol
     161#else
     162                  + ((uint32_t)bProtocol << 8)
     163#endif
     164                  + RT_H2BE_U16(cbPkt);
     165    return iSum;
     166}
     167
     168
     169/**
     170 * Adds the checksum of the UDP header to the intermediate checksum value.
     171 *
     172 * @returns 32-bit intermediary checksum value.
     173 * @param   pUdpHdr         Pointer to the UDP header to checksum, network endian (big).
     174 * @param   iSum            The 32-bit intermediate checksum value.
     175 */
     176RTDECL(uint32_t) RTNetIPv4AddUDPChecksum(PCRTNETUDP pUdpHdr, uint32_t iSum)
     177{
     178    iSum += pUdpHdr->uh_sport
     179          + pUdpHdr->uh_dport
     180          /*+ pUdpHdr->uh_sum = 0 */
     181          + pUdpHdr->uh_ulen;
     182    return iSum;
     183}
     184
     185
     186/**
     187 * Adds the checksum of the TCP header to the intermediate checksum value.
     188 *
     189 * @returns 32-bit intermediary checksum value.
     190 * @param   pUdpHdr         Pointer to the TCP header to checksum, network endian (big).
     191 *                          Assums the caller has already validate it and made sure the
     192 *                          entire header is present.
     193 * @param   iSum            The 32-bit intermediate checksum value.
     194 */
     195RTDECL(uint32_t) RTNetIPv4AddTCPChecksum(PCRTNETTCP pTcpHdr, uint32_t iSum)
     196{
     197    uint16_t const *paw = (uint16_t const *)pTcpHdr;
     198    iSum += paw[0]                      /* th_sport */
     199          + paw[1]                      /* th_dport */
     200          + paw[2]                      /* th_seq */
     201          + paw[3]                      /* th_seq:16 */
     202          + paw[4]                      /* th_ack */
     203          + paw[5]                      /* th_ack:16 */
     204          + paw[6]                      /* th_off, th_x2, th_flags */
     205          + paw[7]                      /* th_win */
     206          /*+ paw[8] == 0 */            /* th_sum */
     207          + paw[9];                     /* th_urp */
     208    if (pTcpHdr->th_off > RTNETTCP_MIN_LEN / 4)
     209    {
     210        /* this is a bit insane... (identical to the IPv4 header) */
     211        switch (pTcpHdr->th_off)
     212        {
     213            case 6:  iSum += paw[10] + paw[11]; break;
     214            case 7:  iSum += paw[10] + paw[11] + paw[12] + paw[13]; break;
     215            case 8:  iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15]; break;
     216            case 9:  iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17]; break;
     217            case 10: iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19]; break;
     218            case 11: iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21]; break;
     219            case 12: iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23]; break;
     220            case 13: iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25]; break;
     221            case 14: iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25] + paw[26] + paw[27]; break;
     222            case 15: iSum += paw[10] + paw[11] + paw[12] + paw[13] + paw[14] + paw[15] + paw[16] + paw[17] + paw[18] + paw[19] + paw[20] + paw[21] + paw[22] + paw[23] + paw[24] + paw[25] + paw[26] + paw[27] + paw[28] + paw[29]; break;
     223            default:
     224                AssertFailed();
     225        }
     226    }
     227
     228    return iSum;
     229}
     230
     231
     232/**
     233 * Adds the checksum of the specified data segment to the intermediate checksum value.
     234 *
     235 * @returns 32-bit intermediary checksum value.
     236 * @param   pUdpHdr         Pointer to the UDP header to checksum, network endian (big).
     237 * @param   iSum            The 32-bit intermediate checksum value.
     238 * @param   pfOdd           This is used to keep track of odd bits, initialize to false
     239 *                          when starting to checksum the data (aka text) after a TCP
     240 *                          or UDP header (data never start at an odd offset).
     241 */
     242RTDECL(uint32_t) RTNetIPv4AddDataChecksum(void const *pvData, size_t cbData, uint32_t iSum, bool *pfOdd)
     243{
     244    if (*pfOdd)
     245    {
     246#ifdef RT_BIG_ENDIAN
     247        /* there was an odd byte in the previous chunk, add the lower byte. */
     248        iSum += *(uint8_t *)pvData;
     249#else
     250        /* there was an odd byte in the previous chunk, add the upper byte. */
     251        iSum += (uint32_t)*(uint8_t *)pvData << 8;
     252#endif
     253        /* skip the byte. */
     254        cbData--;
     255        if (!cbData)
     256            return iSum;
     257        pvData = (uint8_t const *)pvData + 1;
     258    }
     259
     260    /* iterate the data. */
     261    uint16_t const *pw = (uint16_t const *)pvData;
     262    while (cbData > 1)
     263    {
     264        iSum += *pw;
     265        pw += 2;
     266        cbData -= 2;
     267    }
     268
     269    /* handle odd byte. */
     270    if (cbData)
     271    {
     272#ifdef RT_BIG_ENDIAN
     273        iSum += (uint32_t)*(uint8_t *)pw << 8;
     274#else
     275        iSum += *(uint8_t *)pw;
     276#endif
     277        *pfOdd = true;
     278    }
     279    else
     280        *pfOdd = false;
     281    return iSum;
     282}
     283
     284
     285/**
     286 * Finalizes a IPv4 checksum.
     287 *
     288 * @returns The checksum.
     289 * @param   iSum            The 32-bit intermediate checksum value.
     290 */
     291RTDECL(uint16_t) RTNetIPv4FinalizeChecksum(uint32_t iSum)
     292{
     293    /* 16-bit one complement fun */
     294    iSum = (iSum >> 16) + (iSum & 0xffff);  /* hi + low words */
     295    iSum += iSum >> 16;                     /* carry */
     296    return (uint16_t)~iSum;
     297}
     298
     299
     300
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette