Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
daniele
Date:
Thu Jul 25 08:43:55 2013 +0000
Revision:
46:c35c84e301e0
Parent:
29:1a47b7151851
Child:
51:ab4529a384a6
Fixed issue #3 by a merge from master

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 29:1a47b7151851 1 /*********************************************************************
daniele 29:1a47b7151851 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 29:1a47b7151851 3 See LICENSE and COPYING for usage.
daniele 29:1a47b7151851 4
daniele 29:1a47b7151851 5 .
daniele 29:1a47b7151851 6
daniele 29:1a47b7151851 7 Authors: Daniele Lacamera
daniele 29:1a47b7151851 8 *********************************************************************/
daniele 29:1a47b7151851 9
daniele 29:1a47b7151851 10
daniele 29:1a47b7151851 11 #include "pico_icmp4.h"
daniele 29:1a47b7151851 12 #include "pico_config.h"
daniele 29:1a47b7151851 13 #include "pico_ipv4.h"
daniele 29:1a47b7151851 14 #include "pico_eth.h"
daniele 29:1a47b7151851 15 #include "pico_device.h"
daniele 29:1a47b7151851 16 #include "pico_stack.h"
daniele 29:1a47b7151851 17 #include "pico_tree.h"
daniele 29:1a47b7151851 18
daniele 29:1a47b7151851 19 /* Queues */
daniele 29:1a47b7151851 20 static struct pico_queue icmp_in = {};
daniele 29:1a47b7151851 21 static struct pico_queue icmp_out = {};
daniele 29:1a47b7151851 22
daniele 29:1a47b7151851 23
daniele 29:1a47b7151851 24 /* Functions */
daniele 29:1a47b7151851 25
daniele 29:1a47b7151851 26 static int pico_icmp4_checksum(struct pico_frame *f)
daniele 29:1a47b7151851 27 {
daniele 29:1a47b7151851 28 struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 29 if (!hdr) {
daniele 29:1a47b7151851 30 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 31 return -1;
daniele 29:1a47b7151851 32 }
daniele 29:1a47b7151851 33 hdr->crc = 0;
daniele 29:1a47b7151851 34 hdr->crc = short_be(pico_checksum(hdr, f->transport_len));
daniele 29:1a47b7151851 35 return 0;
daniele 29:1a47b7151851 36 }
daniele 29:1a47b7151851 37
daniele 29:1a47b7151851 38 #ifdef PICO_SUPPORT_PING
daniele 29:1a47b7151851 39 static void ping_recv_reply(struct pico_frame *f);
daniele 29:1a47b7151851 40 #endif
daniele 29:1a47b7151851 41
daniele 29:1a47b7151851 42 static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f)
daniele 29:1a47b7151851 43 {
daniele 29:1a47b7151851 44 struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 45 if (hdr->type == PICO_ICMP_ECHO) {
daniele 29:1a47b7151851 46 hdr->type = PICO_ICMP_ECHOREPLY;
daniele 46:c35c84e301e0 47 /* outgoing frames require a f->len without the ethernet header len */
daniele 29:1a47b7151851 48 if (f->dev->eth)
daniele 29:1a47b7151851 49 f->len -= PICO_SIZE_ETHHDR;
daniele 46:c35c84e301e0 50 pico_icmp4_checksum(f);
daniele 29:1a47b7151851 51 pico_ipv4_rebound(f);
daniele 29:1a47b7151851 52 } else if (hdr->type == PICO_ICMP_UNREACH) {
daniele 29:1a47b7151851 53 f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 54 pico_ipv4_unreachable(f, hdr->code);
daniele 29:1a47b7151851 55 } else if (hdr->type == PICO_ICMP_ECHOREPLY) {
daniele 29:1a47b7151851 56 #ifdef PICO_SUPPORT_PING
daniele 29:1a47b7151851 57 ping_recv_reply(f);
daniele 29:1a47b7151851 58 #endif
daniele 29:1a47b7151851 59 pico_frame_discard(f);
daniele 29:1a47b7151851 60 } else {
daniele 29:1a47b7151851 61 pico_frame_discard(f);
daniele 29:1a47b7151851 62 }
daniele 29:1a47b7151851 63 return 0;
daniele 29:1a47b7151851 64 }
daniele 29:1a47b7151851 65
daniele 29:1a47b7151851 66 static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
daniele 29:1a47b7151851 67 {
daniele 29:1a47b7151851 68 dbg("Called %s\n", __FUNCTION__);
daniele 29:1a47b7151851 69 return 0;
daniele 29:1a47b7151851 70 }
daniele 29:1a47b7151851 71
daniele 29:1a47b7151851 72 /* Interface: protocol definition */
daniele 29:1a47b7151851 73 struct pico_protocol pico_proto_icmp4 = {
daniele 29:1a47b7151851 74 .name = "icmp4",
daniele 29:1a47b7151851 75 .proto_number = PICO_PROTO_ICMP4,
daniele 29:1a47b7151851 76 .layer = PICO_LAYER_TRANSPORT,
daniele 29:1a47b7151851 77 .process_in = pico_icmp4_process_in,
daniele 29:1a47b7151851 78 .process_out = pico_icmp4_process_out,
daniele 29:1a47b7151851 79 .q_in = &icmp_in,
daniele 29:1a47b7151851 80 .q_out = &icmp_out,
daniele 29:1a47b7151851 81 };
daniele 29:1a47b7151851 82
daniele 29:1a47b7151851 83 static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code)
daniele 29:1a47b7151851 84 {
daniele 29:1a47b7151851 85 struct pico_frame *reply;
daniele 29:1a47b7151851 86 struct pico_icmp4_hdr *hdr;
daniele 29:1a47b7151851 87 struct pico_ipv4_hdr *info;
daniele 29:1a47b7151851 88 if (f == NULL) {
daniele 29:1a47b7151851 89 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 90 return -1;
daniele 29:1a47b7151851 91 }
daniele 29:1a47b7151851 92 reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, 8 + sizeof(struct pico_ipv4_hdr) + PICO_ICMPHDR_UN_SIZE);
daniele 29:1a47b7151851 93 info = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 29:1a47b7151851 94 hdr = (struct pico_icmp4_hdr *) reply->transport_hdr;
daniele 29:1a47b7151851 95 hdr->type = type;
daniele 29:1a47b7151851 96 hdr->code = code;
daniele 29:1a47b7151851 97 hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500);
daniele 29:1a47b7151851 98 hdr->hun.ih_pmtu.ipm_void = 0;
daniele 29:1a47b7151851 99 reply->transport_len = 8 + sizeof(struct pico_ipv4_hdr) + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 100 reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 101 memcpy(reply->payload, f->net_hdr, 8 + sizeof(struct pico_ipv4_hdr));
daniele 29:1a47b7151851 102 pico_icmp4_checksum(reply);
daniele 29:1a47b7151851 103 pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4);
daniele 29:1a47b7151851 104 return 0;
daniele 29:1a47b7151851 105 }
daniele 29:1a47b7151851 106
daniele 29:1a47b7151851 107 int pico_icmp4_port_unreachable(struct pico_frame *f)
daniele 29:1a47b7151851 108 {
daniele 29:1a47b7151851 109 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 110 return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PORT);
daniele 29:1a47b7151851 111 }
daniele 29:1a47b7151851 112
daniele 29:1a47b7151851 113 int pico_icmp4_proto_unreachable(struct pico_frame *f)
daniele 29:1a47b7151851 114 {
daniele 29:1a47b7151851 115 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 116 return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PROTOCOL);
daniele 29:1a47b7151851 117 }
daniele 29:1a47b7151851 118
daniele 29:1a47b7151851 119 int pico_icmp4_dest_unreachable(struct pico_frame *f)
daniele 29:1a47b7151851 120 {
daniele 29:1a47b7151851 121 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 122 return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_HOST);
daniele 29:1a47b7151851 123 }
daniele 29:1a47b7151851 124
daniele 29:1a47b7151851 125 int pico_icmp4_ttl_expired(struct pico_frame *f)
daniele 29:1a47b7151851 126 {
daniele 29:1a47b7151851 127 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 128 return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS);
daniele 29:1a47b7151851 129 }
daniele 29:1a47b7151851 130
daniele 29:1a47b7151851 131 int pico_icmp4_packet_filtered(struct pico_frame *f)
daniele 29:1a47b7151851 132 {
daniele 29:1a47b7151851 133 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 134 /*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/
daniele 29:1a47b7151851 135 return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB);
daniele 29:1a47b7151851 136 }
daniele 29:1a47b7151851 137
daniele 29:1a47b7151851 138 /***********************/
daniele 29:1a47b7151851 139 /* Ping implementation */
daniele 29:1a47b7151851 140 /***********************/
daniele 29:1a47b7151851 141 /***********************/
daniele 29:1a47b7151851 142 /***********************/
daniele 29:1a47b7151851 143 /***********************/
daniele 29:1a47b7151851 144
daniele 29:1a47b7151851 145
daniele 29:1a47b7151851 146 #ifdef PICO_SUPPORT_PING
daniele 29:1a47b7151851 147
daniele 29:1a47b7151851 148
daniele 29:1a47b7151851 149 struct pico_icmp4_ping_cookie
daniele 29:1a47b7151851 150 {
daniele 29:1a47b7151851 151 struct pico_ip4 dst;
daniele 29:1a47b7151851 152 uint16_t err;
daniele 29:1a47b7151851 153 uint16_t id;
daniele 29:1a47b7151851 154 uint16_t seq;
daniele 29:1a47b7151851 155 uint16_t size;
daniele 29:1a47b7151851 156 int count;
daniele 29:1a47b7151851 157 unsigned long timestamp;
daniele 29:1a47b7151851 158 int interval;
daniele 29:1a47b7151851 159 int timeout;
daniele 29:1a47b7151851 160 void (*cb)(struct pico_icmp4_stats*);
daniele 29:1a47b7151851 161
daniele 29:1a47b7151851 162 };
daniele 29:1a47b7151851 163
daniele 29:1a47b7151851 164 static int cookie_compare(void *ka, void *kb)
daniele 29:1a47b7151851 165 {
daniele 29:1a47b7151851 166 struct pico_icmp4_ping_cookie *a = ka, *b = kb;
daniele 29:1a47b7151851 167 if (a->id < b->id)
daniele 29:1a47b7151851 168 return -1;
daniele 29:1a47b7151851 169 if (a->id > b->id)
daniele 29:1a47b7151851 170 return 1;
daniele 29:1a47b7151851 171 return (a->seq - b->seq);
daniele 29:1a47b7151851 172 }
daniele 29:1a47b7151851 173
daniele 29:1a47b7151851 174 PICO_TREE_DECLARE(Pings,cookie_compare);
daniele 29:1a47b7151851 175
daniele 29:1a47b7151851 176 static int pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
daniele 29:1a47b7151851 177 {
daniele 29:1a47b7151851 178 struct pico_frame *echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, PICO_ICMPHDR_UN_SIZE + cookie->size);
daniele 29:1a47b7151851 179 struct pico_icmp4_hdr *hdr;
daniele 29:1a47b7151851 180
daniele 29:1a47b7151851 181 hdr = (struct pico_icmp4_hdr *) echo->transport_hdr;
daniele 29:1a47b7151851 182
daniele 29:1a47b7151851 183 hdr->type = PICO_ICMP_ECHO;
daniele 29:1a47b7151851 184 hdr->code = 0;
daniele 29:1a47b7151851 185 hdr->hun.ih_idseq.idseq_id = short_be(cookie->id);
daniele 29:1a47b7151851 186 hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq);
daniele 29:1a47b7151851 187 echo->transport_len = PICO_ICMPHDR_UN_SIZE + cookie->size;
daniele 29:1a47b7151851 188 echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 189 echo->payload_len = cookie->size;
daniele 29:1a47b7151851 190 /* XXX: Fill payload */
daniele 29:1a47b7151851 191 pico_icmp4_checksum(echo);
daniele 29:1a47b7151851 192 pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4);
daniele 29:1a47b7151851 193 return 0;
daniele 29:1a47b7151851 194 }
daniele 29:1a47b7151851 195
daniele 29:1a47b7151851 196
daniele 29:1a47b7151851 197 static void ping_timeout(unsigned long now, void *arg)
daniele 29:1a47b7151851 198 {
daniele 29:1a47b7151851 199 struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg;
daniele 29:1a47b7151851 200 if(pico_tree_findKey(&Pings,cookie)){
daniele 29:1a47b7151851 201 if (cookie->err == PICO_PING_ERR_PENDING) {
daniele 29:1a47b7151851 202 struct pico_icmp4_stats stats;
daniele 29:1a47b7151851 203 stats.dst = cookie->dst;
daniele 29:1a47b7151851 204 stats.seq = cookie->seq;
daniele 29:1a47b7151851 205 stats.time = 0;
daniele 29:1a47b7151851 206 stats.size = cookie->size;
daniele 29:1a47b7151851 207 stats.err = PICO_PING_ERR_TIMEOUT;
daniele 29:1a47b7151851 208 dbg(" ---- Ping timeout!!!\n");
daniele 29:1a47b7151851 209 cookie->cb(&stats);
daniele 29:1a47b7151851 210 }
daniele 29:1a47b7151851 211
daniele 29:1a47b7151851 212 pico_tree_delete(&Pings,cookie);
daniele 29:1a47b7151851 213 pico_free(cookie);
daniele 29:1a47b7151851 214 }
daniele 29:1a47b7151851 215 }
daniele 29:1a47b7151851 216
daniele 29:1a47b7151851 217 static void next_ping(unsigned long now, void *arg);
daniele 29:1a47b7151851 218 static inline void send_ping(struct pico_icmp4_ping_cookie *cookie)
daniele 29:1a47b7151851 219 {
daniele 29:1a47b7151851 220 pico_icmp4_send_echo(cookie);
daniele 29:1a47b7151851 221 cookie->timestamp = pico_tick;
daniele 29:1a47b7151851 222 pico_timer_add(cookie->timeout, ping_timeout, cookie);
daniele 29:1a47b7151851 223 if (cookie->seq < cookie->count)
daniele 29:1a47b7151851 224 pico_timer_add(cookie->interval, next_ping, cookie);
daniele 29:1a47b7151851 225 }
daniele 29:1a47b7151851 226
daniele 29:1a47b7151851 227 static void next_ping(unsigned long now, void *arg)
daniele 29:1a47b7151851 228 {
daniele 29:1a47b7151851 229 struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
daniele 29:1a47b7151851 230
daniele 29:1a47b7151851 231 if(pico_tree_findKey(&Pings,cookie)){
daniele 29:1a47b7151851 232 if (cookie->seq < cookie->count) {
daniele 29:1a47b7151851 233 newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
daniele 29:1a47b7151851 234 if (!newcookie)
daniele 29:1a47b7151851 235 return;
daniele 29:1a47b7151851 236 memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
daniele 29:1a47b7151851 237 newcookie->seq++;
daniele 29:1a47b7151851 238
daniele 29:1a47b7151851 239 pico_tree_insert(&Pings,newcookie);
daniele 29:1a47b7151851 240 send_ping(newcookie);
daniele 29:1a47b7151851 241 }
daniele 29:1a47b7151851 242 }
daniele 29:1a47b7151851 243 }
daniele 29:1a47b7151851 244
daniele 29:1a47b7151851 245
daniele 29:1a47b7151851 246 static void ping_recv_reply(struct pico_frame *f)
daniele 29:1a47b7151851 247 {
daniele 29:1a47b7151851 248 struct pico_icmp4_ping_cookie test, *cookie;
daniele 29:1a47b7151851 249 struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 250 test.id = short_be(hdr->hun.ih_idseq.idseq_id );
daniele 29:1a47b7151851 251 test.seq = short_be(hdr->hun.ih_idseq.idseq_seq);
daniele 29:1a47b7151851 252
daniele 29:1a47b7151851 253 cookie = pico_tree_findKey(&Pings, &test);
daniele 29:1a47b7151851 254 if (cookie) {
daniele 29:1a47b7151851 255 struct pico_icmp4_stats stats;
daniele 29:1a47b7151851 256 cookie->err = PICO_PING_ERR_REPLIED;
daniele 29:1a47b7151851 257 stats.dst = cookie->dst;
daniele 29:1a47b7151851 258 stats.seq = cookie->seq;
daniele 29:1a47b7151851 259 stats.size = cookie->size;
daniele 29:1a47b7151851 260 stats.time = pico_tick - cookie->timestamp;
daniele 29:1a47b7151851 261 stats.err = cookie->err;
daniele 29:1a47b7151851 262 stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl;
daniele 29:1a47b7151851 263 if(cookie->cb != NULL)
daniele 29:1a47b7151851 264 cookie->cb(&stats);
daniele 29:1a47b7151851 265 } else {
daniele 29:1a47b7151851 266 dbg("Reply for seq=%d, not found.\n", test.seq);
daniele 29:1a47b7151851 267 }
daniele 29:1a47b7151851 268 }
daniele 29:1a47b7151851 269
daniele 29:1a47b7151851 270 int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *))
daniele 29:1a47b7151851 271 {
daniele 29:1a47b7151851 272 static uint16_t next_id = 0x91c0;
daniele 29:1a47b7151851 273 struct pico_icmp4_ping_cookie *cookie;
daniele 29:1a47b7151851 274
daniele 29:1a47b7151851 275 if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)){
daniele 29:1a47b7151851 276 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 277 return -1;
daniele 29:1a47b7151851 278 }
daniele 29:1a47b7151851 279
daniele 29:1a47b7151851 280 cookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
daniele 29:1a47b7151851 281 if (!cookie) {
daniele 29:1a47b7151851 282 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 283 return -1;
daniele 29:1a47b7151851 284 }
daniele 29:1a47b7151851 285
daniele 29:1a47b7151851 286 if (pico_string_to_ipv4(dst, &cookie->dst.addr) < 0) {
daniele 29:1a47b7151851 287 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 288 pico_free(cookie);
daniele 29:1a47b7151851 289 return -1;
daniele 29:1a47b7151851 290 }
daniele 29:1a47b7151851 291 cookie->seq = 1;
daniele 29:1a47b7151851 292 cookie->id = next_id++;
daniele 29:1a47b7151851 293 cookie->err = PICO_PING_ERR_PENDING;
daniele 29:1a47b7151851 294 cookie->size = size;
daniele 29:1a47b7151851 295 cookie->interval = interval;
daniele 29:1a47b7151851 296 cookie->timeout = timeout;
daniele 29:1a47b7151851 297 cookie->cb = cb;
daniele 29:1a47b7151851 298 cookie->count = count;
daniele 29:1a47b7151851 299
daniele 29:1a47b7151851 300 pico_tree_insert(&Pings,cookie);
daniele 29:1a47b7151851 301 send_ping(cookie);
daniele 29:1a47b7151851 302
daniele 29:1a47b7151851 303 return 0;
daniele 29:1a47b7151851 304
daniele 29:1a47b7151851 305 }
daniele 29:1a47b7151851 306
daniele 29:1a47b7151851 307 #endif