Annotation of qemu/net/checksum.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *  IP checksumming functions.
        !             3:  *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
        !             4:  *
        !             5:  *  This program is free software; you can redistribute it and/or modify
        !             6:  *  it under the terms of the GNU General Public License as published by
        !             7:  *  the Free Software Foundation; under version 2 of the License.
        !             8:  *
        !             9:  *  This program is distributed in the hope that it will be useful,
        !            10:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            12:  *  GNU General Public License for more details.
        !            13:  *
        !            14:  *  You should have received a copy of the GNU General Public License
        !            15:  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
        !            16:  */
        !            17: 
        !            18: #include "net/checksum.h"
        !            19: 
        !            20: #define PROTO_TCP  6
        !            21: #define PROTO_UDP 17
        !            22: 
        !            23: uint32_t net_checksum_add(int len, uint8_t *buf)
        !            24: {
        !            25:     uint32_t sum = 0;
        !            26:     int i;
        !            27: 
        !            28:     for (i = 0; i < len; i++) {
        !            29:        if (i & 1)
        !            30:            sum += (uint32_t)buf[i];
        !            31:        else
        !            32:            sum += (uint32_t)buf[i] << 8;
        !            33:     }
        !            34:     return sum;
        !            35: }
        !            36: 
        !            37: uint16_t net_checksum_finish(uint32_t sum)
        !            38: {
        !            39:     while (sum>>16)
        !            40:        sum = (sum & 0xFFFF)+(sum >> 16);
        !            41:     return ~sum;
        !            42: }
        !            43: 
        !            44: uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
        !            45:                              uint8_t *addrs, uint8_t *buf)
        !            46: {
        !            47:     uint32_t sum = 0;
        !            48: 
        !            49:     sum += net_checksum_add(length, buf);         // payload
        !            50:     sum += net_checksum_add(8, addrs);            // src + dst address
        !            51:     sum += proto + length;                        // protocol & length
        !            52:     return net_checksum_finish(sum);
        !            53: }
        !            54: 
        !            55: void net_checksum_calculate(uint8_t *data, int length)
        !            56: {
        !            57:     int hlen, plen, proto, csum_offset;
        !            58:     uint16_t csum;
        !            59: 
        !            60:     if ((data[14] & 0xf0) != 0x40)
        !            61:        return; /* not IPv4 */
        !            62:     hlen  = (data[14] & 0x0f) * 4;
        !            63:     plen  = (data[16] << 8 | data[17]) - hlen;
        !            64:     proto = data[23];
        !            65: 
        !            66:     switch (proto) {
        !            67:     case PROTO_TCP:
        !            68:        csum_offset = 16;
        !            69:        break;
        !            70:     case PROTO_UDP:
        !            71:        csum_offset = 6;
        !            72:        break;
        !            73:     default:
        !            74:        return;
        !            75:     }
        !            76: 
        !            77:     if (plen < csum_offset+2)
        !            78:        return;
        !            79: 
        !            80:     data[14+hlen+csum_offset]   = 0;
        !            81:     data[14+hlen+csum_offset+1] = 0;
        !            82:     csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen);
        !            83:     data[14+hlen+csum_offset]   = csum >> 8;
        !            84:     data[14+hlen+csum_offset+1] = csum & 0xff;
        !            85: }

unix.superglobalmegacorp.com