Stefan Schuermans commited on 2012-03-24 19:03:45
              Showing 1 changed files, with 113 additions and 7 deletions.
            
| ... | ... | @@ -6,10 +6,58 @@ | 
| 6 | 6 | #include "nethelp.h" | 
| 7 | 7 | #include "udp.h" | 
| 8 | 8 |  | 
| 9 | +// some kind of "token bucket" for UDP echo | |
| 10 | +#define UDP_ECHO_TICKS 10 ///< allowed rate of UDP echo replies (in 200ms) | |
| 11 | +static unsigned int udp_echo_tick_cnt = 0; ///< tick counter | |
| 12 | +#define UDP_ECHO_REPLIES_MAX 3 ///< maximum value for udp_echo_replies | |
| 13 | +static unsigned int udp_echo_replies = 0; // # of allowed UDP echo replies | |
| 14 | + | |
| 9 | 15 | /// tick procedure - call every 200ms | 
| 10 | 16 | void udp_tick200(void) | 
| 11 | 17 |  { | 
| 12 | - // TODO | |
| 18 | + // count ticks | |
| 19 | + udp_echo_tick_cnt++; | |
| 20 | + // time to allow one reply more | |
| 21 | +  if (udp_echo_tick_cnt >= UDP_ECHO_TICKS) { | |
| 22 | + udp_echo_tick_cnt = 0; | |
| 23 | + | |
| 24 | + // increase reply count if not at maximum | |
| 25 | + if (udp_echo_replies < UDP_ECHO_REPLIES_MAX) | |
| 26 | + udp_echo_replies++; | |
| 27 | + } | |
| 28 | +} | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * @brief process a received UDP echo packet | |
| 32 | + * @param[in] ptr pointer to data of packet | |
| 33 | + * @param[in] sz size of packet | |
| 34 | + */ | |
| 35 | +static void udp_echo_recv(void *ptr, unsigned int sz) | |
| 36 | +{ | |
| 37 | + struct udp_packet *udp_pack; | |
| 38 | + | |
| 39 | + udp_pack = ptr; | |
| 40 | + | |
| 41 | + // source port is UDP echo port | |
| 42 | + if (udp_pack->udp_hdr.src_port == htons(7)) | |
| 43 | + // ignore this packet | |
| 44 | + // - UDP echo answer to another UDP echo port will result | |
| 45 | + // in endless echoing | |
| 46 | + return; | |
| 47 | + | |
| 48 | + // only reply with allowed packet rate | |
| 49 | + if (udp_echo_replies <= 0) | |
| 50 | + return; | |
| 51 | + udp_echo_replies--; | |
| 52 | + | |
| 53 | + // send an UDP echo | |
| 54 | + // - use same buffer to send reply | |
| 55 | + // - this saves us from allocating a new buffer | |
| 56 | + // - this saves us from copying the data | |
| 57 | + udp_pack->udp_hdr.dest_port = udp_pack->udp_hdr.src_port; // to source port | |
| 58 | + udp_pack->udp_hdr.src_port = htons(7); // UDP echo port | |
| 59 | + ip_cpy( udp_pack->ip_hdr.dest, udp_pack->ip_hdr.src); // to source IP | |
| 60 | + udp_send(udp_pack, sz); | |
| 13 | 61 | } | 
| 14 | 62 |  | 
| 15 | 63 | /** | 
| ... | ... | @@ -19,9 +67,42 @@ void udp_tick200(void) | 
| 19 | 67 | */ | 
| 20 | 68 | void udp_recv(void *ptr, unsigned int sz) | 
| 21 | 69 |  { | 
| 22 | - // TODO | |
| 23 | - (void)ptr; | |
| 24 | - (void)sz; | |
| 70 | + struct udp_packet *udp_pack; | |
| 71 | + unsigned int len; | |
| 72 | + | |
| 73 | + // packet too short | |
| 74 | + if (sz < sizeof(struct udp_packet)) | |
| 75 | + return; | |
| 76 | + | |
| 77 | + udp_pack = ptr; | |
| 78 | + | |
| 79 | + // ignore packets sent from or to port 0 (not allowed by RFC) | |
| 80 | + if (udp_pack->udp_hdr.src_port == htons(0) || | |
| 81 | + udp_pack->udp_hdr.dest_port == htons(0)) | |
| 82 | + return; | |
| 83 | + | |
| 84 | + // check total length | |
| 85 | + len = sizeof(struct ethernet_header) + sizeof(struct ip_header) + | |
| 86 | + ntohs(udp_pack->udp_hdr.length); // length according to UDP header | |
| 87 | + if (sz < len) // packet is truncated | |
| 88 | + return; | |
| 89 | + sz = len; // remove IP padding from packet (maybe sz > len) | |
| 90 | + | |
| 91 | + // test checksum | |
| 92 | + if (checksum(&udp_pack->ip_hdr.src, | |
| 93 | + sz - sizeof(struct ethernet_header) | |
| 94 | + - sizeof(struct ip_header ) + 8, | |
| 95 | + 0x0011, | |
| 96 | + ntohs(udp_pack->udp_hdr.length))) | |
| 97 | + return; | |
| 98 | + | |
| 99 | + // branch according to destination port | |
| 100 | +  switch (ntohs(udp_pack->udp_hdr.dest_port)) { | |
| 101 | + // UDP echo | |
| 102 | + case 7: | |
| 103 | + udp_echo_recv(ptr, sz); | |
| 104 | + break; | |
| 105 | + } | |
| 25 | 106 | } | 
| 26 | 107 |  | 
| 27 | 108 | /** | 
| ... | ... | @@ -35,8 +116,33 @@ void udp_recv(void *ptr, unsigned int sz) | 
| 35 | 116 | */ | 
| 36 | 117 | void udp_send(void *ptr, unsigned int sz) | 
| 37 | 118 |  { | 
| 38 | - // TODO | |
| 39 | - (void)ptr; | |
| 40 | - (void)sz; | |
| 119 | + struct udp_packet *udp_pack; | |
| 120 | + unsigned int chk; | |
| 121 | + | |
| 122 | + // packet too short | |
| 123 | + if (sz < sizeof(struct udp_packet)) | |
| 124 | + return; | |
| 125 | + | |
| 126 | + udp_pack = ptr; | |
| 127 | + | |
| 128 | + // fill in header values | |
| 129 | + udp_pack->udp_hdr.length = htons(sz - sizeof(struct ethernet_header) | |
| 130 | + - sizeof(struct ip_header)); | |
| 131 | + udp_pack->udp_hdr.chk = 0x0000; | |
| 132 | + /* put IP already here into IP header | |
| 133 | + because it is needed for calculation of UDP checksum */ | |
| 134 | + ip_cpy(udp_pack->ip_hdr.src, config_ip.ip); | |
| 135 | + | |
| 136 | + // generate checksum | |
| 137 | + chk = checksum(&udp_pack->ip_hdr.src, | |
| 138 | + sz - sizeof(struct ethernet_header ) | |
| 139 | + - sizeof(struct ip_header ) + 8, | |
| 140 | + 0x0011, | |
| 141 | + ntohs(udp_pack->udp_hdr.length)); | |
| 142 | + udp_pack->udp_hdr.chk = htons(chk); | |
| 143 | + | |
| 144 | + // send UDP packet | |
| 145 | + udp_pack->ip_hdr.proto = 0x11; // UDP | |
| 146 | + ip_send(udp_pack, sz); | |
| 41 | 147 | } | 
| 42 | 148 |  | 
| 43 | 149 |