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 picotcp@tass.be
Date:
Wed Apr 09 14:31:41 2014 +0200
Revision:
149:5f4cb161cec3
Child:
152:a3d286bf94e5
Update from git masterbranch

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass picotcp@tass.be 149:5f4cb161cec3 1 /*********************************************************************
tass picotcp@tass.be 149:5f4cb161cec3 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
tass picotcp@tass.be 149:5f4cb161cec3 3 See LICENSE and COPYING for usage.
tass picotcp@tass.be 149:5f4cb161cec3 4
tass picotcp@tass.be 149:5f4cb161cec3 5 .
tass picotcp@tass.be 149:5f4cb161cec3 6
tass picotcp@tass.be 149:5f4cb161cec3 7 Authors: Daniele Lacamera
tass picotcp@tass.be 149:5f4cb161cec3 8 *********************************************************************/
tass picotcp@tass.be 149:5f4cb161cec3 9
tass picotcp@tass.be 149:5f4cb161cec3 10
tass picotcp@tass.be 149:5f4cb161cec3 11 #include "pico_config.h"
tass picotcp@tass.be 149:5f4cb161cec3 12 #include "pico_arp.h"
tass picotcp@tass.be 149:5f4cb161cec3 13 #include "pico_tree.h"
tass picotcp@tass.be 149:5f4cb161cec3 14 #include "pico_ipv4.h"
tass picotcp@tass.be 149:5f4cb161cec3 15 #include "pico_device.h"
tass picotcp@tass.be 149:5f4cb161cec3 16 #include "pico_stack.h"
tass picotcp@tass.be 149:5f4cb161cec3 17
tass picotcp@tass.be 149:5f4cb161cec3 18 extern const uint8_t PICO_ETHADDR_ALL[6];
tass picotcp@tass.be 149:5f4cb161cec3 19 #define PICO_ARP_TIMEOUT 600000llu
tass picotcp@tass.be 149:5f4cb161cec3 20 #define PICO_ARP_RETRY 300lu
tass picotcp@tass.be 149:5f4cb161cec3 21
tass picotcp@tass.be 149:5f4cb161cec3 22 #ifdef DEBUG_ARP
tass picotcp@tass.be 149:5f4cb161cec3 23 #define arp_dbg dbg
tass picotcp@tass.be 149:5f4cb161cec3 24 #else
tass picotcp@tass.be 149:5f4cb161cec3 25 #define arp_dbg(...) do {} while(0)
tass picotcp@tass.be 149:5f4cb161cec3 26 #endif
tass picotcp@tass.be 149:5f4cb161cec3 27
tass picotcp@tass.be 149:5f4cb161cec3 28 static struct pico_queue pending;
tass picotcp@tass.be 149:5f4cb161cec3 29 static int pending_timer_on = 0;
tass picotcp@tass.be 149:5f4cb161cec3 30 static int max_arp_reqs = PICO_ARP_MAX_RATE;
tass picotcp@tass.be 149:5f4cb161cec3 31
tass picotcp@tass.be 149:5f4cb161cec3 32
tass picotcp@tass.be 149:5f4cb161cec3 33 static void check_pending(pico_time now, void *_unused)
tass picotcp@tass.be 149:5f4cb161cec3 34 {
tass picotcp@tass.be 149:5f4cb161cec3 35 struct pico_frame *f = pico_dequeue(&pending);
tass picotcp@tass.be 149:5f4cb161cec3 36 IGNORE_PARAMETER(now);
tass picotcp@tass.be 149:5f4cb161cec3 37 IGNORE_PARAMETER(_unused);
tass picotcp@tass.be 149:5f4cb161cec3 38 if (!f) {
tass picotcp@tass.be 149:5f4cb161cec3 39 pending_timer_on = 0;
tass picotcp@tass.be 149:5f4cb161cec3 40 return;
tass picotcp@tass.be 149:5f4cb161cec3 41 }
tass picotcp@tass.be 149:5f4cb161cec3 42
tass picotcp@tass.be 149:5f4cb161cec3 43 pico_ethernet_send(f);
tass picotcp@tass.be 149:5f4cb161cec3 44
tass picotcp@tass.be 149:5f4cb161cec3 45 pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
tass picotcp@tass.be 149:5f4cb161cec3 46 }
tass picotcp@tass.be 149:5f4cb161cec3 47
tass picotcp@tass.be 149:5f4cb161cec3 48 static void update_max_arp_reqs(pico_time now, void *unused)
tass picotcp@tass.be 149:5f4cb161cec3 49 {
tass picotcp@tass.be 149:5f4cb161cec3 50 IGNORE_PARAMETER(now);
tass picotcp@tass.be 149:5f4cb161cec3 51 IGNORE_PARAMETER(unused);
tass picotcp@tass.be 149:5f4cb161cec3 52 if (max_arp_reqs < PICO_ARP_MAX_RATE)
tass picotcp@tass.be 149:5f4cb161cec3 53 max_arp_reqs++;
tass picotcp@tass.be 149:5f4cb161cec3 54
tass picotcp@tass.be 149:5f4cb161cec3 55 pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
tass picotcp@tass.be 149:5f4cb161cec3 56 }
tass picotcp@tass.be 149:5f4cb161cec3 57
tass picotcp@tass.be 149:5f4cb161cec3 58 void pico_arp_init(void)
tass picotcp@tass.be 149:5f4cb161cec3 59 {
tass picotcp@tass.be 149:5f4cb161cec3 60 pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
tass picotcp@tass.be 149:5f4cb161cec3 61 }
tass picotcp@tass.be 149:5f4cb161cec3 62
tass picotcp@tass.be 149:5f4cb161cec3 63 PACKED_STRUCT_DEF pico_arp_hdr
tass picotcp@tass.be 149:5f4cb161cec3 64 {
tass picotcp@tass.be 149:5f4cb161cec3 65 uint16_t htype;
tass picotcp@tass.be 149:5f4cb161cec3 66 uint16_t ptype;
tass picotcp@tass.be 149:5f4cb161cec3 67 uint8_t hsize;
tass picotcp@tass.be 149:5f4cb161cec3 68 uint8_t psize;
tass picotcp@tass.be 149:5f4cb161cec3 69 uint16_t opcode;
tass picotcp@tass.be 149:5f4cb161cec3 70 uint8_t s_mac[PICO_SIZE_ETH];
tass picotcp@tass.be 149:5f4cb161cec3 71 struct pico_ip4 src;
tass picotcp@tass.be 149:5f4cb161cec3 72 uint8_t d_mac[PICO_SIZE_ETH];
tass picotcp@tass.be 149:5f4cb161cec3 73 struct pico_ip4 dst;
tass picotcp@tass.be 149:5f4cb161cec3 74 };
tass picotcp@tass.be 149:5f4cb161cec3 75
tass picotcp@tass.be 149:5f4cb161cec3 76
tass picotcp@tass.be 149:5f4cb161cec3 77
tass picotcp@tass.be 149:5f4cb161cec3 78 /* Callback handler for ip conflict service (e.g. IPv4 SLAAC)
tass picotcp@tass.be 149:5f4cb161cec3 79 * Whenever the IP address registered here is seen in the network,
tass picotcp@tass.be 149:5f4cb161cec3 80 * the callback is awaken to take countermeasures against IP collisions.
tass picotcp@tass.be 149:5f4cb161cec3 81 *
tass picotcp@tass.be 149:5f4cb161cec3 82 */
tass picotcp@tass.be 149:5f4cb161cec3 83
tass picotcp@tass.be 149:5f4cb161cec3 84 struct arp_service_ipconflict {
tass picotcp@tass.be 149:5f4cb161cec3 85 struct pico_eth mac;
tass picotcp@tass.be 149:5f4cb161cec3 86 struct pico_ip4 ip;
tass picotcp@tass.be 149:5f4cb161cec3 87 void (*conflict)(void);
tass picotcp@tass.be 149:5f4cb161cec3 88 };
tass picotcp@tass.be 149:5f4cb161cec3 89
tass picotcp@tass.be 149:5f4cb161cec3 90 static struct arp_service_ipconflict conflict_ipv4;
tass picotcp@tass.be 149:5f4cb161cec3 91
tass picotcp@tass.be 149:5f4cb161cec3 92
tass picotcp@tass.be 149:5f4cb161cec3 93
tass picotcp@tass.be 149:5f4cb161cec3 94 #define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr)))
tass picotcp@tass.be 149:5f4cb161cec3 95
tass picotcp@tass.be 149:5f4cb161cec3 96 /* Arp Entries for the tables. */
tass picotcp@tass.be 149:5f4cb161cec3 97 struct pico_arp {
tass picotcp@tass.be 149:5f4cb161cec3 98 /* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure,
tass picotcp@tass.be 149:5f4cb161cec3 99 * due to in-place casting!!! */
tass picotcp@tass.be 149:5f4cb161cec3 100 struct pico_eth eth;
tass picotcp@tass.be 149:5f4cb161cec3 101 struct pico_ip4 ipv4;
tass picotcp@tass.be 149:5f4cb161cec3 102 int arp_status;
tass picotcp@tass.be 149:5f4cb161cec3 103 pico_time timestamp;
tass picotcp@tass.be 149:5f4cb161cec3 104 struct pico_device *dev;
tass picotcp@tass.be 149:5f4cb161cec3 105 struct pico_timer *timer;
tass picotcp@tass.be 149:5f4cb161cec3 106 };
tass picotcp@tass.be 149:5f4cb161cec3 107
tass picotcp@tass.be 149:5f4cb161cec3 108
tass picotcp@tass.be 149:5f4cb161cec3 109
tass picotcp@tass.be 149:5f4cb161cec3 110 /*****************/
tass picotcp@tass.be 149:5f4cb161cec3 111 /** ARP TREE **/
tass picotcp@tass.be 149:5f4cb161cec3 112 /*****************/
tass picotcp@tass.be 149:5f4cb161cec3 113
tass picotcp@tass.be 149:5f4cb161cec3 114 /* Routing destination */
tass picotcp@tass.be 149:5f4cb161cec3 115
tass picotcp@tass.be 149:5f4cb161cec3 116 static int arp_compare(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 117 {
tass picotcp@tass.be 149:5f4cb161cec3 118 struct pico_arp *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 119 if (a->ipv4.addr < b->ipv4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 120 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 121 else if (a->ipv4.addr > b->ipv4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 122 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 123
tass picotcp@tass.be 149:5f4cb161cec3 124 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 125 }
tass picotcp@tass.be 149:5f4cb161cec3 126
tass picotcp@tass.be 149:5f4cb161cec3 127 PICO_TREE_DECLARE(arp_tree, arp_compare);
tass picotcp@tass.be 149:5f4cb161cec3 128
tass picotcp@tass.be 149:5f4cb161cec3 129 /*********************/
tass picotcp@tass.be 149:5f4cb161cec3 130 /** END ARP TREE **/
tass picotcp@tass.be 149:5f4cb161cec3 131 /*********************/
tass picotcp@tass.be 149:5f4cb161cec3 132
tass picotcp@tass.be 149:5f4cb161cec3 133 struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst)
tass picotcp@tass.be 149:5f4cb161cec3 134 {
tass picotcp@tass.be 149:5f4cb161cec3 135 struct pico_arp search, *found;
tass picotcp@tass.be 149:5f4cb161cec3 136 search.ipv4.addr = dst->addr;
tass picotcp@tass.be 149:5f4cb161cec3 137 found = pico_tree_findKey(&arp_tree, &search);
tass picotcp@tass.be 149:5f4cb161cec3 138 if (found && (found->arp_status != PICO_ARP_STATUS_STALE))
tass picotcp@tass.be 149:5f4cb161cec3 139 return &found->eth;
tass picotcp@tass.be 149:5f4cb161cec3 140
tass picotcp@tass.be 149:5f4cb161cec3 141 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 142 }
tass picotcp@tass.be 149:5f4cb161cec3 143
tass picotcp@tass.be 149:5f4cb161cec3 144 struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst)
tass picotcp@tass.be 149:5f4cb161cec3 145 {
tass picotcp@tass.be 149:5f4cb161cec3 146 struct pico_arp*search;
tass picotcp@tass.be 149:5f4cb161cec3 147 struct pico_tree_node *index;
tass picotcp@tass.be 149:5f4cb161cec3 148 pico_tree_foreach(index, &arp_tree){
tass picotcp@tass.be 149:5f4cb161cec3 149 search = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 150 if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0)
tass picotcp@tass.be 149:5f4cb161cec3 151 return &search->ipv4;
tass picotcp@tass.be 149:5f4cb161cec3 152 }
tass picotcp@tass.be 149:5f4cb161cec3 153 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 154 }
tass picotcp@tass.be 149:5f4cb161cec3 155
tass picotcp@tass.be 149:5f4cb161cec3 156 void pico_arp_retry(struct pico_frame *f, struct pico_ip4 *where)
tass picotcp@tass.be 149:5f4cb161cec3 157 {
tass picotcp@tass.be 149:5f4cb161cec3 158 if (++f->failure_count < 4) {
tass picotcp@tass.be 149:5f4cb161cec3 159 arp_dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count);
tass picotcp@tass.be 149:5f4cb161cec3 160 /* check if dst is local (gateway = 0), or if to use gateway */
tass picotcp@tass.be 149:5f4cb161cec3 161 pico_arp_request(f->dev, where, PICO_ARP_QUERY);
tass picotcp@tass.be 149:5f4cb161cec3 162 pico_enqueue(&pending, f);
tass picotcp@tass.be 149:5f4cb161cec3 163 if (!pending_timer_on) {
tass picotcp@tass.be 149:5f4cb161cec3 164 pending_timer_on++;
tass picotcp@tass.be 149:5f4cb161cec3 165 pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
tass picotcp@tass.be 149:5f4cb161cec3 166 }
tass picotcp@tass.be 149:5f4cb161cec3 167 } else {
tass picotcp@tass.be 149:5f4cb161cec3 168 dbg("ARP: Destination Unreachable\n");
tass picotcp@tass.be 149:5f4cb161cec3 169 pico_notify_dest_unreachable(f);
tass picotcp@tass.be 149:5f4cb161cec3 170 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 171 }
tass picotcp@tass.be 149:5f4cb161cec3 172 }
tass picotcp@tass.be 149:5f4cb161cec3 173
tass picotcp@tass.be 149:5f4cb161cec3 174 struct pico_eth *pico_arp_get(struct pico_frame *f)
tass picotcp@tass.be 149:5f4cb161cec3 175 {
tass picotcp@tass.be 149:5f4cb161cec3 176 struct pico_eth *a4;
tass picotcp@tass.be 149:5f4cb161cec3 177 struct pico_ip4 gateway;
tass picotcp@tass.be 149:5f4cb161cec3 178 struct pico_ip4 *where;
tass picotcp@tass.be 149:5f4cb161cec3 179 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 180 struct pico_ipv4_link *l;
tass picotcp@tass.be 149:5f4cb161cec3 181 if (!hdr)
tass picotcp@tass.be 149:5f4cb161cec3 182 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 183
tass picotcp@tass.be 149:5f4cb161cec3 184 l = pico_ipv4_link_get(&hdr->dst);
tass picotcp@tass.be 149:5f4cb161cec3 185 if(l) {
tass picotcp@tass.be 149:5f4cb161cec3 186 /* address belongs to ourself */
tass picotcp@tass.be 149:5f4cb161cec3 187 return &l->dev->eth->mac;
tass picotcp@tass.be 149:5f4cb161cec3 188 }
tass picotcp@tass.be 149:5f4cb161cec3 189
tass picotcp@tass.be 149:5f4cb161cec3 190 gateway = pico_ipv4_route_get_gateway(&hdr->dst);
tass picotcp@tass.be 149:5f4cb161cec3 191 /* check if dst is local (gateway = 0), or if to use gateway */
tass picotcp@tass.be 149:5f4cb161cec3 192 if (gateway.addr != 0)
tass picotcp@tass.be 149:5f4cb161cec3 193 where = &gateway;
tass picotcp@tass.be 149:5f4cb161cec3 194 else
tass picotcp@tass.be 149:5f4cb161cec3 195 where = &hdr->dst;
tass picotcp@tass.be 149:5f4cb161cec3 196
tass picotcp@tass.be 149:5f4cb161cec3 197 a4 = pico_arp_lookup(where); /* check if dst ip mac in cache */
tass picotcp@tass.be 149:5f4cb161cec3 198
tass picotcp@tass.be 149:5f4cb161cec3 199 if (!a4)
tass picotcp@tass.be 149:5f4cb161cec3 200 pico_arp_retry(f, where);
tass picotcp@tass.be 149:5f4cb161cec3 201
tass picotcp@tass.be 149:5f4cb161cec3 202 return a4;
tass picotcp@tass.be 149:5f4cb161cec3 203 }
tass picotcp@tass.be 149:5f4cb161cec3 204
tass picotcp@tass.be 149:5f4cb161cec3 205 #ifdef DEBUG_ARP
tass picotcp@tass.be 149:5f4cb161cec3 206 void dbg_arp(void)
tass picotcp@tass.be 149:5f4cb161cec3 207 {
tass picotcp@tass.be 149:5f4cb161cec3 208 struct pico_arp *a;
tass picotcp@tass.be 149:5f4cb161cec3 209 struct pico_tree_node *index;
tass picotcp@tass.be 149:5f4cb161cec3 210
tass picotcp@tass.be 149:5f4cb161cec3 211 pico_tree_foreach(index, &arp_tree) {
tass picotcp@tass.be 149:5f4cb161cec3 212 a = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 213 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 picotcp@tass.be 149:5f4cb161cec3 214 }
tass picotcp@tass.be 149:5f4cb161cec3 215 }
tass picotcp@tass.be 149:5f4cb161cec3 216 #endif
tass picotcp@tass.be 149:5f4cb161cec3 217
tass picotcp@tass.be 149:5f4cb161cec3 218 static void arp_expire(pico_time now, void *_stale)
tass picotcp@tass.be 149:5f4cb161cec3 219 {
tass picotcp@tass.be 149:5f4cb161cec3 220 struct pico_arp *stale = (struct pico_arp *) _stale;
tass picotcp@tass.be 149:5f4cb161cec3 221 if (now >= (stale->timestamp + PICO_ARP_TIMEOUT)) {
tass picotcp@tass.be 149:5f4cb161cec3 222 stale->arp_status = PICO_ARP_STATUS_STALE;
tass picotcp@tass.be 149:5f4cb161cec3 223 arp_dbg("ARP: Setting arp_status to STALE\n");
tass picotcp@tass.be 149:5f4cb161cec3 224 pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY);
tass picotcp@tass.be 149:5f4cb161cec3 225 } else {
tass picotcp@tass.be 149:5f4cb161cec3 226 /* Timer must be rescheduled, ARP entry has been renewed lately.
tass picotcp@tass.be 149:5f4cb161cec3 227 * No action required to refresh the entry, will check on the next timeout */
tass picotcp@tass.be 149:5f4cb161cec3 228 pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale);
tass picotcp@tass.be 149:5f4cb161cec3 229 }
tass picotcp@tass.be 149:5f4cb161cec3 230 }
tass picotcp@tass.be 149:5f4cb161cec3 231
tass picotcp@tass.be 149:5f4cb161cec3 232 static void pico_arp_add_entry(struct pico_arp *entry)
tass picotcp@tass.be 149:5f4cb161cec3 233 {
tass picotcp@tass.be 149:5f4cb161cec3 234 entry->arp_status = PICO_ARP_STATUS_REACHABLE;
tass picotcp@tass.be 149:5f4cb161cec3 235 entry->timestamp = PICO_TIME();
tass picotcp@tass.be 149:5f4cb161cec3 236
tass picotcp@tass.be 149:5f4cb161cec3 237 pico_tree_insert(&arp_tree, entry);
tass picotcp@tass.be 149:5f4cb161cec3 238 arp_dbg("ARP ## reachable.\n");
tass picotcp@tass.be 149:5f4cb161cec3 239 pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry);
tass picotcp@tass.be 149:5f4cb161cec3 240 }
tass picotcp@tass.be 149:5f4cb161cec3 241
tass picotcp@tass.be 149:5f4cb161cec3 242 int pico_arp_create_entry(uint8_t *hwaddr, struct pico_ip4 ipv4, struct pico_device *dev)
tass picotcp@tass.be 149:5f4cb161cec3 243 {
tass picotcp@tass.be 149:5f4cb161cec3 244 struct pico_arp*arp = PICO_ZALLOC(sizeof(struct pico_arp));
tass picotcp@tass.be 149:5f4cb161cec3 245 if(!arp) {
tass picotcp@tass.be 149:5f4cb161cec3 246 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 247 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 248 }
tass picotcp@tass.be 149:5f4cb161cec3 249
tass picotcp@tass.be 149:5f4cb161cec3 250 memcpy(arp->eth.addr, hwaddr, 6);
tass picotcp@tass.be 149:5f4cb161cec3 251 arp->ipv4.addr = ipv4.addr;
tass picotcp@tass.be 149:5f4cb161cec3 252 arp->dev = dev;
tass picotcp@tass.be 149:5f4cb161cec3 253
tass picotcp@tass.be 149:5f4cb161cec3 254 pico_arp_add_entry(arp);
tass picotcp@tass.be 149:5f4cb161cec3 255
tass picotcp@tass.be 149:5f4cb161cec3 256 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 257 }
tass picotcp@tass.be 149:5f4cb161cec3 258
tass picotcp@tass.be 149:5f4cb161cec3 259 static void pico_arp_check_conflict(struct pico_arp_hdr *hdr)
tass picotcp@tass.be 149:5f4cb161cec3 260 {
tass picotcp@tass.be 149:5f4cb161cec3 261
tass picotcp@tass.be 149:5f4cb161cec3 262 if ((conflict_ipv4.conflict) &&
tass picotcp@tass.be 149:5f4cb161cec3 263 ((conflict_ipv4.ip.addr == hdr->src.addr) &&
tass picotcp@tass.be 149:5f4cb161cec3 264 (memcmp(hdr->s_mac, conflict_ipv4.mac.addr, PICO_SIZE_ETH) != 0)))
tass picotcp@tass.be 149:5f4cb161cec3 265 conflict_ipv4.conflict();
tass picotcp@tass.be 149:5f4cb161cec3 266 }
tass picotcp@tass.be 149:5f4cb161cec3 267
tass picotcp@tass.be 149:5f4cb161cec3 268 static struct pico_arp *pico_arp_lookup_entry(struct pico_frame *f)
tass picotcp@tass.be 149:5f4cb161cec3 269 {
tass picotcp@tass.be 149:5f4cb161cec3 270 struct pico_arp search;
tass picotcp@tass.be 149:5f4cb161cec3 271 struct pico_arp *found = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 272 struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 273 /* Populate a new arp entry */
tass picotcp@tass.be 149:5f4cb161cec3 274 search.ipv4.addr = hdr->src.addr;
tass picotcp@tass.be 149:5f4cb161cec3 275
tass picotcp@tass.be 149:5f4cb161cec3 276 /* Search for already existing entry */
tass picotcp@tass.be 149:5f4cb161cec3 277 found = pico_tree_findKey(&arp_tree, &search);
tass picotcp@tass.be 149:5f4cb161cec3 278 if (found) {
tass picotcp@tass.be 149:5f4cb161cec3 279 if (found->arp_status == PICO_ARP_STATUS_STALE) {
tass picotcp@tass.be 149:5f4cb161cec3 280 /* Replace if stale */
tass picotcp@tass.be 149:5f4cb161cec3 281 pico_tree_delete(&arp_tree, found);
tass picotcp@tass.be 149:5f4cb161cec3 282 pico_arp_add_entry(found);
tass picotcp@tass.be 149:5f4cb161cec3 283 } else {
tass picotcp@tass.be 149:5f4cb161cec3 284 /* Update mac address */
tass picotcp@tass.be 149:5f4cb161cec3 285 memcpy(found->eth.addr, hdr->s_mac, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 286 arp_dbg("ARP entry updated!\n");
tass picotcp@tass.be 149:5f4cb161cec3 287
tass picotcp@tass.be 149:5f4cb161cec3 288 /* Refresh timestamp, this will force a reschedule on the next timeout*/
tass picotcp@tass.be 149:5f4cb161cec3 289 found->timestamp = PICO_TIME();
tass picotcp@tass.be 149:5f4cb161cec3 290 }
tass picotcp@tass.be 149:5f4cb161cec3 291 }
tass picotcp@tass.be 149:5f4cb161cec3 292
tass picotcp@tass.be 149:5f4cb161cec3 293 return found;
tass picotcp@tass.be 149:5f4cb161cec3 294 }
tass picotcp@tass.be 149:5f4cb161cec3 295
tass picotcp@tass.be 149:5f4cb161cec3 296
tass picotcp@tass.be 149:5f4cb161cec3 297 static int pico_arp_check_incoming_hdr_type(struct pico_arp_hdr *h)
tass picotcp@tass.be 149:5f4cb161cec3 298 {
tass picotcp@tass.be 149:5f4cb161cec3 299 /* Check the hardware type and protocol */
tass picotcp@tass.be 149:5f4cb161cec3 300 if ((h->htype != PICO_ARP_HTYPE_ETH) || (h->ptype != PICO_IDETH_IPV4))
tass picotcp@tass.be 149:5f4cb161cec3 301 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 302
tass picotcp@tass.be 149:5f4cb161cec3 303 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 304 }
tass picotcp@tass.be 149:5f4cb161cec3 305
tass picotcp@tass.be 149:5f4cb161cec3 306 static int pico_arp_check_incoming_hdr(struct pico_frame *f, struct pico_ip4 *dst_addr)
tass picotcp@tass.be 149:5f4cb161cec3 307 {
tass picotcp@tass.be 149:5f4cb161cec3 308 struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 309 if (!hdr)
tass picotcp@tass.be 149:5f4cb161cec3 310 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 311
tass picotcp@tass.be 149:5f4cb161cec3 312 dst_addr->addr = hdr->dst.addr;
tass picotcp@tass.be 149:5f4cb161cec3 313 if (pico_arp_check_incoming_hdr_type(hdr) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 314 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 315
tass picotcp@tass.be 149:5f4cb161cec3 316 /* The source mac address must not be a multicast or broadcast address */
tass picotcp@tass.be 149:5f4cb161cec3 317 if (hdr->s_mac[0] & 0x01)
tass picotcp@tass.be 149:5f4cb161cec3 318 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 319
tass picotcp@tass.be 149:5f4cb161cec3 320 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 321 }
tass picotcp@tass.be 149:5f4cb161cec3 322
tass picotcp@tass.be 149:5f4cb161cec3 323 static void pico_arp_reply_on_request(struct pico_frame *f, struct pico_ip4 me)
tass picotcp@tass.be 149:5f4cb161cec3 324 {
tass picotcp@tass.be 149:5f4cb161cec3 325 struct pico_arp_hdr *hdr;
tass picotcp@tass.be 149:5f4cb161cec3 326 struct pico_eth_hdr *eh;
tass picotcp@tass.be 149:5f4cb161cec3 327
tass picotcp@tass.be 149:5f4cb161cec3 328 hdr = (struct pico_arp_hdr *) f->net_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 329 eh = (struct pico_eth_hdr *)f->datalink_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 330 if (hdr->opcode != PICO_ARP_REQUEST)
tass picotcp@tass.be 149:5f4cb161cec3 331 return;
tass picotcp@tass.be 149:5f4cb161cec3 332
tass picotcp@tass.be 149:5f4cb161cec3 333 hdr->opcode = PICO_ARP_REPLY;
tass picotcp@tass.be 149:5f4cb161cec3 334 memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 335 memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 336 hdr->dst.addr = hdr->src.addr;
tass picotcp@tass.be 149:5f4cb161cec3 337 hdr->src.addr = me.addr;
tass picotcp@tass.be 149:5f4cb161cec3 338
tass picotcp@tass.be 149:5f4cb161cec3 339 /* Prepare eth header for arp reply */
tass picotcp@tass.be 149:5f4cb161cec3 340 memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 341 memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 342 f->start = f->datalink_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 343 f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR;
tass picotcp@tass.be 149:5f4cb161cec3 344 f->dev->send(f->dev, f->start, (int)f->len);
tass picotcp@tass.be 149:5f4cb161cec3 345 }
tass picotcp@tass.be 149:5f4cb161cec3 346
tass picotcp@tass.be 149:5f4cb161cec3 347 static int pico_arp_check_flooding(struct pico_frame *f, struct pico_ip4 me)
tass picotcp@tass.be 149:5f4cb161cec3 348 {
tass picotcp@tass.be 149:5f4cb161cec3 349 struct pico_device *link_dev;
tass picotcp@tass.be 149:5f4cb161cec3 350 struct pico_arp_hdr *hdr;
tass picotcp@tass.be 149:5f4cb161cec3 351 hdr = (struct pico_arp_hdr *) f->net_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 352
tass picotcp@tass.be 149:5f4cb161cec3 353 /* Prevent ARP flooding */
tass picotcp@tass.be 149:5f4cb161cec3 354 link_dev = pico_ipv4_link_find(&me);
tass picotcp@tass.be 149:5f4cb161cec3 355 if ((link_dev == f->dev) && (hdr->opcode == PICO_ARP_REQUEST)) {
tass picotcp@tass.be 149:5f4cb161cec3 356 if (max_arp_reqs == 0)
tass picotcp@tass.be 149:5f4cb161cec3 357 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 358 else
tass picotcp@tass.be 149:5f4cb161cec3 359 max_arp_reqs--;
tass picotcp@tass.be 149:5f4cb161cec3 360 }
tass picotcp@tass.be 149:5f4cb161cec3 361
tass picotcp@tass.be 149:5f4cb161cec3 362 /* Check if we are the target IP address */
tass picotcp@tass.be 149:5f4cb161cec3 363 if (link_dev != f->dev)
tass picotcp@tass.be 149:5f4cb161cec3 364 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 365
tass picotcp@tass.be 149:5f4cb161cec3 366 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 367 }
tass picotcp@tass.be 149:5f4cb161cec3 368
tass picotcp@tass.be 149:5f4cb161cec3 369 static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, struct pico_arp *found)
tass picotcp@tass.be 149:5f4cb161cec3 370 {
tass picotcp@tass.be 149:5f4cb161cec3 371 struct pico_ip4 me;
tass picotcp@tass.be 149:5f4cb161cec3 372 if (pico_arp_check_incoming_hdr(f, &me) < 0) {
tass picotcp@tass.be 149:5f4cb161cec3 373 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 374 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 375 }
tass picotcp@tass.be 149:5f4cb161cec3 376
tass picotcp@tass.be 149:5f4cb161cec3 377 if (pico_arp_check_flooding(f, me) < 0) {
tass picotcp@tass.be 149:5f4cb161cec3 378 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 379 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 380 }
tass picotcp@tass.be 149:5f4cb161cec3 381
tass picotcp@tass.be 149:5f4cb161cec3 382 /* If no existing entry was found, create a new entry, or fail trying. */
tass picotcp@tass.be 149:5f4cb161cec3 383 if ((!found) && (pico_arp_create_entry(hdr->s_mac, hdr->src, f->dev) < 0)) {
tass picotcp@tass.be 149:5f4cb161cec3 384 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 385 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 386 }
tass picotcp@tass.be 149:5f4cb161cec3 387
tass picotcp@tass.be 149:5f4cb161cec3 388 /* If the packet is a request, send a reply */
tass picotcp@tass.be 149:5f4cb161cec3 389 pico_arp_reply_on_request(f, me);
tass picotcp@tass.be 149:5f4cb161cec3 390
tass picotcp@tass.be 149:5f4cb161cec3 391 #ifdef DEBUG_ARP
tass picotcp@tass.be 149:5f4cb161cec3 392 dbg_arp();
tass picotcp@tass.be 149:5f4cb161cec3 393 #endif
tass picotcp@tass.be 149:5f4cb161cec3 394 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 395 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 396 }
tass picotcp@tass.be 149:5f4cb161cec3 397
tass picotcp@tass.be 149:5f4cb161cec3 398 int pico_arp_receive(struct pico_frame *f)
tass picotcp@tass.be 149:5f4cb161cec3 399 {
tass picotcp@tass.be 149:5f4cb161cec3 400 struct pico_arp_hdr *hdr;
tass picotcp@tass.be 149:5f4cb161cec3 401 struct pico_arp *found = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 402
tass picotcp@tass.be 149:5f4cb161cec3 403 hdr = (struct pico_arp_hdr *) f->net_hdr;
tass picotcp@tass.be 149:5f4cb161cec3 404 if (!hdr)
tass picotcp@tass.be 149:5f4cb161cec3 405 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 406
tass picotcp@tass.be 149:5f4cb161cec3 407 pico_arp_check_conflict(hdr);
tass picotcp@tass.be 149:5f4cb161cec3 408 found = pico_arp_lookup_entry(f);
tass picotcp@tass.be 149:5f4cb161cec3 409 return pico_arp_process_in(f, hdr, found);
tass picotcp@tass.be 149:5f4cb161cec3 410
tass picotcp@tass.be 149:5f4cb161cec3 411 }
tass picotcp@tass.be 149:5f4cb161cec3 412
tass picotcp@tass.be 149:5f4cb161cec3 413 int32_t pico_arp_request_xmit(struct pico_device *dev, struct pico_frame *f, struct pico_ip4 *src, struct pico_ip4 *dst, uint8_t type)
tass picotcp@tass.be 149:5f4cb161cec3 414 {
tass picotcp@tass.be 149:5f4cb161cec3 415 struct pico_arp_hdr *ah = (struct pico_arp_hdr *) (f->start + PICO_SIZE_ETHHDR);
tass picotcp@tass.be 149:5f4cb161cec3 416 int ret;
tass picotcp@tass.be 149:5f4cb161cec3 417
tass picotcp@tass.be 149:5f4cb161cec3 418 /* Fill arp header */
tass picotcp@tass.be 149:5f4cb161cec3 419 ah->htype = PICO_ARP_HTYPE_ETH;
tass picotcp@tass.be 149:5f4cb161cec3 420 ah->ptype = PICO_IDETH_IPV4;
tass picotcp@tass.be 149:5f4cb161cec3 421 ah->hsize = PICO_SIZE_ETH;
tass picotcp@tass.be 149:5f4cb161cec3 422 ah->psize = PICO_SIZE_IP4;
tass picotcp@tass.be 149:5f4cb161cec3 423 ah->opcode = PICO_ARP_REQUEST;
tass picotcp@tass.be 149:5f4cb161cec3 424 memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 425
tass picotcp@tass.be 149:5f4cb161cec3 426 switch (type) {
tass picotcp@tass.be 149:5f4cb161cec3 427 case PICO_ARP_ANNOUNCE:
tass picotcp@tass.be 149:5f4cb161cec3 428 ah->src.addr = dst->addr;
tass picotcp@tass.be 149:5f4cb161cec3 429 ah->dst.addr = dst->addr;
tass picotcp@tass.be 149:5f4cb161cec3 430 break;
tass picotcp@tass.be 149:5f4cb161cec3 431 case PICO_ARP_PROBE:
tass picotcp@tass.be 149:5f4cb161cec3 432 ah->src.addr = 0;
tass picotcp@tass.be 149:5f4cb161cec3 433 ah->dst.addr = dst->addr;
tass picotcp@tass.be 149:5f4cb161cec3 434 break;
tass picotcp@tass.be 149:5f4cb161cec3 435 case PICO_ARP_QUERY:
tass picotcp@tass.be 149:5f4cb161cec3 436 ah->src.addr = src->addr;
tass picotcp@tass.be 149:5f4cb161cec3 437 ah->dst.addr = dst->addr;
tass picotcp@tass.be 149:5f4cb161cec3 438 break;
tass picotcp@tass.be 149:5f4cb161cec3 439 default:
tass picotcp@tass.be 149:5f4cb161cec3 440 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 441 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 442 }
tass picotcp@tass.be 149:5f4cb161cec3 443 arp_dbg("Sending arp request.\n");
tass picotcp@tass.be 149:5f4cb161cec3 444 ret = dev->send(dev, f->start, (int) f->len);
tass picotcp@tass.be 149:5f4cb161cec3 445 pico_frame_discard(f);
tass picotcp@tass.be 149:5f4cb161cec3 446 return ret;
tass picotcp@tass.be 149:5f4cb161cec3 447 }
tass picotcp@tass.be 149:5f4cb161cec3 448
tass picotcp@tass.be 149:5f4cb161cec3 449 int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type)
tass picotcp@tass.be 149:5f4cb161cec3 450 {
tass picotcp@tass.be 149:5f4cb161cec3 451 struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR);
tass picotcp@tass.be 149:5f4cb161cec3 452 struct pico_eth_hdr *eh;
tass picotcp@tass.be 149:5f4cb161cec3 453 struct pico_ip4 *src = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 454
tass picotcp@tass.be 149:5f4cb161cec3 455 if (!q)
tass picotcp@tass.be 149:5f4cb161cec3 456 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 457
tass picotcp@tass.be 149:5f4cb161cec3 458 if (type == PICO_ARP_QUERY)
tass picotcp@tass.be 149:5f4cb161cec3 459 {
tass picotcp@tass.be 149:5f4cb161cec3 460 src = pico_ipv4_source_find(dst);
tass picotcp@tass.be 149:5f4cb161cec3 461 if (!src) {
tass picotcp@tass.be 149:5f4cb161cec3 462 pico_frame_discard(q);
tass picotcp@tass.be 149:5f4cb161cec3 463 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 464 }
tass picotcp@tass.be 149:5f4cb161cec3 465 }
tass picotcp@tass.be 149:5f4cb161cec3 466
tass picotcp@tass.be 149:5f4cb161cec3 467 arp_dbg("QUERY: %08x\n", dst->addr);
tass picotcp@tass.be 149:5f4cb161cec3 468
tass picotcp@tass.be 149:5f4cb161cec3 469 eh = (struct pico_eth_hdr *)q->start;
tass picotcp@tass.be 149:5f4cb161cec3 470
tass picotcp@tass.be 149:5f4cb161cec3 471 /* Fill eth header */
tass picotcp@tass.be 149:5f4cb161cec3 472 memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 473 memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH);
tass picotcp@tass.be 149:5f4cb161cec3 474 eh->proto = PICO_IDETH_ARP;
tass picotcp@tass.be 149:5f4cb161cec3 475
tass picotcp@tass.be 149:5f4cb161cec3 476 return pico_arp_request_xmit(dev, q, src, dst, type);
tass picotcp@tass.be 149:5f4cb161cec3 477 }
tass picotcp@tass.be 149:5f4cb161cec3 478
tass picotcp@tass.be 149:5f4cb161cec3 479 int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen)
tass picotcp@tass.be 149:5f4cb161cec3 480 {
tass picotcp@tass.be 149:5f4cb161cec3 481 struct pico_arp*search;
tass picotcp@tass.be 149:5f4cb161cec3 482 struct pico_tree_node *index;
tass picotcp@tass.be 149:5f4cb161cec3 483 int i = 0;
tass picotcp@tass.be 149:5f4cb161cec3 484 pico_tree_foreach(index, &arp_tree){
tass picotcp@tass.be 149:5f4cb161cec3 485 search = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 486 if (search->dev == dev) {
tass picotcp@tass.be 149:5f4cb161cec3 487 neighbors[i++].addr = search->ipv4.addr;
tass picotcp@tass.be 149:5f4cb161cec3 488 if (i >= maxlen)
tass picotcp@tass.be 149:5f4cb161cec3 489 return i;
tass picotcp@tass.be 149:5f4cb161cec3 490 }
tass picotcp@tass.be 149:5f4cb161cec3 491 }
tass picotcp@tass.be 149:5f4cb161cec3 492 return i;
tass picotcp@tass.be 149:5f4cb161cec3 493 }
tass picotcp@tass.be 149:5f4cb161cec3 494
tass picotcp@tass.be 149:5f4cb161cec3 495 void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(void))
tass picotcp@tass.be 149:5f4cb161cec3 496 {
tass picotcp@tass.be 149:5f4cb161cec3 497 conflict_ipv4.conflict = cb;
tass picotcp@tass.be 149:5f4cb161cec3 498 conflict_ipv4.ip.addr = ip->addr;
tass picotcp@tass.be 149:5f4cb161cec3 499 if (mac != NULL)
tass picotcp@tass.be 149:5f4cb161cec3 500 memcpy(conflict_ipv4.mac.addr, mac, 6);
tass picotcp@tass.be 149:5f4cb161cec3 501 }
tass picotcp@tass.be 149:5f4cb161cec3 502