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 Jan 28 15:12:00 2016 +0100
Revision:
155:a70f34550c34
Parent:
154:6c0e92a80c4a
Adding TCP flag for FIN.

Who changed what in which revision?

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