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:
Mon Sep 02 08:02:21 2013 +0000
Revision:
51:ab4529a384a6
Parent:
3:b4047e8a0123
Child:
63:97f481e33cb2
Updated from masterbranch

Who changed what in which revision?

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