simple reliable networking over ethernet. Provides IPv4 ARP, ICMP echo reply, and UDP unicast. Does NOT provide TCP, that's not simple :-).
inet.cpp@0:6df0a6ed91d4, 2015-03-04 (annotated)
- Committer:
- altasoul
- Date:
- Wed Mar 04 02:04:32 2015 +0000
- Revision:
- 0:6df0a6ed91d4
- Child:
- 2:397316d97354
refactor into Snet
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
altasoul | 0:6df0a6ed91d4 | 1 | #include "flyer.h" |
altasoul | 0:6df0a6ed91d4 | 2 | #include "snet.h" |
altasoul | 0:6df0a6ed91d4 | 3 | |
altasoul | 0:6df0a6ed91d4 | 4 | void handle_icmp_packet(uint8_t *buf, int len); |
altasoul | 0:6df0a6ed91d4 | 5 | void handle_udp_packet(uint8_t *buf, int len); |
altasoul | 0:6df0a6ed91d4 | 6 | |
altasoul | 0:6df0a6ed91d4 | 7 | //extern Ethernet eth; |
altasoul | 0:6df0a6ed91d4 | 8 | //extern uint8_t my_mac[]; |
altasoul | 0:6df0a6ed91d4 | 9 | //uint8_t my_ip[4] = { 192, 168, 32, 191 }; |
altasoul | 0:6df0a6ed91d4 | 10 | |
altasoul | 0:6df0a6ed91d4 | 11 | //extern uint16_t ip_checksum_of(const uint8_t *buf, int len); |
altasoul | 0:6df0a6ed91d4 | 12 | //extern uint16_t ones_complement_sum(const uint8_t *buf, const int len, int sum); |
altasoul | 0:6df0a6ed91d4 | 13 | |
altasoul | 0:6df0a6ed91d4 | 14 | //-- IP utilities |
altasoul | 0:6df0a6ed91d4 | 15 | |
altasoul | 0:6df0a6ed91d4 | 16 | // Calculate the ones' complement sum of a buffer, initialized |
altasoul | 0:6df0a6ed91d4 | 17 | // See also RFC1071 http://tools.ietf.org/html/rfc1071 |
altasoul | 0:6df0a6ed91d4 | 18 | uint16_t Snet::ones_complement_sum(const uint8_t *buf, int len, int sum) { |
altasoul | 0:6df0a6ed91d4 | 19 | for (int i=0; i<len/2; i++) { |
altasoul | 0:6df0a6ed91d4 | 20 | sum += (buf[0] << 8) + (buf[1]); |
altasoul | 0:6df0a6ed91d4 | 21 | buf += 2; |
altasoul | 0:6df0a6ed91d4 | 22 | } |
altasoul | 0:6df0a6ed91d4 | 23 | if (len & 1) sum += buf[0] << 8; // odd length |
altasoul | 0:6df0a6ed91d4 | 24 | while (sum & 0xffff0000) sum = (sum & 0xffff) + (sum >> 16); |
altasoul | 0:6df0a6ed91d4 | 25 | return sum; |
altasoul | 0:6df0a6ed91d4 | 26 | } |
altasoul | 0:6df0a6ed91d4 | 27 | |
altasoul | 0:6df0a6ed91d4 | 28 | // Calculate the RFC1071 IP checksum. No assumption about byte alignment is made. |
altasoul | 0:6df0a6ed91d4 | 29 | uint16_t Snet::ip_checksum_of(const uint8_t *buf, const int len) { |
altasoul | 0:6df0a6ed91d4 | 30 | return ~ones_complement_sum(buf, len, 0); |
altasoul | 0:6df0a6ed91d4 | 31 | }; |
altasoul | 0:6df0a6ed91d4 | 32 | |
altasoul | 0:6df0a6ed91d4 | 33 | void Snet::turn_ip_packet_around(uint8_t *buf) { |
altasoul | 0:6df0a6ed91d4 | 34 | memcpy(&buf[ENET_DMAC_O], &buf[ENET_SMAC_O], 6); |
altasoul | 0:6df0a6ed91d4 | 35 | memcpy(&buf[ENET_SMAC_O], my_mac, 6); |
altasoul | 0:6df0a6ed91d4 | 36 | memcpy(&buf[IP_DADDR_O], &buf[IP_SADDR_O], 4); |
altasoul | 0:6df0a6ed91d4 | 37 | memcpy(&buf[IP_SADDR_O], my_ip, 4); |
altasoul | 0:6df0a6ed91d4 | 38 | }; |
altasoul | 0:6df0a6ed91d4 | 39 | |
altasoul | 0:6df0a6ed91d4 | 40 | |
altasoul | 0:6df0a6ed91d4 | 41 | void Snet::handle_icmp_packet(uint8_t *buf, int len) { |
altasoul | 0:6df0a6ed91d4 | 42 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 43 | printf("ICMP:"); |
altasoul | 0:6df0a6ed91d4 | 44 | print_hex(&buf[ICMP_HEADER_O], len-ICMP_HEADER_O); |
altasoul | 0:6df0a6ed91d4 | 45 | #endif |
altasoul | 0:6df0a6ed91d4 | 46 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 47 | printf("ip header checksum = 0x%x\r\n", |
altasoul | 0:6df0a6ed91d4 | 48 | ip_checksum_of(&buf[IP_HEADER_O], IP_HEADER_LEN)); |
altasoul | 0:6df0a6ed91d4 | 49 | #endif |
altasoul | 0:6df0a6ed91d4 | 50 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 51 | printf("icmp checksum = 0x%x\r\n", |
altasoul | 0:6df0a6ed91d4 | 52 | ip_checksum_of(&buf[ICMP_HEADER_O], len-ICMP_HEADER_O)); |
altasoul | 0:6df0a6ed91d4 | 53 | #endif |
altasoul | 0:6df0a6ed91d4 | 54 | if (buf[ICMP_TYPE_O] != 8 || buf[ICMP_CODE_O] != 0) return; |
altasoul | 0:6df0a6ed91d4 | 55 | // Here we have ICMP echo request |
altasoul | 0:6df0a6ed91d4 | 56 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 57 | printf("ICMP echo request\r\n"); |
altasoul | 0:6df0a6ed91d4 | 58 | #endif |
altasoul | 0:6df0a6ed91d4 | 59 | buf[ICMP_TYPE_O] = 0x0; // make it an echo reply |
altasoul | 0:6df0a6ed91d4 | 60 | // Fix the ICMP checksum |
altasoul | 0:6df0a6ed91d4 | 61 | // HC' = ~(C + (-m) + m') -- [Eqn. 3] |
altasoul | 0:6df0a6ed91d4 | 62 | // = ~(~HC + ~m + m') |
altasoul | 0:6df0a6ed91d4 | 63 | // HC' = HC - ~m - m' -- [Eqn. 4] of RFC1624, where: |
altasoul | 0:6df0a6ed91d4 | 64 | // HC - old checksum in header |
altasoul | 0:6df0a6ed91d4 | 65 | // C - one's complement sum of old header |
altasoul | 0:6df0a6ed91d4 | 66 | // HC' - new checksum in header |
altasoul | 0:6df0a6ed91d4 | 67 | // m - old value of a 16-bit field |
altasoul | 0:6df0a6ed91d4 | 68 | // m' - new value of a 16-bit field |
altasoul | 0:6df0a6ed91d4 | 69 | // we have m == 0x800 and m' == 0 |
altasoul | 0:6df0a6ed91d4 | 70 | // so HC' = HC - ~0x800 = HC - 0xf7ff |
altasoul | 0:6df0a6ed91d4 | 71 | uint32_t sum = (buf[ICMP_CHECKSUM_O] << 8) |
altasoul | 0:6df0a6ed91d4 | 72 | + buf[ICMP_CHECKSUM_O + 1] |
altasoul | 0:6df0a6ed91d4 | 73 | - 0xf7ff; |
altasoul | 0:6df0a6ed91d4 | 74 | if (sum & 0xffff0000) sum -= 1; // handle borrow-around |
altasoul | 0:6df0a6ed91d4 | 75 | //printf("adj: 0x%x\r\n", sum); |
altasoul | 0:6df0a6ed91d4 | 76 | buf[ICMP_CHECKSUM_O] = sum >> 8; // type casting takes care of the masking |
altasoul | 0:6df0a6ed91d4 | 77 | buf[ICMP_CHECKSUM_O + 1] = sum; |
altasoul | 0:6df0a6ed91d4 | 78 | turn_ip_packet_around(buf); |
altasoul | 0:6df0a6ed91d4 | 79 | eth.write((char *) buf, len); |
altasoul | 0:6df0a6ed91d4 | 80 | eth.send(); |
altasoul | 0:6df0a6ed91d4 | 81 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 82 | printf("check new checksums: ip = 0x%x, icmp = 0x%x\r\n", |
altasoul | 0:6df0a6ed91d4 | 83 | ip_checksum_of(&buf[IP_HEADER_O], IP_HEADER_LEN), |
altasoul | 0:6df0a6ed91d4 | 84 | ip_checksum_of(&buf[ICMP_HEADER_O], len-ICMP_HEADER_O)); |
altasoul | 0:6df0a6ed91d4 | 85 | #endif |
altasoul | 0:6df0a6ed91d4 | 86 | #if 1 |
altasoul | 0:6df0a6ed91d4 | 87 | if (int v = ip_checksum_of(&buf[IP_HEADER_O], IP_HEADER_LEN)) |
altasoul | 0:6df0a6ed91d4 | 88 | printf("Bad new IP checksum: %d\r\n", v); |
altasoul | 0:6df0a6ed91d4 | 89 | if (int v = ip_checksum_of(&buf[ICMP_HEADER_O], len-ICMP_HEADER_O)) |
altasoul | 0:6df0a6ed91d4 | 90 | printf("Bad new ICMP checksum: %d\r\n", v); |
altasoul | 0:6df0a6ed91d4 | 91 | #endif |
altasoul | 0:6df0a6ed91d4 | 92 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 93 | printf("sent"); |
altasoul | 0:6df0a6ed91d4 | 94 | print_hex(buf, len); |
altasoul | 0:6df0a6ed91d4 | 95 | #endif |
altasoul | 0:6df0a6ed91d4 | 96 | }; |
altasoul | 0:6df0a6ed91d4 | 97 | |
altasoul | 0:6df0a6ed91d4 | 98 | |
altasoul | 0:6df0a6ed91d4 | 99 | void Snet::interpret_inet_packet(uint8_t *buf, int len) { |
altasoul | 0:6df0a6ed91d4 | 100 | //printf("Got inet:"); |
altasoul | 0:6df0a6ed91d4 | 101 | //print_hex(&buf[ENET_PAYLOAD_O], len-IP_HEADER_O); //DEBUG |
altasoul | 0:6df0a6ed91d4 | 102 | // skip packets with certain attributes we don't like |
altasoul | 0:6df0a6ed91d4 | 103 | #if 0 |
altasoul | 0:6df0a6ed91d4 | 104 | printf("ip header checksum = 0x%x\r\n", |
altasoul | 0:6df0a6ed91d4 | 105 | ip_checksum_of(&buf[IP_HEADER_O], IP_HEADER_LEN)); |
altasoul | 0:6df0a6ed91d4 | 106 | #endif |
altasoul | 0:6df0a6ed91d4 | 107 | if (buf[IP_VIHL_O] != 0x45 |
altasoul | 0:6df0a6ed91d4 | 108 | || buf[IP_FLAGS_FRAGOFF_O+0] & ~0x40 != 0x00 // allow Don't Fragment flag |
altasoul | 0:6df0a6ed91d4 | 109 | || buf[IP_FLAGS_FRAGOFF_O+1] != 0x00 |
altasoul | 0:6df0a6ed91d4 | 110 | || memcmp(&buf[IP_DADDR_O], my_ip, 4)) { |
altasoul | 0:6df0a6ed91d4 | 111 | printf("don't like: fragoff 0x%x, dest %d.%d.%d.%d\r\n", |
altasoul | 0:6df0a6ed91d4 | 112 | (buf[IP_FLAGS_FRAGOFF_O+0] << 8) + buf[IP_FLAGS_FRAGOFF_O+1], |
altasoul | 0:6df0a6ed91d4 | 113 | buf[IP_DADDR_O+0], |
altasoul | 0:6df0a6ed91d4 | 114 | buf[IP_DADDR_O+1], |
altasoul | 0:6df0a6ed91d4 | 115 | buf[IP_DADDR_O+2], |
altasoul | 0:6df0a6ed91d4 | 116 | buf[IP_DADDR_O+3] |
altasoul | 0:6df0a6ed91d4 | 117 | ); //DEBUG |
altasoul | 0:6df0a6ed91d4 | 118 | return; |
altasoul | 0:6df0a6ed91d4 | 119 | }; |
altasoul | 0:6df0a6ed91d4 | 120 | if (buf[IP_PROTO_O] == 0x01) handle_icmp_packet(buf, len); |
altasoul | 0:6df0a6ed91d4 | 121 | else if (buf[IP_PROTO_O] == 0x11) handle_udp_packet(buf, len); |
altasoul | 0:6df0a6ed91d4 | 122 | else printf("Protocol 0x%x\r\n", buf[IP_PROTO_O]); |
altasoul | 0:6df0a6ed91d4 | 123 | } |