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:
tass
Date:
Thu Sep 26 07:05:22 2013 +0000
Revision:
70:cd218dd180e5
Parent:
68:0847e35d08a6
Child:
73:dfb737147f6e
Update from masterbranch

Who changed what in which revision?

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