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_device.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 #include "pico_config.h" 00011 #include "pico_device.h" 00012 #include "pico_stack.h" 00013 #include "pico_protocol.h" 00014 #include "pico_tree.h" 00015 #include "pico_ipv6.h" 00016 #include "pico_ipv4.h" 00017 #include "pico_icmp6.h" 00018 #include "pico_eth.h" 00019 #define PICO_DEVICE_DEFAULT_MTU (1500) 00020 00021 struct pico_devices_rr_info { 00022 struct pico_tree_node *node_in, *node_out; 00023 }; 00024 00025 static struct pico_devices_rr_info Devices_rr_info = { 00026 NULL, NULL 00027 }; 00028 00029 static int pico_dev_cmp(void *ka, void *kb) 00030 { 00031 struct pico_device *a = ka, *b = kb; 00032 if (a->hash < b->hash) 00033 return -1; 00034 00035 if (a->hash > b->hash) 00036 return 1; 00037 00038 return 0; 00039 } 00040 00041 PICO_TREE_DECLARE(Device_tree, pico_dev_cmp); 00042 00043 #ifdef PICO_SUPPORT_IPV6 00044 static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *linklocal) 00045 { 00046 dev->hostvars.basetime = PICO_ND_REACHABLE_TIME; 00047 /* RFC 4861 $6.3.2 value between 0.5 and 1.5 times basetime */ 00048 dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * PICO_ND_REACHABLE_TIME) / 10; 00049 dev->hostvars.retranstime = PICO_ND_RETRANS_TIMER; 00050 pico_icmp6_router_solicitation(dev, linklocal); 00051 dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP; 00052 } 00053 00054 struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix) 00055 { 00056 struct pico_ip6 newaddr; 00057 struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; 00058 struct pico_ipv6_link *link; 00059 memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6); 00060 /* modified EUI-64 + invert universal/local bit */ 00061 newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02); 00062 newaddr.addr[9] = dev->eth->mac.addr[1]; 00063 newaddr.addr[10] = dev->eth->mac.addr[2]; 00064 newaddr.addr[11] = 0xff; 00065 newaddr.addr[12] = 0xfe; 00066 newaddr.addr[13] = dev->eth->mac.addr[3]; 00067 newaddr.addr[14] = dev->eth->mac.addr[4]; 00068 newaddr.addr[15] = dev->eth->mac.addr[5]; 00069 link = pico_ipv6_link_add(dev, newaddr, netmask64); 00070 if (link) { 00071 device_init_ipv6_final(dev, &newaddr); 00072 } 00073 00074 return link; 00075 } 00076 #endif 00077 00078 static int device_init_mac(struct pico_device *dev, uint8_t *mac) 00079 { 00080 #ifdef PICO_SUPPORT_IPV6 00081 struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}}; 00082 #endif 00083 dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev)); 00084 if (dev->eth) { 00085 memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH); 00086 #ifdef PICO_SUPPORT_IPV6 00087 if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) { 00088 PICO_FREE(dev->q_in); 00089 PICO_FREE(dev->q_out); 00090 PICO_FREE(dev->eth); 00091 return -1; 00092 } 00093 00094 #endif 00095 } else { 00096 pico_err = PICO_ERR_ENOMEM; 00097 return -1; 00098 } 00099 00100 return 0; 00101 } 00102 00103 int pico_device_ipv6_random_ll(struct pico_device *dev) 00104 { 00105 #ifdef PICO_SUPPORT_IPV6 00106 struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}}; 00107 struct pico_ip6 netmask6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; 00108 uint32_t len = (uint32_t)strlen(dev->name); 00109 if (strcmp(dev->name, "loop")) { 00110 do { 00111 /* privacy extension + unset universal/local and individual/group bit */ 00112 len = pico_rand(); 00113 linklocal.addr[8] = (uint8_t)((len & 0xffu) & (uint8_t)(~0x03)); 00114 linklocal.addr[9] = (uint8_t)(len >> 8); 00115 linklocal.addr[10] = (uint8_t)(len >> 16); 00116 linklocal.addr[11] = (uint8_t)(len >> 24); 00117 len = pico_rand(); 00118 linklocal.addr[12] = (uint8_t)len; 00119 linklocal.addr[13] = (uint8_t)(len >> 8); 00120 linklocal.addr[14] = (uint8_t)(len >> 16); 00121 linklocal.addr[15] = (uint8_t)(len >> 24); 00122 pico_rand_feed(dev->hash); 00123 } while (pico_ipv6_link_get(&linklocal)); 00124 00125 if (pico_ipv6_link_add(dev, linklocal, netmask6) == NULL) { 00126 return -1; 00127 } 00128 } 00129 00130 #endif 00131 return 0; 00132 } 00133 00134 static int device_init_nomac(struct pico_device *dev) 00135 { 00136 if (pico_device_ipv6_random_ll(dev) < 0) { 00137 PICO_FREE(dev->q_in); 00138 PICO_FREE(dev->q_out); 00139 return -1; 00140 } 00141 00142 dev->eth = NULL; 00143 return 0; 00144 } 00145 00146 int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac) 00147 { 00148 00149 uint32_t len = (uint32_t)strlen(name); 00150 int ret = 0; 00151 if(len > MAX_DEVICE_NAME) 00152 len = MAX_DEVICE_NAME; 00153 00154 memcpy(dev->name, name, len); 00155 dev->hash = pico_hash(dev->name, len); 00156 00157 Devices_rr_info.node_in = NULL; 00158 Devices_rr_info.node_out = NULL; 00159 dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue)); 00160 if (!dev->q_in) 00161 return -1; 00162 00163 dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue)); 00164 if (!dev->q_out) { 00165 PICO_FREE(dev->q_in); 00166 return -1; 00167 } 00168 00169 pico_tree_insert(&Device_tree, dev); 00170 if (!dev->mtu) 00171 dev->mtu = PICO_DEVICE_DEFAULT_MTU; 00172 00173 if (mac) { 00174 ret = device_init_mac(dev, mac); 00175 } else { 00176 ret = device_init_nomac(dev); 00177 } 00178 00179 return ret; 00180 } 00181 00182 static void pico_queue_destroy(struct pico_queue *q) 00183 { 00184 if (q) { 00185 pico_queue_empty(q); 00186 PICO_FREE(q); 00187 } 00188 } 00189 00190 void pico_device_destroy(struct pico_device *dev) 00191 { 00192 if (dev->destroy) 00193 dev->destroy(dev); 00194 00195 pico_queue_destroy(dev->q_in); 00196 pico_queue_destroy(dev->q_out); 00197 00198 if (dev->eth) 00199 PICO_FREE(dev->eth); 00200 00201 #ifdef PICO_SUPPORT_IPV4 00202 pico_ipv4_cleanup_links(dev); 00203 #endif 00204 #ifdef PICO_SUPPORT_IPV6 00205 pico_ipv6_cleanup_links(dev); 00206 #endif 00207 pico_tree_delete(&Device_tree, dev); 00208 00209 Devices_rr_info.node_in = NULL; 00210 Devices_rr_info.node_out = NULL; 00211 PICO_FREE(dev); 00212 } 00213 00214 static int check_dev_serve_interrupt(struct pico_device *dev, int loop_score) 00215 { 00216 if ((dev->__serving_interrupt) && (dev->dsr)) { 00217 /* call dsr routine */ 00218 loop_score = dev->dsr(dev, loop_score); 00219 } 00220 00221 return loop_score; 00222 } 00223 00224 static int check_dev_serve_polling(struct pico_device *dev, int loop_score) 00225 { 00226 if (dev->poll) { 00227 loop_score = dev->poll(dev, loop_score); 00228 } 00229 00230 return loop_score; 00231 } 00232 00233 static int devloop_in(struct pico_device *dev, int loop_score) 00234 { 00235 struct pico_frame *f; 00236 while(loop_score > 0) { 00237 if (dev->q_in->frames == 0) 00238 break; 00239 00240 /* Receive */ 00241 f = pico_dequeue(dev->q_in); 00242 if (f) { 00243 if (dev->eth) { 00244 f->datalink_hdr = f->buffer; 00245 (void)pico_ethernet_receive(f); 00246 } else { 00247 f->net_hdr = f->buffer; 00248 pico_network_receive(f); 00249 } 00250 00251 loop_score--; 00252 } 00253 } 00254 return loop_score; 00255 } 00256 00257 static int devloop_sendto_dev(struct pico_device *dev, struct pico_frame *f) 00258 { 00259 00260 if (dev->eth) { 00261 /* Ethernet: pass management of the frame to the pico_ethernet_send() rdv function */ 00262 return pico_ethernet_send(f); 00263 } else { 00264 /* non-ethernet: no post-processing needed */ 00265 return (dev->send(dev, f->start, (int)f->len) <= 0); /* Return 0 upon success, which is dev->send() > 0 */ 00266 } 00267 } 00268 00269 static int devloop_out(struct pico_device *dev, int loop_score) 00270 { 00271 struct pico_frame *f; 00272 while(loop_score > 0) { 00273 if (dev->q_out->frames == 0) 00274 break; 00275 00276 /* Device dequeue + send */ 00277 f = pico_queue_peek(dev->q_out); 00278 if (!f) 00279 break; 00280 00281 if (devloop_sendto_dev(dev, f) == 0) { /* success. */ 00282 f = pico_dequeue(dev->q_out); 00283 pico_frame_discard(f); /* SINGLE POINT OF DISCARD for OUTGOING FRAMES */ 00284 loop_score--; 00285 } else 00286 break; /* Don't discard */ 00287 00288 } 00289 return loop_score; 00290 } 00291 00292 static int devloop(struct pico_device *dev, int loop_score, int direction) 00293 { 00294 /* If device supports interrupts, read the value of the condition and trigger the dsr */ 00295 loop_score = check_dev_serve_interrupt(dev, loop_score); 00296 00297 /* If device supports polling, give control. Loop score is managed internally, 00298 * remaining loop points are returned. */ 00299 loop_score = check_dev_serve_polling(dev, loop_score); 00300 00301 if (direction == PICO_LOOP_DIR_OUT) 00302 loop_score = devloop_out(dev, loop_score); 00303 else 00304 loop_score = devloop_in(dev, loop_score); 00305 00306 return loop_score; 00307 } 00308 00309 00310 static struct pico_tree_node *pico_dev_roundrobin_start(int direction) 00311 { 00312 if (Devices_rr_info.node_in == NULL) 00313 Devices_rr_info.node_in = pico_tree_firstNode(Device_tree.root); 00314 00315 if (Devices_rr_info.node_out == NULL) 00316 Devices_rr_info.node_out = pico_tree_firstNode(Device_tree.root); 00317 00318 if (direction == PICO_LOOP_DIR_IN) 00319 return Devices_rr_info.node_in; 00320 else 00321 return Devices_rr_info.node_out; 00322 } 00323 00324 static void pico_dev_roundrobin_end(int direction, struct pico_tree_node *last) 00325 { 00326 if (direction == PICO_LOOP_DIR_IN) 00327 Devices_rr_info.node_in = last; 00328 else 00329 Devices_rr_info.node_out = last; 00330 } 00331 00332 #define DEV_LOOP_MIN 16 00333 00334 int pico_devices_loop(int loop_score, int direction) 00335 { 00336 struct pico_device *start, *next; 00337 struct pico_tree_node *next_node = pico_dev_roundrobin_start(direction); 00338 00339 if (!next_node) 00340 return loop_score; 00341 00342 next = next_node->keyValue; 00343 start = next; 00344 00345 /* round-robin all devices, break if traversed all devices */ 00346 while ((loop_score > DEV_LOOP_MIN) && (next != NULL)) { 00347 loop_score = devloop(next, loop_score, direction); 00348 next_node = pico_tree_next(next_node); 00349 next = next_node->keyValue; 00350 if (next == NULL) 00351 { 00352 next_node = pico_tree_firstNode(Device_tree.root); 00353 next = next_node->keyValue; 00354 } 00355 00356 if (next == start) 00357 break; 00358 } 00359 pico_dev_roundrobin_end(direction, next_node); 00360 return loop_score; 00361 } 00362 00363 struct pico_device *pico_get_device(const char*name) 00364 { 00365 struct pico_device *dev; 00366 struct pico_tree_node *index; 00367 pico_tree_foreach(index, &Device_tree){ 00368 dev = index->keyValue; 00369 if(strcmp(name, dev->name) == 0) 00370 return dev; 00371 } 00372 return NULL; 00373 } 00374 00375 int32_t pico_device_broadcast(struct pico_frame *f) 00376 { 00377 struct pico_tree_node *index; 00378 int32_t ret = -1; 00379 00380 pico_tree_foreach(index, &Device_tree) 00381 { 00382 struct pico_device *dev = index->keyValue; 00383 if(dev != f->dev) 00384 { 00385 struct pico_frame *copy = pico_frame_copy(f); 00386 00387 if(!copy) 00388 break; 00389 00390 copy->dev = dev; 00391 copy->dev->send(copy->dev, copy->start, (int)copy->len); 00392 pico_frame_discard(copy); 00393 } 00394 else 00395 { 00396 ret = f->dev->send(f->dev, f->start, (int)f->len); 00397 } 00398 } 00399 return ret; 00400 } 00401 00402 int pico_device_link_state(struct pico_device *dev) 00403 { 00404 if (!dev->link_state) 00405 return 1; /* Not supported, assuming link is always up */ 00406 00407 return dev->link_state(dev); 00408 }
Generated on Tue Jul 12 2022 15:59:21 by 1.7.2