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:
Fri May 17 12:09:59 2013 +0000
Revision:
1:cfe8984a32b4
Parent:
libraries/picotcp/stack/pico_arp.c@0:d7f2341ab245
Update for smaller SOCKETQ

Who changed what in which revision?

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