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
pico_arp.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 . 00006 00007 Authors: Daniele Lacamera 00008 *********************************************************************/ 00009 00010 00011 #include "pico_config.h" 00012 #include "pico_arp.h" 00013 #include "pico_tree.h" 00014 #include "pico_ipv4.h" 00015 #include "pico_device.h" 00016 #include "pico_stack.h" 00017 00018 extern const uint8_t PICO_ETHADDR_ALL[6]; 00019 #define PICO_ARP_TIMEOUT 600000llu 00020 #define PICO_ARP_RETRY 300lu 00021 #define PICO_ARP_MAX_PENDING 5 00022 00023 #ifdef DEBUG_ARP 00024 #define arp_dbg dbg 00025 #else 00026 #define arp_dbg(...) do {} while(0) 00027 #endif 00028 00029 static int max_arp_reqs = PICO_ARP_MAX_RATE; 00030 static struct pico_frame *frames_queued[PICO_ARP_MAX_PENDING] = { 0 }; 00031 00032 static void pico_arp_queued_trigger(void) 00033 { 00034 int i; 00035 struct pico_frame *f; 00036 for (i = 0; i < PICO_ARP_MAX_PENDING; i++) 00037 { 00038 f = frames_queued[i]; 00039 if (f) { 00040 if (!pico_ethernet_send(f)) 00041 { 00042 pico_frame_discard(f); 00043 frames_queued[i] = NULL; 00044 } 00045 } 00046 } 00047 } 00048 00049 static void update_max_arp_reqs(pico_time now, void *unused) 00050 { 00051 IGNORE_PARAMETER(now); 00052 IGNORE_PARAMETER(unused); 00053 if (max_arp_reqs < PICO_ARP_MAX_RATE) 00054 max_arp_reqs++; 00055 00056 pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL); 00057 } 00058 00059 void pico_arp_init(void) 00060 { 00061 pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL); 00062 } 00063 00064 PACKED_STRUCT_DEF pico_arp_hdr 00065 { 00066 uint16_t htype; 00067 uint16_t ptype; 00068 uint8_t hsize; 00069 uint8_t psize; 00070 uint16_t opcode; 00071 uint8_t s_mac[PICO_SIZE_ETH]; 00072 struct pico_ip4 src; 00073 uint8_t d_mac[PICO_SIZE_ETH]; 00074 struct pico_ip4 dst; 00075 }; 00076 00077 00078 00079 /* Callback handler for ip conflict service (e.g. IPv4 SLAAC) 00080 * Whenever the IP address registered here is seen in the network, 00081 * the callback is awaken to take countermeasures against IP collisions. 00082 * 00083 */ 00084 00085 struct arp_service_ipconflict { 00086 struct pico_eth mac; 00087 struct pico_ip4 ip; 00088 void (*conflict)(void); 00089 }; 00090 00091 static struct arp_service_ipconflict conflict_ipv4; 00092 00093 00094 00095 #define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr))) 00096 00097 /* Arp Entries for the tables. */ 00098 struct pico_arp { 00099 /* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure, 00100 * due to in-place casting!!! */ 00101 struct pico_eth eth; 00102 struct pico_ip4 ipv4; 00103 int arp_status; 00104 pico_time timestamp; 00105 struct pico_device *dev; 00106 struct pico_timer *timer; 00107 }; 00108 00109 00110 00111 /*****************/ 00112 /** ARP TREE **/ 00113 /*****************/ 00114 00115 /* Routing destination */ 00116 00117 static int arp_compare(void *ka, void *kb) 00118 { 00119 struct pico_arp *a = ka, *b = kb; 00120 return pico_ipv4_compare(&a->ipv4, &b->ipv4); 00121 } 00122 00123 PICO_TREE_DECLARE(arp_tree, arp_compare); 00124 00125 /*********************/ 00126 /** END ARP TREE **/ 00127 /*********************/ 00128 00129 struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst) 00130 { 00131 struct pico_arp search, *found; 00132 search.ipv4.addr = dst->addr; 00133 found = pico_tree_findKey(&arp_tree, &search); 00134 if (found && (found->arp_status != PICO_ARP_STATUS_STALE)) 00135 return &found->eth; 00136 00137 return NULL; 00138 } 00139 00140 struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst) 00141 { 00142 struct pico_arp*search; 00143 struct pico_tree_node *index; 00144 pico_tree_foreach(index, &arp_tree){ 00145 search = index->keyValue; 00146 if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0) 00147 return &search->ipv4; 00148 } 00149 return NULL; 00150 } 00151 00152 static void pico_arp_unreachable(struct pico_ip4 *a) 00153 { 00154 int i; 00155 struct pico_frame *f; 00156 struct pico_ipv4_hdr *hdr; 00157 struct pico_ip4 dst; 00158 for (i = 0; i < PICO_ARP_MAX_PENDING; i++) 00159 { 00160 f = frames_queued[i]; 00161 if (f) { 00162 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00163 dst = pico_ipv4_route_get_gateway(&hdr->dst); 00164 if (!dst.addr) 00165 dst.addr = hdr->dst.addr; 00166 00167 if (dst.addr == a->addr) { 00168 if (!pico_source_is_local(f)) { 00169 pico_notify_dest_unreachable(f); 00170 } 00171 00172 pico_frame_discard(f); 00173 frames_queued[i] = NULL; 00174 } 00175 } 00176 } 00177 } 00178 00179 static void pico_arp_retry(struct pico_frame *f, struct pico_ip4 *where) 00180 { 00181 if (++f->failure_count < 4) { 00182 arp_dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count); 00183 /* check if dst is local (gateway = 0), or if to use gateway */ 00184 pico_arp_request(f->dev, where, PICO_ARP_QUERY); 00185 } else { 00186 pico_arp_unreachable(where); 00187 } 00188 } 00189 00190 struct pico_eth *pico_arp_get(struct pico_frame *f) 00191 { 00192 struct pico_eth *a4; 00193 struct pico_ip4 gateway; 00194 struct pico_ip4 *where; 00195 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00196 struct pico_ipv4_link *l; 00197 if (!hdr) 00198 return NULL; 00199 00200 l = pico_ipv4_link_get(&hdr->dst); 00201 if(l) { 00202 /* address belongs to ourself */ 00203 return &l->dev->eth->mac; 00204 } 00205 00206 gateway = pico_ipv4_route_get_gateway(&hdr->dst); 00207 /* check if dst is local (gateway = 0), or if to use gateway */ 00208 if (gateway.addr != 0) 00209 where = &gateway; 00210 else 00211 where = &hdr->dst; 00212 00213 a4 = pico_arp_lookup(where); /* check if dst ip mac in cache */ 00214 00215 if (!a4) 00216 pico_arp_retry(f, where); 00217 00218 return a4; 00219 } 00220 00221 00222 void pico_arp_postpone(struct pico_frame *f) 00223 { 00224 int i; 00225 for (i = 0; i < PICO_ARP_MAX_PENDING; i++) 00226 { 00227 if (!frames_queued[i]) { 00228 frames_queued[i] = pico_frame_copy(f); 00229 return; 00230 } 00231 } 00232 /* Not possible to enqueue: caller will discard packet */ 00233 } 00234 00235 00236 #ifdef DEBUG_ARP 00237 void dbg_arp(void) 00238 { 00239 struct pico_arp *a; 00240 struct pico_tree_node *index; 00241 00242 pico_tree_foreach(index, &arp_tree) { 00243 a = index->keyValue; 00244 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] ); 00245 } 00246 } 00247 #endif 00248 00249 static void arp_expire(pico_time now, void *_stale) 00250 { 00251 struct pico_arp *stale = (struct pico_arp *) _stale; 00252 if (now >= (stale->timestamp + PICO_ARP_TIMEOUT)) { 00253 stale->arp_status = PICO_ARP_STATUS_STALE; 00254 arp_dbg("ARP: Setting arp_status to STALE\n"); 00255 pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY); 00256 } else { 00257 /* Timer must be rescheduled, ARP entry has been renewed lately. 00258 * No action required to refresh the entry, will check on the next timeout */ 00259 pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale); 00260 } 00261 } 00262 00263 static void pico_arp_add_entry(struct pico_arp *entry) 00264 { 00265 entry->arp_status = PICO_ARP_STATUS_REACHABLE; 00266 entry->timestamp = PICO_TIME(); 00267 00268 pico_tree_insert(&arp_tree, entry); 00269 arp_dbg("ARP ## reachable.\n"); 00270 pico_arp_queued_trigger(); 00271 pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry); 00272 } 00273 00274 int pico_arp_create_entry(uint8_t *hwaddr, struct pico_ip4 ipv4, struct pico_device *dev) 00275 { 00276 struct pico_arp*arp = PICO_ZALLOC(sizeof(struct pico_arp)); 00277 if(!arp) { 00278 pico_err = PICO_ERR_ENOMEM; 00279 return -1; 00280 } 00281 00282 memcpy(arp->eth.addr, hwaddr, 6); 00283 arp->ipv4.addr = ipv4.addr; 00284 arp->dev = dev; 00285 00286 pico_arp_add_entry(arp); 00287 00288 return 0; 00289 } 00290 00291 static void pico_arp_check_conflict(struct pico_arp_hdr *hdr) 00292 { 00293 00294 if ((conflict_ipv4.conflict) && 00295 ((conflict_ipv4.ip.addr == hdr->src.addr) && 00296 (memcmp(hdr->s_mac, conflict_ipv4.mac.addr, PICO_SIZE_ETH) != 0))) 00297 conflict_ipv4.conflict(); 00298 } 00299 00300 static struct pico_arp *pico_arp_lookup_entry(struct pico_frame *f) 00301 { 00302 struct pico_arp search; 00303 struct pico_arp *found = NULL; 00304 struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr; 00305 /* Populate a new arp entry */ 00306 search.ipv4.addr = hdr->src.addr; 00307 00308 /* Search for already existing entry */ 00309 found = pico_tree_findKey(&arp_tree, &search); 00310 if (found) { 00311 if (found->arp_status == PICO_ARP_STATUS_STALE) { 00312 /* Replace if stale */ 00313 pico_tree_delete(&arp_tree, found); 00314 pico_arp_add_entry(found); 00315 } else { 00316 /* Update mac address */ 00317 memcpy(found->eth.addr, hdr->s_mac, PICO_SIZE_ETH); 00318 arp_dbg("ARP entry updated!\n"); 00319 00320 /* Refresh timestamp, this will force a reschedule on the next timeout*/ 00321 found->timestamp = PICO_TIME(); 00322 } 00323 } 00324 00325 return found; 00326 } 00327 00328 00329 static int pico_arp_check_incoming_hdr_type(struct pico_arp_hdr *h) 00330 { 00331 /* Check the hardware type and protocol */ 00332 if ((h->htype != PICO_ARP_HTYPE_ETH) || (h->ptype != PICO_IDETH_IPV4)) 00333 return -1; 00334 00335 return 0; 00336 } 00337 00338 static int pico_arp_check_incoming_hdr(struct pico_frame *f, struct pico_ip4 *dst_addr) 00339 { 00340 struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr; 00341 if (!hdr) 00342 return -1; 00343 00344 dst_addr->addr = hdr->dst.addr; 00345 if (pico_arp_check_incoming_hdr_type(hdr) < 0) 00346 return -1; 00347 00348 /* The source mac address must not be a multicast or broadcast address */ 00349 if (hdr->s_mac[0] & 0x01) 00350 return -1; 00351 00352 return 0; 00353 } 00354 00355 static void pico_arp_reply_on_request(struct pico_frame *f, struct pico_ip4 me) 00356 { 00357 struct pico_arp_hdr *hdr; 00358 struct pico_eth_hdr *eh; 00359 00360 hdr = (struct pico_arp_hdr *) f->net_hdr; 00361 eh = (struct pico_eth_hdr *)f->datalink_hdr; 00362 if (hdr->opcode != PICO_ARP_REQUEST) 00363 return; 00364 00365 hdr->opcode = PICO_ARP_REPLY; 00366 memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH); 00367 memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH); 00368 hdr->dst.addr = hdr->src.addr; 00369 hdr->src.addr = me.addr; 00370 00371 /* Prepare eth header for arp reply */ 00372 memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH); 00373 memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); 00374 f->start = f->datalink_hdr; 00375 f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR; 00376 f->dev->send(f->dev, f->start, (int)f->len); 00377 } 00378 00379 static int pico_arp_check_flooding(struct pico_frame *f, struct pico_ip4 me) 00380 { 00381 struct pico_device *link_dev; 00382 struct pico_arp_hdr *hdr; 00383 hdr = (struct pico_arp_hdr *) f->net_hdr; 00384 00385 /* Prevent ARP flooding */ 00386 link_dev = pico_ipv4_link_find(&me); 00387 if ((link_dev == f->dev) && (hdr->opcode == PICO_ARP_REQUEST)) { 00388 if (max_arp_reqs == 0) 00389 return -1; 00390 else 00391 max_arp_reqs--; 00392 } 00393 00394 /* Check if we are the target IP address */ 00395 if (link_dev != f->dev) 00396 return -1; 00397 00398 return 0; 00399 } 00400 00401 static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, struct pico_arp *found) 00402 { 00403 struct pico_ip4 me; 00404 if (pico_arp_check_incoming_hdr(f, &me) < 0) { 00405 pico_frame_discard(f); 00406 return -1; 00407 } 00408 00409 if (pico_arp_check_flooding(f, me) < 0) { 00410 pico_frame_discard(f); 00411 return -1; 00412 } 00413 00414 /* If no existing entry was found, create a new entry, or fail trying. */ 00415 if ((!found) && (pico_arp_create_entry(hdr->s_mac, hdr->src, f->dev) < 0)) { 00416 pico_frame_discard(f); 00417 return -1; 00418 } 00419 00420 /* If the packet is a request, send a reply */ 00421 pico_arp_reply_on_request(f, me); 00422 00423 #ifdef DEBUG_ARP 00424 dbg_arp(); 00425 #endif 00426 pico_frame_discard(f); 00427 return 0; 00428 } 00429 00430 int pico_arp_receive(struct pico_frame *f) 00431 { 00432 struct pico_arp_hdr *hdr; 00433 struct pico_arp *found = NULL; 00434 00435 hdr = (struct pico_arp_hdr *) f->net_hdr; 00436 if (!hdr) 00437 return -1; 00438 00439 pico_arp_check_conflict(hdr); 00440 found = pico_arp_lookup_entry(f); 00441 return pico_arp_process_in(f, hdr, found); 00442 00443 } 00444 00445 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) 00446 { 00447 struct pico_arp_hdr *ah = (struct pico_arp_hdr *) (f->start + PICO_SIZE_ETHHDR); 00448 int ret; 00449 00450 /* Fill arp header */ 00451 ah->htype = PICO_ARP_HTYPE_ETH; 00452 ah->ptype = PICO_IDETH_IPV4; 00453 ah->hsize = PICO_SIZE_ETH; 00454 ah->psize = PICO_SIZE_IP4; 00455 ah->opcode = PICO_ARP_REQUEST; 00456 memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH); 00457 00458 switch (type) { 00459 case PICO_ARP_ANNOUNCE: 00460 ah->src.addr = dst->addr; 00461 ah->dst.addr = dst->addr; 00462 break; 00463 case PICO_ARP_PROBE: 00464 ah->src.addr = 0; 00465 ah->dst.addr = dst->addr; 00466 break; 00467 case PICO_ARP_QUERY: 00468 ah->src.addr = src->addr; 00469 ah->dst.addr = dst->addr; 00470 break; 00471 default: 00472 pico_frame_discard(f); 00473 return -1; 00474 } 00475 arp_dbg("Sending arp request.\n"); 00476 ret = dev->send(dev, f->start, (int) f->len); 00477 pico_frame_discard(f); 00478 return ret; 00479 } 00480 00481 int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type) 00482 { 00483 struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR); 00484 struct pico_eth_hdr *eh; 00485 struct pico_ip4 *src = NULL; 00486 00487 if (!q) 00488 return -1; 00489 00490 if (type == PICO_ARP_QUERY) 00491 { 00492 src = pico_ipv4_source_find(dst); 00493 if (!src) { 00494 pico_frame_discard(q); 00495 return -1; 00496 } 00497 } 00498 00499 arp_dbg("QUERY: %08x\n", dst->addr); 00500 00501 eh = (struct pico_eth_hdr *)q->start; 00502 00503 /* Fill eth header */ 00504 memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH); 00505 memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH); 00506 eh->proto = PICO_IDETH_ARP; 00507 00508 return pico_arp_request_xmit(dev, q, src, dst, type); 00509 } 00510 00511 int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen) 00512 { 00513 struct pico_arp*search; 00514 struct pico_tree_node *index; 00515 int i = 0; 00516 pico_tree_foreach(index, &arp_tree){ 00517 search = index->keyValue; 00518 if (search->dev == dev) { 00519 neighbors[i++].addr = search->ipv4.addr; 00520 if (i >= maxlen) 00521 return i; 00522 } 00523 } 00524 return i; 00525 } 00526 00527 void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(void)) 00528 { 00529 conflict_ipv4.conflict = cb; 00530 conflict_ipv4.ip.addr = ip->addr; 00531 if (mac != NULL) 00532 memcpy(conflict_ipv4.mac.addr, mac, 6); 00533 } 00534
Generated on Tue Jul 12 2022 15:59:21 by 1.7.2