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:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Child:
51:ab4529a384a6
Updated from main repo + fixed Mutexes;

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