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 19 12:38:53 2013 +0000
Revision:
63:97f481e33cb2
Parent:
51:ab4529a384a6
Update from the master branch

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 */
tass 63:97f481e33cb2 20 static struct pico_queue icmp_in = {};
tass 63:97f481e33cb2 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 {
tass 63:97f481e33cb2 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;
tass 63:97f481e33cb2 47 /* Ugly, but the best way to get ICMP data size here. */
tass 63:97f481e33cb2 48 f->transport_len = f->buffer_len - PICO_SIZE_IP4HDR;
tass 63:97f481e33cb2 49 if (f->dev->eth)
tass 63:97f481e33cb2 50 f->transport_len -= PICO_SIZE_ETHHDR;
tass 63:97f481e33cb2 51 pico_icmp4_checksum(f);
tass 63:97f481e33cb2 52 f->net_hdr = f->transport_hdr - PICO_SIZE_IP4HDR;
tass 63:97f481e33cb2 53 f->start = f->net_hdr;
tass 63:97f481e33cb2 54 f->len = f->buffer_len;
daniele 29:1a47b7151851 55 if (f->dev->eth)
daniele 29:1a47b7151851 56 f->len -= PICO_SIZE_ETHHDR;
daniele 29:1a47b7151851 57 pico_ipv4_rebound(f);
daniele 29:1a47b7151851 58 } else if (hdr->type == PICO_ICMP_UNREACH) {
daniele 29:1a47b7151851 59 f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 60 pico_ipv4_unreachable(f, hdr->code);
daniele 29:1a47b7151851 61 } else if (hdr->type == PICO_ICMP_ECHOREPLY) {
daniele 29:1a47b7151851 62 #ifdef PICO_SUPPORT_PING
daniele 29:1a47b7151851 63 ping_recv_reply(f);
daniele 29:1a47b7151851 64 #endif
daniele 29:1a47b7151851 65 pico_frame_discard(f);
daniele 29:1a47b7151851 66 } else {
daniele 29:1a47b7151851 67 pico_frame_discard(f);
daniele 29:1a47b7151851 68 }
daniele 29:1a47b7151851 69 return 0;
daniele 29:1a47b7151851 70 }
daniele 29:1a47b7151851 71
daniele 29:1a47b7151851 72 static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
daniele 29:1a47b7151851 73 {
tass 63:97f481e33cb2 74 dbg("Called %s\n", __FUNCTION__);
daniele 29:1a47b7151851 75 return 0;
daniele 29:1a47b7151851 76 }
daniele 29:1a47b7151851 77
daniele 29:1a47b7151851 78 /* Interface: protocol definition */
daniele 29:1a47b7151851 79 struct pico_protocol pico_proto_icmp4 = {
daniele 29:1a47b7151851 80 .name = "icmp4",
daniele 29:1a47b7151851 81 .proto_number = PICO_PROTO_ICMP4,
daniele 29:1a47b7151851 82 .layer = PICO_LAYER_TRANSPORT,
daniele 29:1a47b7151851 83 .process_in = pico_icmp4_process_in,
daniele 29:1a47b7151851 84 .process_out = pico_icmp4_process_out,
daniele 29:1a47b7151851 85 .q_in = &icmp_in,
daniele 29:1a47b7151851 86 .q_out = &icmp_out,
daniele 29:1a47b7151851 87 };
daniele 29:1a47b7151851 88
daniele 29:1a47b7151851 89 static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code)
daniele 29:1a47b7151851 90 {
daniele 29:1a47b7151851 91 struct pico_frame *reply;
daniele 29:1a47b7151851 92 struct pico_icmp4_hdr *hdr;
daniele 29:1a47b7151851 93 struct pico_ipv4_hdr *info;
daniele 29:1a47b7151851 94 if (f == NULL) {
daniele 29:1a47b7151851 95 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 96 return -1;
daniele 29:1a47b7151851 97 }
daniele 29:1a47b7151851 98 reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, 8 + sizeof(struct pico_ipv4_hdr) + PICO_ICMPHDR_UN_SIZE);
daniele 29:1a47b7151851 99 info = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 29:1a47b7151851 100 hdr = (struct pico_icmp4_hdr *) reply->transport_hdr;
daniele 29:1a47b7151851 101 hdr->type = type;
daniele 29:1a47b7151851 102 hdr->code = code;
daniele 29:1a47b7151851 103 hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500);
daniele 29:1a47b7151851 104 hdr->hun.ih_pmtu.ipm_void = 0;
daniele 29:1a47b7151851 105 reply->transport_len = 8 + sizeof(struct pico_ipv4_hdr) + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 106 reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 107 memcpy(reply->payload, f->net_hdr, 8 + sizeof(struct pico_ipv4_hdr));
daniele 29:1a47b7151851 108 pico_icmp4_checksum(reply);
daniele 29:1a47b7151851 109 pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4);
daniele 29:1a47b7151851 110 return 0;
daniele 29:1a47b7151851 111 }
daniele 29:1a47b7151851 112
daniele 29:1a47b7151851 113 int pico_icmp4_port_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_PORT);
daniele 29:1a47b7151851 117 }
daniele 29:1a47b7151851 118
daniele 29:1a47b7151851 119 int pico_icmp4_proto_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_PROTOCOL);
daniele 29:1a47b7151851 123 }
daniele 29:1a47b7151851 124
daniele 29:1a47b7151851 125 int pico_icmp4_dest_unreachable(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_UNREACH, PICO_ICMP_UNREACH_HOST);
daniele 29:1a47b7151851 129 }
daniele 29:1a47b7151851 130
daniele 29:1a47b7151851 131 int pico_icmp4_ttl_expired(struct pico_frame *f)
daniele 29:1a47b7151851 132 {
daniele 29:1a47b7151851 133 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 134 return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS);
daniele 29:1a47b7151851 135 }
daniele 29:1a47b7151851 136
daniele 29:1a47b7151851 137 int pico_icmp4_packet_filtered(struct pico_frame *f)
daniele 29:1a47b7151851 138 {
daniele 29:1a47b7151851 139 /*Parameter check executed in pico_icmp4_notify*/
daniele 29:1a47b7151851 140 /*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/
daniele 29:1a47b7151851 141 return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB);
daniele 29:1a47b7151851 142 }
daniele 29:1a47b7151851 143
daniele 29:1a47b7151851 144 /***********************/
daniele 29:1a47b7151851 145 /* Ping implementation */
daniele 29:1a47b7151851 146 /***********************/
daniele 29:1a47b7151851 147 /***********************/
daniele 29:1a47b7151851 148 /***********************/
daniele 29:1a47b7151851 149 /***********************/
daniele 29:1a47b7151851 150
daniele 29:1a47b7151851 151
daniele 29:1a47b7151851 152 #ifdef PICO_SUPPORT_PING
daniele 29:1a47b7151851 153
daniele 29:1a47b7151851 154
daniele 29:1a47b7151851 155 struct pico_icmp4_ping_cookie
daniele 29:1a47b7151851 156 {
daniele 29:1a47b7151851 157 struct pico_ip4 dst;
daniele 29:1a47b7151851 158 uint16_t err;
daniele 29:1a47b7151851 159 uint16_t id;
daniele 29:1a47b7151851 160 uint16_t seq;
daniele 29:1a47b7151851 161 uint16_t size;
daniele 29:1a47b7151851 162 int count;
daniele 29:1a47b7151851 163 unsigned long timestamp;
daniele 29:1a47b7151851 164 int interval;
daniele 29:1a47b7151851 165 int timeout;
daniele 29:1a47b7151851 166 void (*cb)(struct pico_icmp4_stats*);
daniele 29:1a47b7151851 167
daniele 29:1a47b7151851 168 };
daniele 29:1a47b7151851 169
daniele 29:1a47b7151851 170 static int cookie_compare(void *ka, void *kb)
daniele 29:1a47b7151851 171 {
tass 51:ab4529a384a6 172 struct pico_icmp4_ping_cookie *a = ka, *b = kb;
daniele 29:1a47b7151851 173 if (a->id < b->id)
daniele 29:1a47b7151851 174 return -1;
daniele 29:1a47b7151851 175 if (a->id > b->id)
daniele 29:1a47b7151851 176 return 1;
daniele 29:1a47b7151851 177 return (a->seq - b->seq);
daniele 29:1a47b7151851 178 }
daniele 29:1a47b7151851 179
daniele 29:1a47b7151851 180 PICO_TREE_DECLARE(Pings,cookie_compare);
daniele 29:1a47b7151851 181
daniele 29:1a47b7151851 182 static int pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
daniele 29:1a47b7151851 183 {
daniele 29:1a47b7151851 184 struct pico_frame *echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, PICO_ICMPHDR_UN_SIZE + cookie->size);
daniele 29:1a47b7151851 185 struct pico_icmp4_hdr *hdr;
daniele 29:1a47b7151851 186
daniele 29:1a47b7151851 187 hdr = (struct pico_icmp4_hdr *) echo->transport_hdr;
daniele 29:1a47b7151851 188
daniele 29:1a47b7151851 189 hdr->type = PICO_ICMP_ECHO;
daniele 29:1a47b7151851 190 hdr->code = 0;
daniele 29:1a47b7151851 191 hdr->hun.ih_idseq.idseq_id = short_be(cookie->id);
daniele 29:1a47b7151851 192 hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq);
daniele 29:1a47b7151851 193 echo->transport_len = PICO_ICMPHDR_UN_SIZE + cookie->size;
daniele 29:1a47b7151851 194 echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE;
daniele 29:1a47b7151851 195 echo->payload_len = cookie->size;
daniele 29:1a47b7151851 196 /* XXX: Fill payload */
daniele 29:1a47b7151851 197 pico_icmp4_checksum(echo);
daniele 29:1a47b7151851 198 pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4);
daniele 29:1a47b7151851 199 return 0;
daniele 29:1a47b7151851 200 }
daniele 29:1a47b7151851 201
daniele 29:1a47b7151851 202
daniele 29:1a47b7151851 203 static void ping_timeout(unsigned long now, void *arg)
daniele 29:1a47b7151851 204 {
daniele 29:1a47b7151851 205 struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg;
daniele 29:1a47b7151851 206 if(pico_tree_findKey(&Pings,cookie)){
daniele 29:1a47b7151851 207 if (cookie->err == PICO_PING_ERR_PENDING) {
daniele 29:1a47b7151851 208 struct pico_icmp4_stats stats;
daniele 29:1a47b7151851 209 stats.dst = cookie->dst;
daniele 29:1a47b7151851 210 stats.seq = cookie->seq;
daniele 29:1a47b7151851 211 stats.time = 0;
daniele 29:1a47b7151851 212 stats.size = cookie->size;
daniele 29:1a47b7151851 213 stats.err = PICO_PING_ERR_TIMEOUT;
daniele 29:1a47b7151851 214 dbg(" ---- Ping timeout!!!\n");
daniele 29:1a47b7151851 215 cookie->cb(&stats);
daniele 29:1a47b7151851 216 }
daniele 29:1a47b7151851 217
daniele 29:1a47b7151851 218 pico_tree_delete(&Pings,cookie);
daniele 29:1a47b7151851 219 pico_free(cookie);
daniele 29:1a47b7151851 220 }
daniele 29:1a47b7151851 221 }
daniele 29:1a47b7151851 222
daniele 29:1a47b7151851 223 static void next_ping(unsigned long now, void *arg);
daniele 29:1a47b7151851 224 static inline void send_ping(struct pico_icmp4_ping_cookie *cookie)
daniele 29:1a47b7151851 225 {
daniele 29:1a47b7151851 226 pico_icmp4_send_echo(cookie);
daniele 29:1a47b7151851 227 cookie->timestamp = pico_tick;
daniele 29:1a47b7151851 228 pico_timer_add(cookie->timeout, ping_timeout, cookie);
daniele 29:1a47b7151851 229 if (cookie->seq < cookie->count)
daniele 29:1a47b7151851 230 pico_timer_add(cookie->interval, next_ping, cookie);
daniele 29:1a47b7151851 231 }
daniele 29:1a47b7151851 232
daniele 29:1a47b7151851 233 static void next_ping(unsigned long now, void *arg)
daniele 29:1a47b7151851 234 {
daniele 29:1a47b7151851 235 struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
daniele 29:1a47b7151851 236
tass 51:ab4529a384a6 237 if(pico_tree_findKey(&Pings,cookie)){
daniele 29:1a47b7151851 238 if (cookie->seq < cookie->count) {
daniele 29:1a47b7151851 239 newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
daniele 29:1a47b7151851 240 if (!newcookie)
daniele 29:1a47b7151851 241 return;
daniele 29:1a47b7151851 242 memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
daniele 29:1a47b7151851 243 newcookie->seq++;
daniele 29:1a47b7151851 244
tass 51:ab4529a384a6 245 pico_tree_insert(&Pings,newcookie);
daniele 29:1a47b7151851 246 send_ping(newcookie);
daniele 29:1a47b7151851 247 }
daniele 29:1a47b7151851 248 }
daniele 29:1a47b7151851 249 }
daniele 29:1a47b7151851 250
daniele 29:1a47b7151851 251
daniele 29:1a47b7151851 252 static void ping_recv_reply(struct pico_frame *f)
daniele 29:1a47b7151851 253 {
daniele 29:1a47b7151851 254 struct pico_icmp4_ping_cookie test, *cookie;
daniele 29:1a47b7151851 255 struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 256 test.id = short_be(hdr->hun.ih_idseq.idseq_id );
daniele 29:1a47b7151851 257 test.seq = short_be(hdr->hun.ih_idseq.idseq_seq);
daniele 29:1a47b7151851 258
daniele 29:1a47b7151851 259 cookie = pico_tree_findKey(&Pings, &test);
daniele 29:1a47b7151851 260 if (cookie) {
daniele 29:1a47b7151851 261 struct pico_icmp4_stats stats;
daniele 29:1a47b7151851 262 cookie->err = PICO_PING_ERR_REPLIED;
daniele 29:1a47b7151851 263 stats.dst = cookie->dst;
daniele 29:1a47b7151851 264 stats.seq = cookie->seq;
daniele 29:1a47b7151851 265 stats.size = cookie->size;
daniele 29:1a47b7151851 266 stats.time = pico_tick - cookie->timestamp;
daniele 29:1a47b7151851 267 stats.err = cookie->err;
daniele 29:1a47b7151851 268 stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl;
tass 51:ab4529a384a6 269 if(cookie->cb != NULL)
tass 51:ab4529a384a6 270 cookie->cb(&stats);
daniele 29:1a47b7151851 271 } else {
daniele 29:1a47b7151851 272 dbg("Reply for seq=%d, not found.\n", test.seq);
daniele 29:1a47b7151851 273 }
daniele 29:1a47b7151851 274 }
daniele 29:1a47b7151851 275
daniele 29:1a47b7151851 276 int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *))
daniele 29:1a47b7151851 277 {
daniele 29:1a47b7151851 278 static uint16_t next_id = 0x91c0;
daniele 29:1a47b7151851 279 struct pico_icmp4_ping_cookie *cookie;
daniele 29:1a47b7151851 280
daniele 29:1a47b7151851 281 if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)){
daniele 29:1a47b7151851 282 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 283 return -1;
daniele 29:1a47b7151851 284 }
daniele 29:1a47b7151851 285
daniele 29:1a47b7151851 286 cookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
daniele 29:1a47b7151851 287 if (!cookie) {
daniele 29:1a47b7151851 288 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 289 return -1;
daniele 29:1a47b7151851 290 }
daniele 29:1a47b7151851 291
daniele 29:1a47b7151851 292 if (pico_string_to_ipv4(dst, &cookie->dst.addr) < 0) {
daniele 29:1a47b7151851 293 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 294 pico_free(cookie);
daniele 29:1a47b7151851 295 return -1;
daniele 29:1a47b7151851 296 }
daniele 29:1a47b7151851 297 cookie->seq = 1;
daniele 29:1a47b7151851 298 cookie->id = next_id++;
daniele 29:1a47b7151851 299 cookie->err = PICO_PING_ERR_PENDING;
daniele 29:1a47b7151851 300 cookie->size = size;
daniele 29:1a47b7151851 301 cookie->interval = interval;
daniele 29:1a47b7151851 302 cookie->timeout = timeout;
daniele 29:1a47b7151851 303 cookie->cb = cb;
daniele 29:1a47b7151851 304 cookie->count = count;
daniele 29:1a47b7151851 305
daniele 29:1a47b7151851 306 pico_tree_insert(&Pings,cookie);
daniele 29:1a47b7151851 307 send_ping(cookie);
daniele 29:1a47b7151851 308
daniele 29:1a47b7151851 309 return 0;
daniele 29:1a47b7151851 310
daniele 29:1a47b7151851 311 }
daniele 29:1a47b7151851 312
daniele 29:1a47b7151851 313 #endif