Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of PicoTCP by
pico_arp.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. 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 const uint8_t PICO_ETHADDR_ALL[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 00019 #define PICO_ARP_TIMEOUT 600000 00020 #define PICO_ARP_RETRY 300 00021 00022 #ifdef DEBUG_ARP 00023 #define arp_dbg dbg 00024 #else 00025 #define arp_dbg(...) do{}while(0) 00026 #endif 00027 00028 static struct pico_queue pending; 00029 static int pending_timer_on = 0; 00030 00031 void check_pending(unsigned long now, void *_unused) 00032 { 00033 struct pico_frame *f = pico_dequeue(&pending); 00034 if (!f) { 00035 pending_timer_on = 0; 00036 return; 00037 } 00038 if(pico_ethernet_send(f) > 0) 00039 pico_frame_discard(f); 00040 pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL); 00041 } 00042 00043 00044 struct 00045 __attribute__ ((__packed__)) 00046 pico_arp_hdr 00047 { 00048 uint16_t htype; 00049 uint16_t ptype; 00050 uint8_t hsize; 00051 uint8_t psize; 00052 uint16_t opcode; 00053 uint8_t s_mac[PICO_SIZE_ETH]; 00054 struct pico_ip4 src; 00055 uint8_t d_mac[PICO_SIZE_ETH]; 00056 struct pico_ip4 dst; 00057 }; 00058 00059 00060 #define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr))) 00061 00062 /* Arp Entries for the tables. */ 00063 struct pico_arp { 00064 /* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure, 00065 * due to in-place casting!!! */ 00066 struct pico_eth eth; 00067 struct pico_ip4 ipv4; 00068 int arp_status; 00069 uint32_t timestamp; 00070 struct pico_device *dev; 00071 }; 00072 00073 00074 00075 /*****************/ 00076 /** ARP TREE **/ 00077 /*****************/ 00078 00079 /* Routing destination */ 00080 00081 static int arp_compare(void * ka, void * kb) 00082 { 00083 struct pico_arp *a = ka, *b = kb; 00084 if (a->ipv4.addr < b->ipv4.addr) 00085 return -1; 00086 else if (a->ipv4.addr > b->ipv4.addr) 00087 return 1; 00088 return 0; 00089 } 00090 00091 PICO_TREE_DECLARE(arp_tree, arp_compare); 00092 00093 /*********************/ 00094 /** END ARP TREE **/ 00095 /*********************/ 00096 00097 struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst) 00098 { 00099 struct pico_arp search, *found; 00100 search.ipv4.addr = dst->addr; 00101 found = pico_tree_findKey(&arp_tree,&search); 00102 if (found && (found->arp_status != PICO_ARP_STATUS_STALE)) 00103 return &found->eth; 00104 return NULL; 00105 } 00106 00107 struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst) 00108 { 00109 struct pico_arp* search; 00110 struct pico_tree_node * index; 00111 pico_tree_foreach(index,&arp_tree){ 00112 search = index->keyValue; 00113 if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0) 00114 return &search->ipv4; 00115 } 00116 return NULL; 00117 } 00118 00119 struct pico_eth *pico_arp_get(struct pico_frame *f) { 00120 struct pico_eth *a4; 00121 struct pico_ip4 gateway; 00122 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00123 struct pico_ipv4_link *l; 00124 00125 l = pico_ipv4_link_get(&hdr->dst); 00126 if(l){ 00127 //address belongs to ourself 00128 return &l->dev->eth->mac; 00129 } 00130 00131 gateway = pico_ipv4_route_get_gateway(&hdr->dst); 00132 /* check if dst is local (gateway = 0), or if to use gateway */ 00133 if (gateway.addr != 0) 00134 a4 = pico_arp_lookup(&gateway); /* check if gateway ip mac in cache */ 00135 else 00136 a4 = pico_arp_lookup(&hdr->dst); /* check if local ip mac in cache */ 00137 if (!a4) { 00138 if (++f->failure_count < 4) { 00139 dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count); 00140 /* check if dst is local (gateway = 0), or if to use gateway */ 00141 if (gateway.addr != 0) 00142 pico_arp_query(f->dev, &gateway); /* arp to gateway */ 00143 else 00144 pico_arp_query(f->dev, &hdr->dst); /* arp to dst */ 00145 00146 pico_enqueue(&pending, f); 00147 if (!pending_timer_on) { 00148 pending_timer_on++; 00149 pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL); 00150 } 00151 } else { 00152 dbg("ARP: Destination Unreachable\n"); 00153 pico_notify_dest_unreachable(f); 00154 pico_frame_discard(f); 00155 } 00156 } 00157 return a4; 00158 } 00159 00160 #ifdef DEBUG_ARP 00161 void dbg_arp(void) 00162 { 00163 struct pico_arp *a; 00164 struct pico_tree_node * index; 00165 00166 pico_tree_foreach(index,&arp_tree) { 00167 a = index->keyValue; 00168 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] ); 00169 } 00170 } 00171 #endif 00172 00173 void arp_expire(unsigned long now, void *_stale) 00174 { 00175 struct pico_arp *stale = (struct pico_arp *) _stale; 00176 stale->arp_status = PICO_ARP_STATUS_STALE; 00177 arp_dbg("ARP: Setting arp_status to STALE\n"); 00178 pico_arp_query(stale->dev, &stale->ipv4); 00179 00180 } 00181 00182 void pico_arp_add_entry(struct pico_arp *entry) 00183 { 00184 entry->arp_status = PICO_ARP_STATUS_REACHABLE; 00185 entry->timestamp = PICO_TIME(); 00186 00187 pico_tree_insert(&arp_tree,entry); 00188 arp_dbg("ARP ## reachable.\n"); 00189 pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry); 00190 } 00191 00192 int pico_arp_create_entry(uint8_t* hwaddr, struct pico_ip4 ipv4, struct pico_device* dev) 00193 { 00194 struct pico_arp* arp = pico_zalloc(sizeof(struct pico_arp)); 00195 if(!arp){ 00196 pico_err = PICO_ERR_ENOMEM; 00197 return -1; 00198 } 00199 memcpy(arp->eth.addr, hwaddr, 6); 00200 arp->ipv4.addr = ipv4.addr; 00201 arp->dev = dev; 00202 00203 pico_arp_add_entry(arp); 00204 00205 return 0; 00206 } 00207 00208 int pico_arp_receive(struct pico_frame *f) 00209 { 00210 struct pico_arp_hdr *hdr; 00211 struct pico_arp search, *found, *new = NULL; 00212 int ret = -1; 00213 hdr = (struct pico_arp_hdr *) f->net_hdr; 00214 00215 if (!hdr) 00216 goto end; 00217 00218 00219 /* Populate a new arp entry */ 00220 search.ipv4.addr = hdr->src.addr; 00221 memcpy(search.eth.addr, hdr->s_mac, PICO_SIZE_ETH); 00222 00223 /* Search for already existing entry */ 00224 00225 found = pico_tree_findKey(&arp_tree,&search); 00226 if (!found) { 00227 new = pico_zalloc(sizeof(struct pico_arp)); 00228 if (!new) 00229 goto end; 00230 new->ipv4.addr = hdr->src.addr; 00231 } 00232 else if (found->arp_status == PICO_ARP_STATUS_STALE) { 00233 /* Replace if stale */ 00234 new = found; 00235 00236 pico_tree_delete(&arp_tree,new); 00237 } 00238 00239 ret = 0; 00240 00241 if (new) { 00242 memcpy(new->eth.addr, hdr->s_mac, PICO_SIZE_ETH); 00243 new->dev = f->dev; 00244 pico_arp_add_entry(new); 00245 } 00246 00247 if (hdr->opcode == PICO_ARP_REQUEST) { 00248 struct pico_ip4 me; 00249 struct pico_eth_hdr *eh = (struct pico_eth_hdr *)f->datalink_hdr; 00250 struct pico_device *link_dev; 00251 me.addr = hdr->dst.addr; 00252 00253 link_dev = pico_ipv4_link_find(&me); 00254 if (link_dev != f->dev) 00255 goto end; 00256 00257 hdr->opcode = PICO_ARP_REPLY; 00258 memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH); 00259 memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH); 00260 hdr->dst.addr = hdr->src.addr; 00261 hdr->src.addr = me.addr; 00262 00263 /* Prepare eth header for arp reply */ 00264 memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH); 00265 memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); 00266 f->start = f->datalink_hdr; 00267 f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR; 00268 f->dev->send(f->dev, f->start, f->len); 00269 } 00270 00271 #ifdef DEBUG_ARG 00272 dbg_arp(); 00273 #endif 00274 00275 end: 00276 pico_frame_discard(f); 00277 return ret; 00278 } 00279 00280 int pico_arp_query(struct pico_device *dev, struct pico_ip4 *dst) 00281 { 00282 struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR); 00283 struct pico_eth_hdr *eh; 00284 struct pico_arp_hdr *ah; 00285 struct pico_ip4 *src; 00286 int ret; 00287 00288 src = pico_ipv4_source_find(dst); 00289 if (!src) 00290 return -1; 00291 00292 arp_dbg("QUERY: %08x\n", dst->addr); 00293 00294 if (!q) 00295 return -1; 00296 eh = (struct pico_eth_hdr *)q->start; 00297 ah = (struct pico_arp_hdr *) (q->start + PICO_SIZE_ETHHDR); 00298 00299 /* Fill eth header */ 00300 memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH); 00301 memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH); 00302 eh->proto = PICO_IDETH_ARP; 00303 00304 /* Fill arp header */ 00305 ah->htype = PICO_ARP_HTYPE_ETH; 00306 ah->ptype = PICO_IDETH_IPV4; 00307 ah->hsize = PICO_SIZE_ETH; 00308 ah->psize = PICO_SIZE_IP4; 00309 ah->opcode = PICO_ARP_REQUEST; 00310 memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH); 00311 ah->src.addr = src->addr; 00312 ah->dst.addr = dst->addr; 00313 arp_dbg("Sending arp query.\n"); 00314 ret = dev->send(dev, q->start, q->len); 00315 pico_frame_discard(q); 00316 return ret; 00317 }
Generated on Thu Jul 14 2022 08:24:58 by
1.7.2
