Commit 48c643630c5e994e4885dceb45a5da1c403a678a
1 parent
dd5e6304
Add IP checksumming functions to qemu (Gerd Hoffmann)
This can be shared between the e1000, virtio-net, and xennet. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4971 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
95 additions
and
1 deletions
Makefile.target
... | ... | @@ -472,7 +472,7 @@ endif #CONFIG_DARWIN_USER |
472 | 472 | # System emulator target |
473 | 473 | ifndef CONFIG_USER_ONLY |
474 | 474 | |
475 | -OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o | |
475 | +OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o | |
476 | 476 | ifdef CONFIG_WIN32 |
477 | 477 | OBJS+=block-raw-win32.o |
478 | 478 | else | ... | ... |
net-checksum.c
0 → 100644
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, write to the Free Software | |
16 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
17 | + */ | |
18 | + | |
19 | +#include "hw/hw.h" | |
20 | +#include "net.h" | |
21 | + | |
22 | +#define PROTO_TCP 6 | |
23 | +#define PROTO_UDP 17 | |
24 | + | |
25 | +uint32_t net_checksum_add(int len, uint8_t *buf) | |
26 | +{ | |
27 | + uint32_t sum = 0; | |
28 | + int i; | |
29 | + | |
30 | + for (i = 0; i < len; i++) { | |
31 | + if (i & 1) | |
32 | + sum += (uint32_t)buf[i]; | |
33 | + else | |
34 | + sum += (uint32_t)buf[i] << 8; | |
35 | + } | |
36 | + return sum; | |
37 | +} | |
38 | + | |
39 | +uint16_t net_checksum_finish(uint32_t sum) | |
40 | +{ | |
41 | + while (sum>>16) | |
42 | + sum = (sum & 0xFFFF)+(sum >> 16); | |
43 | + return ~sum; | |
44 | +} | |
45 | + | |
46 | +uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, | |
47 | + uint8_t *addrs, uint8_t *buf) | |
48 | +{ | |
49 | + uint32_t sum = 0; | |
50 | + | |
51 | + sum += net_checksum_add(length, buf); // payload | |
52 | + sum += net_checksum_add(8, addrs); // src + dst address | |
53 | + sum += proto + length; // protocol & length | |
54 | + return net_checksum_finish(sum); | |
55 | +} | |
56 | + | |
57 | +void net_checksum_calculate(uint8_t *data, int length) | |
58 | +{ | |
59 | + int hlen, plen, proto, csum_offset; | |
60 | + uint16_t csum; | |
61 | + | |
62 | + if ((data[14] & 0xf0) != 0x40) | |
63 | + return; /* not IPv4 */ | |
64 | + hlen = (data[14] & 0x0f) * 4; | |
65 | + plen = (data[16] << 8 | data[17]) - hlen; | |
66 | + proto = data[23]; | |
67 | + | |
68 | + switch (proto) { | |
69 | + case PROTO_TCP: | |
70 | + csum_offset = 16; | |
71 | + break; | |
72 | + case PROTO_UDP: | |
73 | + csum_offset = 6; | |
74 | + break; | |
75 | + default: | |
76 | + return; | |
77 | + } | |
78 | + | |
79 | + if (plen < csum_offset+2) | |
80 | + return; | |
81 | + | |
82 | + data[14+hlen+csum_offset] = 0; | |
83 | + data[14+hlen+csum_offset+1] = 0; | |
84 | + csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen); | |
85 | + data[14+hlen+csum_offset] = csum >> 8; | |
86 | + data[14+hlen+csum_offset+1] = csum & 0xff; | |
87 | +} | ... | ... |
net.h
... | ... | @@ -48,4 +48,11 @@ struct NICInfo { |
48 | 48 | extern int nb_nics; |
49 | 49 | extern NICInfo nd_table[MAX_NICS]; |
50 | 50 | |
51 | +/* checksumming functions (net-checksum.c) */ | |
52 | +uint32_t net_checksum_add(int len, uint8_t *buf); | |
53 | +uint16_t net_checksum_finish(uint32_t sum); | |
54 | +uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, | |
55 | + uint8_t *addrs, uint8_t *buf); | |
56 | +void net_checksum_calculate(uint8_t *data, int length); | |
57 | + | |
51 | 58 | #endif | ... | ... |