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,7 +472,7 @@ endif #CONFIG_DARWIN_USER | ||
| 472 | # System emulator target | 472 | # System emulator target |
| 473 | ifndef CONFIG_USER_ONLY | 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 | ifdef CONFIG_WIN32 | 476 | ifdef CONFIG_WIN32 |
| 477 | OBJS+=block-raw-win32.o | 477 | OBJS+=block-raw-win32.o |
| 478 | else | 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,4 +48,11 @@ struct NICInfo { | ||
| 48 | extern int nb_nics; | 48 | extern int nb_nics; |
| 49 | extern NICInfo nd_table[MAX_NICS]; | 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 | #endif | 58 | #endif |