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_config.h"
tass 68:0847e35d08a6 12 #include "pico_arp.h"
tass 68:0847e35d08a6 13 #include "pico_tree.h"
tass 68:0847e35d08a6 14 #include "pico_ipv4.h"
tass 68:0847e35d08a6 15 #include "pico_device.h"
tass 68:0847e35d08a6 16 #include "pico_stack.h"
tass 68:0847e35d08a6 17
tass 68:0847e35d08a6 18 const uint8_t PICO_ETHADDR_ALL[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
tass 68:0847e35d08a6 19 #define PICO_ARP_TIMEOUT 600000
tass 68:0847e35d08a6 20 #define PICO_ARP_RETRY 300
tass 68:0847e35d08a6 21
tass 68:0847e35d08a6 22 #ifdef DEBUG_ARP
tass 68:0847e35d08a6 23 #define arp_dbg dbg
tass 68:0847e35d08a6 24 #else
tass 68:0847e35d08a6 25 #define arp_dbg(...) do{}while(0)
tass 68:0847e35d08a6 26 #endif
tass 68:0847e35d08a6 27
tass 68:0847e35d08a6 28 static struct pico_queue pending;
tass 68:0847e35d08a6 29 static int pending_timer_on = 0;
tass 68:0847e35d08a6 30
tass 70:cd218dd180e5 31 void check_pending(uint64_t now, void *_unused)
tass 68:0847e35d08a6 32 {
tass 68:0847e35d08a6 33 struct pico_frame *f = pico_dequeue(&pending);
tass 68:0847e35d08a6 34 IGNORE_PARAMETER(now);
tass 68:0847e35d08a6 35 IGNORE_PARAMETER(_unused);
tass 68:0847e35d08a6 36 if (!f) {
tass 68:0847e35d08a6 37 pending_timer_on = 0;
tass 68:0847e35d08a6 38 return;
tass 68:0847e35d08a6 39 }
tass 68:0847e35d08a6 40 if(pico_ethernet_send(f) > 0)
tass 68:0847e35d08a6 41 pico_frame_discard(f);
tass 68:0847e35d08a6 42 pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
tass 68:0847e35d08a6 43 }
tass 68:0847e35d08a6 44
tass 68:0847e35d08a6 45
tass 68:0847e35d08a6 46 struct
tass 68:0847e35d08a6 47 __attribute__ ((__packed__))
tass 68:0847e35d08a6 48 pico_arp_hdr
tass 68:0847e35d08a6 49 {
tass 68:0847e35d08a6 50 uint16_t htype;
tass 68:0847e35d08a6 51 uint16_t ptype;
tass 68:0847e35d08a6 52 uint8_t hsize;
tass 68:0847e35d08a6 53 uint8_t psize;
tass 68:0847e35d08a6 54 uint16_t opcode;
tass 68:0847e35d08a6 55 uint8_t s_mac[PICO_SIZE_ETH];
tass 68:0847e35d08a6 56 struct pico_ip4 src;
tass 68:0847e35d08a6 57 uint8_t d_mac[PICO_SIZE_ETH];
tass 68:0847e35d08a6 58 struct pico_ip4 dst;
tass 68:0847e35d08a6 59 };
tass 68:0847e35d08a6 60
tass 68:0847e35d08a6 61
tass 68:0847e35d08a6 62 #define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr)))
tass 68:0847e35d08a6 63
tass 68:0847e35d08a6 64 /* Arp Entries for the tables. */
tass 68:0847e35d08a6 65 struct pico_arp {
tass 68:0847e35d08a6 66 /* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure,
tass 68:0847e35d08a6 67 * due to in-place casting!!! */
tass 68:0847e35d08a6 68 struct pico_eth eth;
tass 68:0847e35d08a6 69 struct pico_ip4 ipv4;
tass 68:0847e35d08a6 70 int arp_status;
tass 70:cd218dd180e5 71 uint64_t timestamp;
tass 68:0847e35d08a6 72 struct pico_device *dev;
tass 68:0847e35d08a6 73 };
tass 68:0847e35d08a6 74
tass 68:0847e35d08a6 75
tass 68:0847e35d08a6 76
tass 68:0847e35d08a6 77 /*****************/
tass 68:0847e35d08a6 78 /** ARP TREE **/
tass 68:0847e35d08a6 79 /*****************/
tass 68:0847e35d08a6 80
tass 68:0847e35d08a6 81 /* Routing destination */
tass 68:0847e35d08a6 82
tass 68:0847e35d08a6 83 static int arp_compare(void * ka, void * kb)
tass 68:0847e35d08a6 84 {
tass 68:0847e35d08a6 85 struct pico_arp *a = ka, *b = kb;
tass 68:0847e35d08a6 86 if (a->ipv4.addr < b->ipv4.addr)
tass 68:0847e35d08a6 87 return -1;
tass 68:0847e35d08a6 88 else if (a->ipv4.addr > b->ipv4.addr)
tass 68:0847e35d08a6 89 return 1;
tass 68:0847e35d08a6 90 return 0;
tass 68:0847e35d08a6 91 }
tass 68:0847e35d08a6 92
tass 68:0847e35d08a6 93 PICO_TREE_DECLARE(arp_tree, arp_compare);
tass 68:0847e35d08a6 94
tass 68:0847e35d08a6 95 /*********************/
tass 68:0847e35d08a6 96 /** END ARP TREE **/
tass 68:0847e35d08a6 97 /*********************/
tass 68:0847e35d08a6 98
tass 68:0847e35d08a6 99 struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst)
tass 68:0847e35d08a6 100 {
tass 68:0847e35d08a6 101 struct pico_arp search, *found;
tass 68:0847e35d08a6 102 search.ipv4.addr = dst->addr;
tass 68:0847e35d08a6 103 found = pico_tree_findKey(&arp_tree,&search);
tass 68:0847e35d08a6 104 if (found && (found->arp_status != PICO_ARP_STATUS_STALE))
tass 68:0847e35d08a6 105 return &found->eth;
tass 68:0847e35d08a6 106 return NULL;
tass 68:0847e35d08a6 107 }
tass 68:0847e35d08a6 108
tass 68:0847e35d08a6 109 struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst)
tass 68:0847e35d08a6 110 {
tass 68:0847e35d08a6 111 struct pico_arp* search;
tass 68:0847e35d08a6 112 struct pico_tree_node * index;
tass 68:0847e35d08a6 113 pico_tree_foreach(index,&arp_tree){
tass 68:0847e35d08a6 114 search = index->keyValue;
tass 68:0847e35d08a6 115 if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0)
tass 68:0847e35d08a6 116 return &search->ipv4;
tass 68:0847e35d08a6 117 }
tass 68:0847e35d08a6 118 return NULL;
tass 68:0847e35d08a6 119 }
tass 68:0847e35d08a6 120
tass 68:0847e35d08a6 121 struct pico_eth *pico_arp_get(struct pico_frame *f) {
tass 68:0847e35d08a6 122 struct pico_eth *a4;
tass 68:0847e35d08a6 123 struct pico_ip4 gateway;
tass 68:0847e35d08a6 124 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
tass 68:0847e35d08a6 125 struct pico_ipv4_link *l;
tass 68:0847e35d08a6 126
tass 68:0847e35d08a6 127 l = pico_ipv4_link_get(&hdr->dst);
tass 68:0847e35d08a6 128 if(l){
tass 68:0847e35d08a6 129 //address belongs to ourself
tass 68:0847e35d08a6 130 return &l->dev->eth->mac;
tass 68:0847e35d08a6 131 }
tass 68:0847e35d08a6 132
tass 68:0847e35d08a6 133 gateway = pico_ipv4_route_get_gateway(&hdr->dst);
tass 68:0847e35d08a6 134 /* check if dst is local (gateway = 0), or if to use gateway */
tass 68:0847e35d08a6 135 if (gateway.addr != 0)
tass 68:0847e35d08a6 136 a4 = pico_arp_lookup(&gateway); /* check if gateway ip mac in cache */
tass 68:0847e35d08a6 137 else
tass 68:0847e35d08a6 138 a4 = pico_arp_lookup(&hdr->dst); /* check if local ip mac in cache */
tass 68:0847e35d08a6 139 if (!a4) {
tass 68:0847e35d08a6 140 if (++f->failure_count < 4) {
tass 68:0847e35d08a6 141 dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count);
tass 68:0847e35d08a6 142 /* check if dst is local (gateway = 0), or if to use gateway */
tass 68:0847e35d08a6 143 if (gateway.addr != 0)
tass 68:0847e35d08a6 144 pico_arp_query(f->dev, &gateway); /* arp to gateway */
tass 68:0847e35d08a6 145 else
tass 68:0847e35d08a6 146 pico_arp_query(f->dev, &hdr->dst); /* arp to dst */
tass 68:0847e35d08a6 147
tass 68:0847e35d08a6 148 pico_enqueue(&pending, f);
tass 68:0847e35d08a6 149 if (!pending_timer_on) {
tass 68:0847e35d08a6 150 pending_timer_on++;
tass 68:0847e35d08a6 151 pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
tass 68:0847e35d08a6 152 }
tass 68:0847e35d08a6 153 } else {
tass 68:0847e35d08a6 154 dbg("ARP: Destination Unreachable\n");
tass 68:0847e35d08a6 155 pico_notify_dest_unreachable(f);
tass 68:0847e35d08a6 156 pico_frame_discard(f);
tass 68:0847e35d08a6 157 }
tass 68:0847e35d08a6 158 }
tass 68:0847e35d08a6 159 return a4;
tass 68:0847e35d08a6 160 }
tass 68:0847e35d08a6 161
tass 68:0847e35d08a6 162 #ifdef DEBUG_ARP
tass 68:0847e35d08a6 163 void dbg_arp(void)
tass 68:0847e35d08a6 164 {
tass 68:0847e35d08a6 165 struct pico_arp *a;
tass 68:0847e35d08a6 166 struct pico_tree_node * index;
tass 68:0847e35d08a6 167
tass 68:0847e35d08a6 168 pico_tree_foreach(index,&arp_tree) {
tass 68:0847e35d08a6 169 a = index->keyValue;
tass 68:0847e35d08a6 170 arp_dbg("ARP to %08x, mac: %02x:%02x:%02x:%02x:%02x:%02x\n", a->ipv4.addr,a->eth.addr[0],a->eth.addr[1],a->eth.addr[2],a->eth.addr[3],a->eth.addr[4],a->eth.addr[5] );
tass 68:0847e35d08a6 171 }
tass 68:0847e35d08a6 172 }
tass 68:0847e35d08a6 173 #endif
tass 68:0847e35d08a6 174
tass 70:cd218dd180e5 175 void arp_expire(uint64_t now, void *_stale)
tass 68:0847e35d08a6 176 {
tass 68:0847e35d08a6 177 struct pico_arp *stale = (struct pico_arp *) _stale;
tass 68:0847e35d08a6 178 IGNORE_PARAMETER(now);
tass 68:0847e35d08a6 179 stale->arp_status = PICO_ARP_STATUS_STALE;
tass 68:0847e35d08a6 180 arp_dbg("ARP: Setting arp_status to STALE\n");
tass 68:0847e35d08a6 181 pico_arp_query(stale->dev, &stale->ipv4);
tass 68:0847e35d08a6 182
tass 68:0847e35d08a6 183 }
tass 68:0847e35d08a6 184
tass 68:0847e35d08a6 185 void pico_arp_add_entry(struct pico_arp *entry)
tass 68:0847e35d08a6 186 {
tass 68:0847e35d08a6 187 entry->arp_status = PICO_ARP_STATUS_REACHABLE;
tass 68:0847e35d08a6 188 entry->timestamp = PICO_TIME();
tass 68:0847e35d08a6 189
tass 68:0847e35d08a6 190 pico_tree_insert(&arp_tree,entry);
tass 68:0847e35d08a6 191 arp_dbg("ARP ## reachable.\n");
tass 68:0847e35d08a6 192 pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry);
tass 68:0847e35d08a6 193 }
tass 68:0847e35d08a6 194
tass 68:0847e35d08a6 195 int pico_arp_create_entry(uint8_t* hwaddr, struct pico_ip4 ipv4, struct pico_device* dev)
tass 68:0847e35d08a6 196 {
tass 68:0847e35d08a6 197 struct pico_arp* arp = pico_zalloc(sizeof(struct pico_arp));
tass 68:0847e35d08a6 198 if(!arp){
tass 68:0847e35d08a6 199 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 200 return -1;
tass 68:0847e35d08a6 201 }
tass 68:0847e35d08a6 202 memcpy(arp->eth.addr, hwaddr, 6);
tass 68:0847e35d08a6 203 arp->ipv4.addr = ipv4.addr;
tass 68:0847e35d08a6 204 arp->dev = dev;
tass 68:0847e35d08a6 205
tass 68:0847e35d08a6 206 pico_arp_add_entry(arp);
tass 68:0847e35d08a6 207
tass 68:0847e35d08a6 208 return 0;
tass 68:0847e35d08a6 209 }
tass 68:0847e35d08a6 210
tass 68:0847e35d08a6 211 int pico_arp_receive(struct pico_frame *f)
tass 68:0847e35d08a6 212 {
tass 68:0847e35d08a6 213 struct pico_arp_hdr *hdr;
tass 68:0847e35d08a6 214 struct pico_arp search, *found, *new = NULL;
tass 68:0847e35d08a6 215 int ret = -1;
tass 68:0847e35d08a6 216 hdr = (struct pico_arp_hdr *) f->net_hdr;
tass 68:0847e35d08a6 217
tass 68:0847e35d08a6 218 if (!hdr)
tass 68:0847e35d08a6 219 goto end;
tass 68:0847e35d08a6 220
tass 68:0847e35d08a6 221
tass 68:0847e35d08a6 222 /* Populate a new arp entry */
tass 68:0847e35d08a6 223 search.ipv4.addr = hdr->src.addr;
tass 68:0847e35d08a6 224 memcpy(search.eth.addr, hdr->s_mac, PICO_SIZE_ETH);
tass 68:0847e35d08a6 225
tass 68:0847e35d08a6 226 /* Search for already existing entry */
tass 68:0847e35d08a6 227
tass 68:0847e35d08a6 228 found = pico_tree_findKey(&arp_tree,&search);
tass 68:0847e35d08a6 229 if (!found) {
tass 68:0847e35d08a6 230 new = pico_zalloc(sizeof(struct pico_arp));
tass 68:0847e35d08a6 231 if (!new)
tass 68:0847e35d08a6 232 goto end;
tass 68:0847e35d08a6 233 new->ipv4.addr = hdr->src.addr;
tass 68:0847e35d08a6 234 }
tass 68:0847e35d08a6 235 else if (found->arp_status == PICO_ARP_STATUS_STALE) {
tass 68:0847e35d08a6 236 /* Replace if stale */
tass 68:0847e35d08a6 237 new = found;
tass 68:0847e35d08a6 238
tass 68:0847e35d08a6 239 pico_tree_delete(&arp_tree,new);
tass 68:0847e35d08a6 240 }
tass 68:0847e35d08a6 241
tass 68:0847e35d08a6 242 ret = 0;
tass 68:0847e35d08a6 243
tass 68:0847e35d08a6 244 if (new) {
tass 68:0847e35d08a6 245 memcpy(new->eth.addr, hdr->s_mac, PICO_SIZE_ETH);
tass 68:0847e35d08a6 246 new->dev = f->dev;
tass 68:0847e35d08a6 247 pico_arp_add_entry(new);
tass 68:0847e35d08a6 248 }
tass 68:0847e35d08a6 249
tass 68:0847e35d08a6 250 if (hdr->opcode == PICO_ARP_REQUEST) {
tass 68:0847e35d08a6 251 struct pico_ip4 me;
tass 68:0847e35d08a6 252 struct pico_eth_hdr *eh = (struct pico_eth_hdr *)f->datalink_hdr;
tass 68:0847e35d08a6 253 struct pico_device *link_dev;
tass 68:0847e35d08a6 254 me.addr = hdr->dst.addr;
tass 68:0847e35d08a6 255
tass 68:0847e35d08a6 256 link_dev = pico_ipv4_link_find(&me);
tass 68:0847e35d08a6 257 if (link_dev != f->dev)
tass 68:0847e35d08a6 258 goto end;
tass 68:0847e35d08a6 259
tass 68:0847e35d08a6 260 hdr->opcode = PICO_ARP_REPLY;
tass 68:0847e35d08a6 261 memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH);
tass 68:0847e35d08a6 262 memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 263 hdr->dst.addr = hdr->src.addr;
tass 68:0847e35d08a6 264 hdr->src.addr = me.addr;
tass 68:0847e35d08a6 265
tass 68:0847e35d08a6 266 /* Prepare eth header for arp reply */
tass 68:0847e35d08a6 267 memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 268 memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 269 f->start = f->datalink_hdr;
tass 68:0847e35d08a6 270 f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR;
tass 68:0847e35d08a6 271 f->dev->send(f->dev, f->start, f->len);
tass 68:0847e35d08a6 272 }
tass 68:0847e35d08a6 273
tass 68:0847e35d08a6 274 #ifdef DEBUG_ARG
tass 68:0847e35d08a6 275 dbg_arp();
tass 68:0847e35d08a6 276 #endif
tass 68:0847e35d08a6 277
tass 68:0847e35d08a6 278 end:
tass 68:0847e35d08a6 279 pico_frame_discard(f);
tass 68:0847e35d08a6 280 return ret;
tass 68:0847e35d08a6 281 }
tass 68:0847e35d08a6 282
tass 70:cd218dd180e5 283 int32_t pico_arp_query(struct pico_device *dev, struct pico_ip4 *dst)
tass 68:0847e35d08a6 284 {
tass 68:0847e35d08a6 285 struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR);
tass 68:0847e35d08a6 286 struct pico_eth_hdr *eh;
tass 68:0847e35d08a6 287 struct pico_arp_hdr *ah;
tass 68:0847e35d08a6 288 struct pico_ip4 *src;
tass 70:cd218dd180e5 289 uint32_t ret;
tass 68:0847e35d08a6 290
tass 68:0847e35d08a6 291 src = pico_ipv4_source_find(dst);
tass 68:0847e35d08a6 292 if (!src)
tass 68:0847e35d08a6 293 return -1;
tass 68:0847e35d08a6 294
tass 68:0847e35d08a6 295 arp_dbg("QUERY: %08x\n", dst->addr);
tass 68:0847e35d08a6 296
tass 68:0847e35d08a6 297 if (!q)
tass 68:0847e35d08a6 298 return -1;
tass 68:0847e35d08a6 299 eh = (struct pico_eth_hdr *)q->start;
tass 68:0847e35d08a6 300 ah = (struct pico_arp_hdr *) (q->start + PICO_SIZE_ETHHDR);
tass 68:0847e35d08a6 301
tass 68:0847e35d08a6 302 /* Fill eth header */
tass 68:0847e35d08a6 303 memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 304 memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH);
tass 68:0847e35d08a6 305 eh->proto = PICO_IDETH_ARP;
tass 68:0847e35d08a6 306
tass 68:0847e35d08a6 307 /* Fill arp header */
tass 68:0847e35d08a6 308 ah->htype = PICO_ARP_HTYPE_ETH;
tass 68:0847e35d08a6 309 ah->ptype = PICO_IDETH_IPV4;
tass 68:0847e35d08a6 310 ah->hsize = PICO_SIZE_ETH;
tass 68:0847e35d08a6 311 ah->psize = PICO_SIZE_IP4;
tass 68:0847e35d08a6 312 ah->opcode = PICO_ARP_REQUEST;
tass 68:0847e35d08a6 313 memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 314 ah->src.addr = src->addr;
tass 68:0847e35d08a6 315 ah->dst.addr = dst->addr;
tass 68:0847e35d08a6 316 arp_dbg("Sending arp query.\n");
tass 68:0847e35d08a6 317 ret = dev->send(dev, q->start, q->len);
tass 68:0847e35d08a6 318 pico_frame_discard(q);
tass 70:cd218dd180e5 319 return (int32_t)ret;
tass 68:0847e35d08a6 320 }