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 | ... | ... |