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_ipv4.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 Authors: Daniele Lacamera, Markian Yskout 00006 *********************************************************************/ 00007 00008 00009 #include "pico_config.h" 00010 #include "pico_ipfilter.h" 00011 #include "pico_ipv4.h" 00012 #include "pico_icmp4.h" 00013 #include "pico_stack.h" 00014 #include "pico_eth.h" 00015 #include "pico_udp.h" 00016 #include "pico_tcp.h" 00017 #include "pico_socket.h" 00018 #include "pico_device.h" 00019 #include "pico_nat.h" 00020 #include "pico_igmp.h" 00021 #include "pico_tree.h" 00022 #include "pico_aodv.h" 00023 #include "pico_socket_multicast.h" 00024 #include "pico_fragments.h" 00025 00026 #ifdef PICO_SUPPORT_IPV4 00027 00028 #ifdef PICO_SUPPORT_MCAST 00029 # define ip_mcast_dbg(...) do {} while(0) /* so_mcast_dbg in pico_socket.c */ 00030 /* #define ip_mcast_dbg dbg */ 00031 # define PICO_MCAST_ALL_HOSTS long_be(0xE0000001) /* 224.0.0.1 */ 00032 /* Default network interface for multicast transmission */ 00033 static struct pico_ipv4_link *mcast_default_link = NULL; 00034 #endif 00035 #ifdef PICO_SUPPORT_IPV4FRAG 00036 /* # define reassembly_dbg dbg */ 00037 # define reassembly_dbg(...) do {} while(0) 00038 #endif 00039 00040 /* Queues */ 00041 static struct pico_queue in = { 00042 0 00043 }; 00044 static struct pico_queue out = { 00045 0 00046 }; 00047 00048 /* Functions */ 00049 static int ipv4_route_compare(void *ka, void *kb); 00050 static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size); 00051 00052 00053 int pico_ipv4_compare(struct pico_ip4 *a, struct pico_ip4 *b) 00054 { 00055 if (a->addr < b->addr) 00056 return -1; 00057 00058 if (a->addr > b->addr) 00059 return 1; 00060 00061 return 0; 00062 } 00063 00064 int pico_ipv4_to_string(char *ipbuf, const uint32_t ip) 00065 { 00066 const unsigned char *addr = (const unsigned char *) &ip; 00067 int i; 00068 00069 if (!ipbuf) { 00070 pico_err = PICO_ERR_EINVAL; 00071 return -1; 00072 } 00073 00074 for(i = 0; i < 4; i++) 00075 { 00076 if (addr[i] > 99) { 00077 *ipbuf++ = (char)('0' + (addr[i] / 100)); 00078 *ipbuf++ = (char)('0' + ((addr[i] % 100) / 10)); 00079 *ipbuf++ = (char)('0' + ((addr[i] % 100) % 10)); 00080 } else if (addr[i] > 9) { 00081 *ipbuf++ = (char)('0' + (addr[i] / 10)); 00082 *ipbuf++ = (char)('0' + (addr[i] % 10)); 00083 } else { 00084 *ipbuf++ = (char)('0' + addr[i]); 00085 } 00086 00087 if (i < 3) 00088 *ipbuf++ = '.'; 00089 } 00090 *ipbuf = '\0'; 00091 00092 return 0; 00093 } 00094 00095 static int pico_string_check_null_args(const char *ipstr, uint32_t *ip) 00096 { 00097 00098 if (!ipstr || !ip) { 00099 pico_err = PICO_ERR_EINVAL; 00100 return -1; 00101 } 00102 00103 return 0; 00104 00105 } 00106 00107 int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) 00108 { 00109 unsigned char buf[PICO_SIZE_IP4] = { 00110 0 00111 }; 00112 int cnt = 0; 00113 char p; 00114 00115 if (pico_string_check_null_args(ipstr, ip) < 0) 00116 return -1; 00117 00118 while((p = *ipstr++) != 0 && cnt < PICO_SIZE_IP4) 00119 { 00120 if (pico_is_digit(p)) { 00121 buf[cnt] = (uint8_t)((10 * buf[cnt]) + (p - '0')); 00122 } else if (p == '.') { 00123 cnt++; 00124 } else { 00125 return -1; 00126 } 00127 } 00128 /* Handle short notation */ 00129 if (cnt == 1) { 00130 buf[3] = buf[1]; 00131 buf[1] = 0; 00132 buf[2] = 0; 00133 } else if (cnt == 2) { 00134 buf[3] = buf[2]; 00135 buf[2] = 0; 00136 } else if (cnt != 3) { 00137 /* String could not be parsed, return error */ 00138 return -1; 00139 } 00140 00141 *ip = long_from(buf); 00142 00143 return 0; 00144 } 00145 00146 int pico_ipv4_valid_netmask(uint32_t mask) 00147 { 00148 int cnt = 0; 00149 int end = 0; 00150 int i; 00151 uint32_t mask_swap = long_be(mask); 00152 00153 /* 00154 * Swap bytes for convenient parsing 00155 * e.g. 0x..f8ff will become 0xfff8.. 00156 * Then, we count the consecutive bits 00157 * 00158 * */ 00159 00160 for(i = 0; i < 32; i++) { 00161 if ((mask_swap << i) & 0x80000000) { 00162 if (end) { 00163 pico_err = PICO_ERR_EINVAL; 00164 return -1; 00165 } 00166 00167 cnt++; 00168 } else { 00169 end = 1; 00170 } 00171 } 00172 return cnt; 00173 } 00174 00175 int pico_ipv4_is_unicast(uint32_t address) 00176 { 00177 const unsigned char *addr = (unsigned char *) &address; 00178 if ((addr[0] & 0xe0) == 0xe0) 00179 return 0; /* multicast */ 00180 00181 return 1; 00182 } 00183 00184 int pico_ipv4_is_multicast(uint32_t address) 00185 { 00186 const unsigned char *addr = (unsigned char *) &address; 00187 if ((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0)) 00188 return 1; /* multicast */ 00189 00190 return 0; 00191 } 00192 00193 int pico_ipv4_is_loopback(uint32_t address) 00194 { 00195 const unsigned char *addr = (unsigned char *) &address; 00196 if (addr[0] == 0x7f) 00197 return 1; 00198 00199 return 0; 00200 } 00201 00202 static int pico_ipv4_is_invalid_loopback(uint32_t address, struct pico_device *dev) 00203 { 00204 return pico_ipv4_is_loopback(address) && ((!dev) || strcmp(dev->name, "loop")); 00205 } 00206 00207 int pico_ipv4_is_valid_src(uint32_t address, struct pico_device *dev) 00208 { 00209 if (pico_ipv4_is_broadcast(address)) { 00210 dbg("Source is a broadcast address, discard packet\n"); 00211 return 0; 00212 } else if ( pico_ipv4_is_multicast(address)) { 00213 dbg("Source is a multicast address, discard packet\n"); 00214 return 0; 00215 } else if (pico_ipv4_is_invalid_loopback(address, dev)) { 00216 dbg("Source is a loopback address, discard packet\n"); 00217 return 0; 00218 } else { 00219 #ifdef PICO_SUPPORT_AODV 00220 union pico_address src; 00221 src.ip4.addr = address; 00222 pico_aodv_refresh(&src); 00223 #endif 00224 return 1; 00225 } 00226 } 00227 00228 static int pico_ipv4_checksum(struct pico_frame *f) 00229 { 00230 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00231 if (!hdr) 00232 return -1; 00233 00234 hdr->crc = 0; 00235 hdr->crc = short_be(pico_checksum(hdr, f->net_len)); 00236 return 0; 00237 } 00238 00239 00240 #ifdef PICO_SUPPORT_CRC 00241 static inline int pico_ipv4_crc_check(struct pico_frame *f) 00242 { 00243 uint16_t checksum_invalid = 1; 00244 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00245 00246 checksum_invalid = short_be(pico_checksum(hdr, f->net_len)); 00247 if (checksum_invalid) { 00248 dbg("IP: checksum failed!\n"); 00249 pico_frame_discard(f); 00250 return 0; 00251 } 00252 00253 return 1; 00254 } 00255 #else 00256 static inline int pico_ipv4_crc_check(struct pico_frame *f) 00257 { 00258 IGNORE_PARAMETER(f); 00259 return 1; 00260 } 00261 #endif /* PICO_SUPPORT_CRC */ 00262 00263 static int pico_ipv4_forward(struct pico_frame *f); 00264 #ifdef PICO_SUPPORT_MCAST 00265 static int pico_ipv4_mcast_filter(struct pico_frame *f); 00266 #endif 00267 00268 static int ipv4_link_compare(void *ka, void *kb) 00269 { 00270 struct pico_ipv4_link *a = ka, *b = kb; 00271 int cmp = pico_ipv4_compare(&a->address, &b->address); 00272 if (cmp) 00273 return cmp; 00274 00275 /* zero can be assigned multiple times (e.g. for DHCP) */ 00276 if (a->dev != NULL && b->dev != NULL && a->address.addr == PICO_IP4_ANY && b->address.addr == PICO_IP4_ANY) { 00277 if (a->dev < b->dev) 00278 return -1; 00279 00280 if (a->dev > b->dev) 00281 return 1; 00282 } 00283 00284 return 0; 00285 } 00286 00287 PICO_TREE_DECLARE(Tree_dev_link, ipv4_link_compare); 00288 00289 static int pico_ipv4_process_bcast_in(struct pico_frame *f) 00290 { 00291 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00292 #ifdef PICO_SUPPORT_UDP 00293 if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) { 00294 /* Receiving UDP broadcast datagram */ 00295 f->flags |= PICO_FRAME_FLAG_BCAST; 00296 pico_enqueue(pico_proto_udp.q_in, f); 00297 return 1; 00298 } 00299 00300 #endif 00301 00302 #ifdef PICO_SUPPORT_ICMP4 00303 if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_ICMP4)) { 00304 /* Receiving ICMP4 bcast packet */ 00305 f->flags |= PICO_FRAME_FLAG_BCAST; 00306 pico_enqueue(pico_proto_icmp4.q_in, f); 00307 return 1; 00308 } 00309 00310 #endif 00311 return 0; 00312 } 00313 00314 static int pico_ipv4_process_mcast_in(struct pico_frame *f) 00315 { 00316 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00317 if (pico_ipv4_is_multicast(hdr->dst.addr)) { 00318 #ifdef PICO_SUPPORT_IGMP 00319 /* Receiving UDP multicast datagram TODO set f->flags? */ 00320 if (hdr->proto == PICO_PROTO_IGMP) { 00321 ip_mcast_dbg("MCAST: received IGMP message\n"); 00322 pico_transport_receive(f, PICO_PROTO_IGMP); 00323 return 1; 00324 } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) { 00325 pico_enqueue(pico_proto_udp.q_in, f); 00326 return 1; 00327 } 00328 00329 #endif 00330 pico_frame_discard(f); 00331 return 1; 00332 } 00333 00334 return 0; 00335 } 00336 00337 static int pico_ipv4_process_local_unicast_in(struct pico_frame *f) 00338 { 00339 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00340 struct pico_ipv4_link test = { 00341 .address = {.addr = PICO_IP4_ANY}, .dev = NULL 00342 }; 00343 if (pico_ipv4_link_find(&hdr->dst)) { 00344 if (pico_ipv4_nat_inbound(f, &hdr->dst) == 0) 00345 pico_enqueue(pico_proto_ipv4.q_in, f); /* dst changed, reprocess */ 00346 else 00347 pico_transport_receive(f, hdr->proto); 00348 00349 return 1; 00350 } else if (pico_tree_findKey(&Tree_dev_link, &test)) { 00351 #ifdef PICO_SUPPORT_UDP 00352 /* address of this device is apparently 0.0.0.0; might be a DHCP packet */ 00353 /* XXX KRO: is obsolete. Broadcast flag is set on outgoing DHCP messages. 00354 * incomming DHCP messages are to be broadcasted. Our current DHCP server 00355 * implementation does not take this flag into account yet though ... */ 00356 pico_enqueue(pico_proto_udp.q_in, f); 00357 return 1; 00358 #endif 00359 } 00360 00361 return 0; 00362 } 00363 00364 static void pico_ipv4_process_finally_try_forward(struct pico_frame *f) 00365 { 00366 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00367 if ((pico_ipv4_is_broadcast(hdr->dst.addr)) || ((f->flags & PICO_FRAME_FLAG_BCAST)!= 0)) { 00368 /* don't forward broadcast frame, discard! */ 00369 pico_frame_discard(f); 00370 } else if (pico_ipv4_forward(f) != 0) { 00371 pico_frame_discard(f); 00372 /* dbg("Forward failed.\n"); */ 00373 } 00374 } 00375 00376 00377 00378 static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f) 00379 { 00380 uint8_t option_len = 0; 00381 int ret = 0; 00382 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00383 uint16_t max_allowed = (uint16_t) ((int)f->buffer_len - (f->net_hdr - f->buffer) - (int)PICO_SIZE_IP4HDR); 00384 uint16_t flag = short_be(hdr->frag); 00385 00386 (void)self; 00387 /* NAT needs transport header information */ 00388 if (((hdr->vhl) & 0x0F) > 5) { 00389 option_len = (uint8_t)(4 * (((hdr->vhl) & 0x0F) - 5)); 00390 } 00391 00392 f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR + option_len; 00393 f->transport_len = (uint16_t)(short_be(hdr->len) - PICO_SIZE_IP4HDR - option_len); 00394 f->net_len = (uint16_t)(PICO_SIZE_IP4HDR + option_len); 00395 00396 if (f->transport_len > max_allowed) { 00397 pico_frame_discard(f); 00398 return 0; /* Packet is discarded due to unfeasible length */ 00399 } 00400 00401 #ifdef PICO_SUPPORT_IPFILTER 00402 if (ipfilter(f)) { 00403 /*pico_frame is discarded as result of the filtering*/ 00404 return 0; 00405 } 00406 00407 #endif 00408 00409 00410 /* ret == 1 indicates to continue the function */ 00411 ret = pico_ipv4_crc_check(f); 00412 if (ret < 1) 00413 return ret; 00414 00415 /* Validate source IP address. Discard quietly if invalid */ 00416 if (!pico_ipv4_is_valid_src(hdr->src.addr, f->dev)) { 00417 pico_frame_discard(f); 00418 return 0; 00419 } 00420 00421 if (hdr->frag & short_be(PICO_IPV4_EVIL)) { 00422 (void)pico_icmp4_param_problem(f, 0); 00423 pico_frame_discard(f); /* RFC 3514 */ 00424 return 0; 00425 } 00426 00427 if ((hdr->vhl & 0x0f) < 5) { 00428 /* RFC 791: IHL minimum value is 5 */ 00429 (void)pico_icmp4_param_problem(f, 0); 00430 pico_frame_discard(f); 00431 return 0; 00432 } 00433 00434 if (flag & (PICO_IPV4_MOREFRAG | PICO_IPV4_FRAG_MASK)) 00435 { 00436 #ifdef PICO_SUPPORT_IPV4FRAG 00437 pico_ipv4_process_frag(hdr, f, hdr ? hdr->proto : 0 ); 00438 /* Frame can be discarded, frag will handle its own copy */ 00439 #endif 00440 /* We do not support fragmentation, discard quietly */ 00441 pico_frame_discard(f); 00442 return 0; 00443 } 00444 00445 if (pico_ipv4_process_bcast_in(f) > 0) 00446 return 0; 00447 00448 if (pico_ipv4_process_mcast_in(f) > 0) 00449 return 0; 00450 00451 if (pico_ipv4_process_local_unicast_in(f) > 0) 00452 return 0; 00453 00454 pico_ipv4_process_finally_try_forward(f); 00455 00456 return 0; 00457 } 00458 00459 PICO_TREE_DECLARE(Routes, ipv4_route_compare); 00460 00461 00462 static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f) 00463 { 00464 IGNORE_PARAMETER(self); 00465 f->start = (uint8_t*) f->net_hdr; 00466 #ifdef PICO_SUPPORT_IPFILTER 00467 if (ipfilter(f)) { 00468 /*pico_frame is discarded as result of the filtering*/ 00469 return 0; 00470 } 00471 00472 #endif 00473 return pico_sendto_dev(f); 00474 } 00475 00476 00477 static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size) 00478 { 00479 struct pico_frame *f = pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR); 00480 IGNORE_PARAMETER(self); 00481 00482 if (!f) 00483 return NULL; 00484 00485 f->datalink_hdr = f->buffer; 00486 f->net_hdr = f->buffer + PICO_SIZE_ETHHDR; 00487 f->net_len = PICO_SIZE_IP4HDR; 00488 f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR; 00489 f->transport_len = size; 00490 f->len = size + PICO_SIZE_IP4HDR; 00491 return f; 00492 } 00493 00494 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f); 00495 00496 /* Interface: protocol definition */ 00497 struct pico_protocol pico_proto_ipv4 = { 00498 .name = "ipv4", 00499 .proto_number = PICO_PROTO_IPV4, 00500 .layer = PICO_LAYER_NETWORK, 00501 .alloc = pico_ipv4_alloc, 00502 .process_in = pico_ipv4_process_in, 00503 .process_out = pico_ipv4_process_out, 00504 .push = pico_ipv4_frame_sock_push, 00505 .q_in = &in, 00506 .q_out = &out, 00507 }; 00508 00509 00510 static int ipv4_route_compare(void *ka, void *kb) 00511 { 00512 struct pico_ipv4_route *a = ka, *b = kb; 00513 uint32_t a_nm, b_nm; 00514 int cmp; 00515 00516 a_nm = long_be(a->netmask.addr); 00517 b_nm = long_be(b->netmask.addr); 00518 00519 /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */ 00520 if (a_nm < b_nm) 00521 return -1; 00522 00523 if (b_nm < a_nm) 00524 return 1; 00525 00526 cmp = pico_ipv4_compare(&a->dest, &b->dest); 00527 if (cmp) 00528 return cmp; 00529 00530 if (a->metric < b->metric) 00531 return -1; 00532 00533 if (a->metric > b->metric) 00534 return 1; 00535 00536 return 0; 00537 } 00538 00539 00540 static struct pico_ipv4_route default_bcast_route = { 00541 .dest = {PICO_IP4_BCAST}, 00542 .netmask = {PICO_IP4_BCAST}, 00543 .gateway = { 0 }, 00544 .link = NULL, 00545 .metric = 1000 00546 }; 00547 00548 static struct pico_ipv4_route *route_find_default_bcast(void) 00549 { 00550 return &default_bcast_route; 00551 } 00552 00553 00554 static struct pico_ipv4_route *route_find(const struct pico_ip4 *addr) 00555 { 00556 struct pico_ipv4_route *r; 00557 struct pico_tree_node *index; 00558 00559 if (addr->addr != PICO_IP4_BCAST) { 00560 pico_tree_foreach_reverse(index, &Routes) { 00561 r = index->keyValue; 00562 if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) { 00563 return r; 00564 } 00565 } 00566 return NULL; 00567 } 00568 00569 return route_find_default_bcast(); 00570 } 00571 00572 struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr) 00573 { 00574 struct pico_ip4 nullip; 00575 struct pico_ipv4_route *route; 00576 nullip.addr = 0U; 00577 00578 if (!addr) { 00579 pico_err = PICO_ERR_EINVAL; 00580 return nullip; 00581 } 00582 00583 route = route_find(addr); 00584 if (!route) { 00585 pico_err = PICO_ERR_EHOSTUNREACH; 00586 return nullip; 00587 } 00588 else 00589 return route->gateway; 00590 } 00591 00592 struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst) 00593 { 00594 struct pico_ip4 *myself = NULL; 00595 struct pico_ipv4_route *rt; 00596 #ifdef PICO_SUPPORT_AODV 00597 union pico_address node_address; 00598 node_address.ip4.addr = dst->addr; 00599 if (dst->addr && pico_ipv4_is_unicast(dst->addr)) 00600 pico_aodv_lookup(&node_address); 00601 00602 #endif 00603 00604 if (!dst) { 00605 pico_err = PICO_ERR_EINVAL; 00606 return NULL; 00607 } 00608 00609 rt = route_find(dst); 00610 if (rt && rt->link) { 00611 myself = &rt->link->address; 00612 } else { 00613 pico_err = PICO_ERR_EHOSTUNREACH; 00614 } 00615 00616 return myself; 00617 } 00618 00619 struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst) 00620 { 00621 struct pico_device *dev = NULL; 00622 struct pico_ipv4_route *rt; 00623 00624 if (!dst) { 00625 pico_err = PICO_ERR_EINVAL; 00626 return NULL; 00627 } 00628 00629 rt = route_find(dst); 00630 if (rt && rt->link) { 00631 dev = rt->link->dev; 00632 } else { 00633 pico_err = PICO_ERR_EHOSTUNREACH; 00634 } 00635 00636 return dev; 00637 } 00638 00639 00640 #ifdef PICO_SUPPORT_MCAST 00641 /* link 00642 * | 00643 * MCASTGroups 00644 * | | | 00645 * ------------ | ------------ 00646 * | | | 00647 * MCASTSources MCASTSources MCASTSources 00648 * | | | | | | | | | | | | 00649 * S S S S S S S S S S S S 00650 * 00651 * MCASTGroups: RBTree(mcast_group) 00652 * MCASTSources: RBTree(source) 00653 */ 00654 static int ipv4_mcast_groups_cmp(void *ka, void *kb) 00655 { 00656 struct pico_mcast_group *a = ka, *b = kb; 00657 return pico_ipv4_compare(&a->mcast_addr, &b->mcast_addr); 00658 } 00659 00660 static int ipv4_mcast_sources_cmp(void *ka, void *kb) 00661 { 00662 struct pico_ip4 *a = ka, *b = kb; 00663 return pico_ipv4_compare(a, b); 00664 } 00665 00666 static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link) 00667 { 00668 uint16_t i = 0; 00669 struct pico_mcast_group *g = NULL; 00670 struct pico_ip4 *source = NULL; 00671 struct pico_tree_node *index = NULL, *index2 = NULL; 00672 (void) source; 00673 00674 ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); 00675 ip_mcast_dbg("+ MULTICAST list interface %-16s +\n", mcast_link->dev->name); 00676 ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); 00677 ip_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n"); 00678 ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); 00679 00680 pico_tree_foreach(index, mcast_link->MCASTGroups) { 00681 g = index->keyValue; 00682 ip_mcast_dbg("+ %04d | %16s | %08X | %05u | %u | %8s +\n", i, mcast_link->dev->name, g->mcast_addr.addr, g->reference_count, g->filter_mode, ""); 00683 pico_tree_foreach(index2, &g->MCASTSources) { 00684 source = index2->keyValue; 00685 ip_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %08X +\n", "", "", "", "", "", source->addr); 00686 } 00687 i++; 00688 } 00689 ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); 00690 } 00691 00692 static int mcast_group_update(struct pico_mcast_group *g, struct pico_tree *MCASTFilter, uint8_t filter_mode) 00693 { 00694 struct pico_tree_node *index = NULL, *_tmp = NULL; 00695 struct pico_ip4 *source = NULL; 00696 /* cleanup filter */ 00697 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { 00698 source = index->keyValue; 00699 pico_tree_delete(&g->MCASTSources, source); 00700 PICO_FREE(source); 00701 } 00702 /* insert new filter */ 00703 if (MCASTFilter) { 00704 pico_tree_foreach(index, MCASTFilter) { 00705 if (index->keyValue) { 00706 source = PICO_ZALLOC(sizeof(struct pico_ip4)); 00707 if (!source) { 00708 pico_err = PICO_ERR_ENOMEM; 00709 return -1; 00710 } 00711 00712 source->addr = ((struct pico_ip4 *)index->keyValue)->addr; 00713 pico_tree_insert(&g->MCASTSources, source); 00714 } 00715 } 00716 } 00717 00718 g->filter_mode = filter_mode; 00719 return 0; 00720 } 00721 00722 int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) 00723 { 00724 struct pico_mcast_group *g = NULL, test = { 00725 0 00726 }; 00727 struct pico_ipv4_link *link = NULL; 00728 00729 if (mcast_link) 00730 link = pico_ipv4_link_get(mcast_link); 00731 00732 if (!link) 00733 link = mcast_default_link; 00734 00735 test.mcast_addr = *mcast_group; 00736 g = pico_tree_findKey(link->MCASTGroups, &test); 00737 if (g) { 00738 if (reference_count) 00739 g->reference_count++; 00740 00741 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); 00742 } else { 00743 g = PICO_ZALLOC(sizeof(struct pico_mcast_group)); 00744 if (!g) { 00745 pico_err = PICO_ERR_ENOMEM; 00746 return -1; 00747 } 00748 00749 /* "non-existent" state of filter mode INCLUDE and empty source list */ 00750 g->filter_mode = PICO_IP_MULTICAST_INCLUDE; 00751 g->reference_count = 1; 00752 g->mcast_addr = *mcast_group; 00753 g->MCASTSources.root = &LEAF; 00754 g->MCASTSources.compare = ipv4_mcast_sources_cmp; 00755 pico_tree_insert(link->MCASTGroups, g); 00756 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE); 00757 } 00758 00759 if (mcast_group_update(g, MCASTFilter, filter_mode) < 0) { 00760 dbg("Error in mcast_group update\n"); 00761 return -1; 00762 } 00763 00764 pico_ipv4_mcast_print_groups(link); 00765 return 0; 00766 } 00767 00768 int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) 00769 { 00770 00771 struct pico_mcast_group *g = NULL, test = { 00772 0 00773 }; 00774 struct pico_ipv4_link *link = NULL; 00775 struct pico_tree_node *index = NULL, *_tmp = NULL; 00776 struct pico_ip4 *source = NULL; 00777 00778 if (mcast_link) 00779 link = pico_ipv4_link_get(mcast_link); 00780 00781 if (!link) 00782 link = mcast_default_link; 00783 00784 test.mcast_addr = *mcast_group; 00785 g = pico_tree_findKey(link->MCASTGroups, &test); 00786 if (!g) { 00787 pico_err = PICO_ERR_EINVAL; 00788 return -1; 00789 } else { 00790 if (reference_count && (--(g->reference_count) < 1)) { 00791 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE); 00792 /* cleanup filter */ 00793 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { 00794 source = index->keyValue; 00795 pico_tree_delete(&g->MCASTSources, source); 00796 PICO_FREE(source); 00797 } 00798 pico_tree_delete(link->MCASTGroups, g); 00799 PICO_FREE(g); 00800 } else { 00801 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); 00802 if (mcast_group_update(g, MCASTFilter, filter_mode) < 0) 00803 return -1; 00804 } 00805 } 00806 00807 pico_ipv4_mcast_print_groups(link); 00808 return 0; 00809 } 00810 00811 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) 00812 { 00813 return mcast_default_link; 00814 } 00815 00816 static int pico_ipv4_mcast_filter(struct pico_frame *f) 00817 { 00818 struct pico_ipv4_link *link = NULL; 00819 struct pico_tree_node *index = NULL, *index2 = NULL; 00820 struct pico_mcast_group *g = NULL, test = { 00821 0 00822 }; 00823 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00824 00825 test.mcast_addr = hdr->dst; 00826 00827 pico_tree_foreach(index, &Tree_dev_link) { 00828 link = index->keyValue; 00829 g = pico_tree_findKey(link->MCASTGroups, &test); 00830 if (g) { 00831 if (f->dev == link->dev) { 00832 ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name); 00833 /* perform source filtering */ 00834 switch (g->filter_mode) { 00835 case PICO_IP_MULTICAST_INCLUDE: 00836 pico_tree_foreach(index2, &g->MCASTSources) { 00837 if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { 00838 ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr); 00839 return 0; 00840 } 00841 } 00842 ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr); 00843 return -1; 00844 00845 case PICO_IP_MULTICAST_EXCLUDE: 00846 pico_tree_foreach(index2, &g->MCASTSources) { 00847 if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { 00848 ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr); 00849 return -1; 00850 } 00851 } 00852 ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr); 00853 return 0; 00854 00855 default: 00856 return -1; 00857 } 00858 } else { 00859 ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name); 00860 } 00861 } else { 00862 ip_mcast_dbg("MCAST: IP %08X is not a group member of link %s\n", hdr->dst.addr, f->dev->name); 00863 } 00864 } 00865 return -1; 00866 } 00867 00868 #else 00869 00870 int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) 00871 { 00872 pico_err = PICO_ERR_EPROTONOSUPPORT; 00873 return -1; 00874 } 00875 00876 int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) 00877 { 00878 pico_err = PICO_ERR_EPROTONOSUPPORT; 00879 return -1; 00880 } 00881 00882 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) 00883 { 00884 pico_err = PICO_ERR_EPROTONOSUPPORT; 00885 return NULL; 00886 } 00887 #endif /* PICO_SUPPORT_MCAST */ 00888 00889 /* #define DEBUG_ROUTE */ 00890 #ifdef DEBUG_ROUTE 00891 void dbg_route(void) 00892 { 00893 struct pico_ipv4_route *r; 00894 struct pico_tree_node *index; 00895 int count_hosts = 0; 00896 dbg("==== ROUTING TABLE =====\n"); 00897 pico_tree_foreach(index, &Routes) { 00898 r = index->keyValue; 00899 dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric); 00900 if (r->netmask.addr == 0xFFFFFFFF) 00901 count_hosts++; 00902 } 00903 dbg("================ total HOST nodes: %d ======\n\n\n", count_hosts); 00904 } 00905 #else 00906 #define dbg_route() do { } while(0) 00907 #endif 00908 00909 int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto) 00910 { 00911 00912 struct pico_ipv4_route *route; 00913 struct pico_ipv4_link *link; 00914 struct pico_ipv4_hdr *hdr; 00915 uint8_t ttl = PICO_IPV4_DEFAULT_TTL; 00916 uint8_t vhl = 0x45; /* version 4, header length 20 */ 00917 static uint16_t ipv4_progressive_id = 0x91c0; 00918 #ifdef PICO_SUPPORT_MCAST 00919 struct pico_tree_node *index; 00920 #endif 00921 00922 if (!f || !dst) { 00923 pico_err = PICO_ERR_EINVAL; 00924 return -1; 00925 } 00926 00927 00928 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00929 if (!hdr) { 00930 dbg("IP header error\n"); 00931 pico_err = PICO_ERR_EINVAL; 00932 goto drop; 00933 } 00934 00935 if (dst->addr == 0) { 00936 dbg("IP destination addr error\n"); 00937 pico_err = PICO_ERR_EINVAL; 00938 goto drop; 00939 } 00940 00941 route = route_find(dst); 00942 if (!route) { 00943 /* dbg("Route to %08x not found.\n", long_be(dst->addr)); */ 00944 00945 00946 pico_err = PICO_ERR_EHOSTUNREACH; 00947 goto drop; 00948 } else { 00949 link = route->link; 00950 #ifdef PICO_SUPPORT_MCAST 00951 if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */ 00952 switch (proto) { 00953 case PICO_PROTO_UDP: 00954 if (pico_udp_get_mc_ttl(f->sock, &ttl) < 0) 00955 ttl = PICO_IP_DEFAULT_MULTICAST_TTL; 00956 00957 break; 00958 #ifdef PICO_SUPPORT_IGMP 00959 case PICO_PROTO_IGMP: 00960 vhl = 0x46; /* header length 24 */ 00961 ttl = 1; 00962 /* router alert (RFC 2113) */ 00963 hdr->options[0] = 0x94; 00964 hdr->options[1] = 0x04; 00965 hdr->options[2] = 0x00; 00966 hdr->options[3] = 0x00; 00967 if (f->dev && link->dev != f->dev) { /* default link is not requested link */ 00968 pico_tree_foreach(index, &Tree_dev_link) { 00969 link = index->keyValue; 00970 if (link->dev == f->dev) 00971 break; 00972 } 00973 } 00974 00975 break; 00976 #endif 00977 default: 00978 ttl = PICO_IPV4_DEFAULT_TTL; 00979 } 00980 } 00981 00982 #endif 00983 } 00984 00985 hdr->vhl = vhl; 00986 hdr->len = short_be((uint16_t)(f->transport_len + f->net_len)); 00987 if ((f->transport_hdr != f->payload) && 00988 #ifdef PICO_SUPPORT_IPV4FRAG 00989 ( (0 == (f->frag & PICO_IPV4_MOREFRAG)) || 00990 (0 == (f->frag & PICO_IPV4_FRAG_MASK)) ) 00991 && 00992 #endif 00993 1 ) 00994 ipv4_progressive_id++; 00995 00996 if (f->send_ttl > 0) { 00997 ttl = f->send_ttl; 00998 } 00999 01000 hdr->id = short_be(ipv4_progressive_id); 01001 hdr->dst.addr = dst->addr; 01002 hdr->src.addr = link->address.addr; 01003 hdr->ttl = ttl; 01004 hdr->tos = f->send_tos; 01005 hdr->proto = proto; 01006 hdr->frag = short_be(PICO_IPV4_DONTFRAG); 01007 01008 #ifdef PICO_SUPPORT_IPV4FRAG 01009 # ifdef PICO_SUPPORT_UDP 01010 if (proto == PICO_PROTO_UDP) { 01011 /* first fragment, can not use transport_len to calculate IP length */ 01012 if (f->transport_hdr != f->payload) 01013 hdr->len = short_be((uint16_t)(f->payload_len + sizeof(struct pico_udp_hdr) + f->net_len)); 01014 01015 /* set fragmentation flags and offset calculated in socket layer */ 01016 hdr->frag = short_be(f->frag); 01017 } 01018 01019 if (proto == PICO_PROTO_ICMP4) 01020 { 01021 hdr->frag = short_be(f->frag); 01022 } 01023 01024 # endif 01025 #endif /* PICO_SUPPORT_IPV4FRAG */ 01026 pico_ipv4_checksum(f); 01027 01028 if (f->sock && f->sock->dev) { 01029 /* if the socket has its device set, use that (currently used for DHCP) */ 01030 f->dev = f->sock->dev; 01031 } else { 01032 f->dev = link->dev; 01033 if (f->sock) 01034 f->sock->dev = f->dev; 01035 } 01036 01037 #ifdef PICO_SUPPORT_MCAST 01038 if (pico_ipv4_is_multicast(hdr->dst.addr)) { 01039 struct pico_frame *cpy; 01040 /* Sending UDP multicast datagram, am I member? If so, loopback copy */ 01041 if ((proto != PICO_PROTO_IGMP) && (pico_ipv4_mcast_filter(f) == 0)) { 01042 ip_mcast_dbg("MCAST: sender is member of group, loopback copy\n"); 01043 cpy = pico_frame_copy(f); 01044 pico_enqueue(&in, cpy); 01045 } 01046 } 01047 01048 #endif 01049 01050 /* #ifdef PICO_SUPPORT_AODV */ 01051 #if 0 01052 { 01053 union pico_address node_address; 01054 node_address.ip4.addr = hdr->dst.addr; 01055 if(hdr->dst.addr && pico_ipv4_is_unicast(hdr->dst.addr)) 01056 pico_aodv_lookup(&node_address); 01057 } 01058 #endif 01059 01060 if (pico_ipv4_link_get(&hdr->dst)) { 01061 /* it's our own IP */ 01062 return pico_enqueue(&in, f); 01063 } else{ 01064 /* TODO: Check if there are members subscribed here */ 01065 return pico_enqueue(&out, f); 01066 } 01067 01068 drop: 01069 pico_frame_discard(f); 01070 return -1; 01071 } 01072 01073 01074 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f) 01075 { 01076 struct pico_ip4 *dst; 01077 struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info; 01078 IGNORE_PARAMETER(self); 01079 01080 if (!f->sock) { 01081 pico_frame_discard(f); 01082 return -1; 01083 } 01084 01085 if (remote_endpoint) { 01086 dst = &remote_endpoint->remote_addr.ip4; 01087 } else { 01088 dst = &f->sock->remote_addr.ip4; 01089 } 01090 01091 return pico_ipv4_frame_push(f, dst, (uint8_t)f->sock->proto->proto_number); 01092 } 01093 01094 01095 int MOCKABLE pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) 01096 { 01097 struct pico_ipv4_route test, *new; 01098 test.dest.addr = address.addr; 01099 test.netmask.addr = netmask.addr; 01100 test.metric = (uint32_t)metric; 01101 01102 if (pico_tree_findKey(&Routes, &test)) { 01103 pico_err = PICO_ERR_EINVAL; 01104 return -1; 01105 } 01106 01107 new = PICO_ZALLOC(sizeof(struct pico_ipv4_route)); 01108 if (!new) { 01109 pico_err = PICO_ERR_ENOMEM; 01110 return -1; 01111 } 01112 01113 new->dest.addr = address.addr; 01114 new->netmask.addr = netmask.addr; 01115 new->gateway.addr = gateway.addr; 01116 new->metric = (uint32_t)metric; 01117 if (gateway.addr == 0) { 01118 /* No gateway provided, use the link */ 01119 new->link = link; 01120 } else { 01121 struct pico_ipv4_route *r = route_find(&gateway); 01122 if (!r ) { /* Specified Gateway is unreachable */ 01123 pico_err = PICO_ERR_EHOSTUNREACH; 01124 PICO_FREE(new); 01125 return -1; 01126 } 01127 01128 if (r->gateway.addr) { /* Specified Gateway is not a neighbor */ 01129 pico_err = PICO_ERR_ENETUNREACH; 01130 PICO_FREE(new); 01131 return -1; 01132 } 01133 01134 new->link = r->link; 01135 } 01136 01137 if (!new->link) { 01138 pico_err = PICO_ERR_EINVAL; 01139 PICO_FREE(new); 01140 return -1; 01141 } 01142 01143 pico_tree_insert(&Routes, new); 01144 dbg_route(); 01145 return 0; 01146 } 01147 01148 int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric) 01149 { 01150 struct pico_ipv4_route test, *found; 01151 01152 test.dest.addr = address.addr; 01153 test.netmask.addr = netmask.addr; 01154 test.metric = (uint32_t)metric; 01155 01156 found = pico_tree_findKey(&Routes, &test); 01157 if (found) { 01158 01159 pico_tree_delete(&Routes, found); 01160 PICO_FREE(found); 01161 01162 dbg_route(); 01163 return 0; 01164 } 01165 01166 pico_err = PICO_ERR_EINVAL; 01167 return -1; 01168 } 01169 01170 01171 int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask) 01172 { 01173 struct pico_ipv4_link test, *new; 01174 struct pico_ip4 network, gateway; 01175 char ipstr[30]; 01176 01177 if (!dev) { 01178 pico_err = PICO_ERR_EINVAL; 01179 return -1; 01180 } 01181 01182 test.address.addr = address.addr; 01183 test.netmask.addr = netmask.addr; 01184 test.dev = dev; 01185 /** XXX: Valid netmask / unicast address test **/ 01186 01187 if (pico_tree_findKey(&Tree_dev_link, &test)) { 01188 pico_err = PICO_ERR_EADDRINUSE; 01189 return -1; 01190 } 01191 01192 /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/ 01193 new = PICO_ZALLOC(sizeof(struct pico_ipv4_link)); 01194 if (!new) { 01195 dbg("IPv4: Out of memory!\n"); 01196 pico_err = PICO_ERR_ENOMEM; 01197 return -1; 01198 } 01199 01200 new->address.addr = address.addr; 01201 new->netmask.addr = netmask.addr; 01202 new->dev = dev; 01203 #ifdef PICO_SUPPORT_MCAST 01204 new->MCASTGroups = PICO_ZALLOC(sizeof(struct pico_tree)); 01205 if (!new->MCASTGroups) { 01206 PICO_FREE(new); 01207 dbg("IPv4: Out of memory!\n"); 01208 pico_err = PICO_ERR_ENOMEM; 01209 return -1; 01210 } 01211 01212 new->MCASTGroups->root = &LEAF; 01213 new->MCASTGroups->compare = ipv4_mcast_groups_cmp; 01214 #ifdef PICO_SUPPORT_IGMP 01215 new->mcast_compatibility = PICO_IGMPV3; /* default RFC 3376 $7.2.1 */ 01216 new->mcast_last_query_interval = PICO_IGMP_QUERY_INTERVAL; 01217 #endif 01218 #endif 01219 01220 pico_tree_insert(&Tree_dev_link, new); 01221 #ifdef PICO_SUPPORT_MCAST 01222 do { 01223 struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw; 01224 if (!mcast_default_link) { 01225 mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ 01226 mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ 01227 mcast_gw.addr = long_be(0x00000000); 01228 mcast_default_link = new; 01229 pico_ipv4_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new); 01230 } 01231 01232 mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; 01233 pico_ipv4_mcast_join(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); 01234 } while(0); 01235 #endif 01236 01237 network.addr = address.addr & netmask.addr; 01238 gateway.addr = 0U; 01239 pico_ipv4_route_add(network, netmask, gateway, 1, new); 01240 pico_ipv4_to_string(ipstr, new->address.addr); 01241 dbg("Assigned ipv4 %s to device %s\n", ipstr, new->dev->name); 01242 if (default_bcast_route.link == NULL) 01243 default_bcast_route.link = new; 01244 01245 return 0; 01246 } 01247 01248 static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link) 01249 { 01250 struct pico_tree_node *index = NULL, *tmp = NULL; 01251 struct pico_ipv4_route *route = NULL; 01252 01253 pico_tree_foreach_safe(index, &Routes, tmp) { 01254 route = index->keyValue; 01255 if (link == route->link) 01256 pico_ipv4_route_del(route->dest, route->netmask, (int)route->metric); 01257 } 01258 return 0; 01259 } 01260 01261 void MOCKABLE pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) 01262 { 01263 if (link) 01264 default_bcast_route.link = link; 01265 } 01266 01267 int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address) 01268 { 01269 struct pico_ipv4_link test, *found; 01270 01271 if (!dev) { 01272 pico_err = PICO_ERR_EINVAL; 01273 return -1; 01274 } 01275 01276 test.address.addr = address.addr; 01277 test.dev = dev; 01278 found = pico_tree_findKey(&Tree_dev_link, &test); 01279 if (!found) { 01280 pico_err = PICO_ERR_ENXIO; 01281 return -1; 01282 } 01283 01284 #ifdef PICO_SUPPORT_MCAST 01285 do { 01286 struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm; 01287 struct pico_mcast_group *g = NULL; 01288 struct pico_tree_node *index, *_tmp; 01289 if (found == mcast_default_link) { 01290 mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ 01291 mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ 01292 mcast_default_link = NULL; 01293 pico_ipv4_route_del(mcast_addr, mcast_nm, 1); 01294 } 01295 01296 mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; 01297 pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); 01298 pico_tree_foreach_safe(index, found->MCASTGroups, _tmp) { 01299 g = index->keyValue; 01300 pico_tree_delete(found->MCASTGroups, g); 01301 PICO_FREE(g); 01302 } 01303 } while(0); 01304 #endif 01305 01306 pico_ipv4_cleanup_routes(found); 01307 pico_tree_delete(&Tree_dev_link, found); 01308 if (default_bcast_route.link == found) 01309 default_bcast_route.link = NULL; 01310 01311 PICO_FREE(found); 01312 01313 return 0; 01314 } 01315 01316 01317 struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address) 01318 { 01319 struct pico_ipv4_link test = { 01320 0 01321 }, *found = NULL; 01322 test.address.addr = address->addr; 01323 01324 found = pico_tree_findKey(&Tree_dev_link, &test); 01325 if (!found) 01326 return NULL; 01327 else 01328 return found; 01329 } 01330 01331 struct pico_ipv4_link *MOCKABLE pico_ipv4_link_by_dev(struct pico_device *dev) 01332 { 01333 struct pico_tree_node *index = NULL; 01334 struct pico_ipv4_link *link = NULL; 01335 01336 pico_tree_foreach(index, &Tree_dev_link) { 01337 link = index->keyValue; 01338 if (link->dev == dev) 01339 return link; 01340 } 01341 return NULL; 01342 } 01343 01344 struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last) 01345 { 01346 struct pico_tree_node *index = NULL; 01347 struct pico_ipv4_link *link = NULL; 01348 int valid = 0; 01349 01350 if (last == NULL) 01351 valid = 1; 01352 01353 pico_tree_foreach(index, &Tree_dev_link) { 01354 link = index->keyValue; 01355 if (link->dev == dev) { 01356 if (last == link) 01357 valid = 1; 01358 else if (valid > 0) 01359 return link; 01360 } 01361 } 01362 return NULL; 01363 } 01364 01365 struct pico_device *MOCKABLE pico_ipv4_link_find(struct pico_ip4 *address) 01366 { 01367 struct pico_ipv4_link test, *found; 01368 if (!address) { 01369 pico_err = PICO_ERR_EINVAL; 01370 return NULL; 01371 } 01372 01373 test.dev = NULL; 01374 test.address.addr = address->addr; 01375 found = pico_tree_findKey(&Tree_dev_link, &test); 01376 if (!found) { 01377 pico_err = PICO_ERR_ENXIO; 01378 return NULL; 01379 } 01380 01381 return found->dev; 01382 } 01383 01384 01385 static int pico_ipv4_rebound_large(struct pico_frame *f) 01386 { 01387 #ifdef PICO_SUPPORT_IPV4FRAG 01388 uint16_t total_payload_written = 0; 01389 uint32_t len = f->transport_len; 01390 struct pico_frame *fr; 01391 struct pico_ip4 dst; 01392 struct pico_ipv4_hdr *hdr; 01393 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 01394 dst.addr = hdr->src.addr; 01395 01396 while(total_payload_written < len) { 01397 uint32_t space = (uint32_t)len - total_payload_written; 01398 if (space > PICO_IPV4_MAXPAYLOAD) 01399 space = PICO_IPV4_MAXPAYLOAD; 01400 01401 fr = pico_ipv4_alloc(&pico_proto_ipv4, (uint16_t)space); 01402 if (!fr) { 01403 pico_err = PICO_ERR_ENOMEM; 01404 return -1; 01405 } 01406 01407 if (space + total_payload_written < len) 01408 { 01409 fr->frag |= PICO_IPV4_MOREFRAG; 01410 } 01411 else 01412 { 01413 fr->frag &= PICO_IPV4_FRAG_MASK; 01414 } 01415 01416 fr->frag = (((total_payload_written) >> 3u) & 0xffffu) | fr->frag; 01417 01418 memcpy(fr->transport_hdr, f->transport_hdr + total_payload_written, fr->transport_len); 01419 if (pico_ipv4_frame_push(fr, &dst, hdr->proto) > 0) { 01420 total_payload_written = (uint16_t)((uint16_t)fr->transport_len + total_payload_written); 01421 } else { 01422 pico_frame_discard(fr); 01423 break; 01424 } 01425 } /* while() */ 01426 return (int)total_payload_written; 01427 #else 01428 (void)f; 01429 return -1; 01430 #endif 01431 } 01432 01433 int pico_ipv4_rebound(struct pico_frame *f) 01434 { 01435 struct pico_ip4 dst; 01436 struct pico_ipv4_hdr *hdr; 01437 if (!f) { 01438 pico_err = PICO_ERR_EINVAL; 01439 return -1; 01440 } 01441 01442 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 01443 if (!hdr) { 01444 pico_err = PICO_ERR_EINVAL; 01445 return -1; 01446 } 01447 01448 dst.addr = hdr->src.addr; 01449 if (f->transport_len > PICO_IPV4_MAXPAYLOAD) { 01450 return pico_ipv4_rebound_large(f); 01451 } 01452 01453 return pico_ipv4_frame_push(f, &dst, hdr->proto); 01454 } 01455 01456 static int pico_ipv4_pre_forward_checks(struct pico_frame *f) 01457 { 01458 static uint16_t last_id = 0; 01459 static uint16_t last_proto = 0; 01460 static struct pico_ip4 last_src = { 01461 0 01462 }; 01463 static struct pico_ip4 last_dst = { 01464 0 01465 }; 01466 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; 01467 01468 /* Decrease TTL, check if expired */ 01469 hdr->ttl = (uint8_t)(hdr->ttl - 1); 01470 if (hdr->ttl < 1) { 01471 pico_notify_ttl_expired(f); 01472 dbg(" ------------------- TTL EXPIRED\n"); 01473 return -1; 01474 } 01475 01476 /* HACK: increase crc to compensate decreased TTL */ 01477 hdr->crc++; 01478 01479 /* If source is local, discard anyway (packets bouncing back and forth) */ 01480 if (pico_ipv4_link_get(&hdr->src)) 01481 return -1; 01482 01483 /* If this was the last forwarded packet, silently discard to prevent duplications */ 01484 if ((last_src.addr == hdr->src.addr) && (last_id == hdr->id) 01485 && (last_dst.addr == hdr->dst.addr) && (last_proto == hdr->proto)) { 01486 return -1; 01487 } else { 01488 last_src.addr = hdr->src.addr; 01489 last_dst.addr = hdr->dst.addr; 01490 last_id = hdr->id; 01491 last_proto = hdr->proto; 01492 } 01493 01494 return 0; 01495 } 01496 01497 static int pico_ipv4_forward_check_dev(struct pico_frame *f) 01498 { 01499 if (f->dev->eth != NULL) 01500 f->len -= PICO_SIZE_ETHHDR; 01501 01502 if (f->len > f->dev->mtu) { 01503 pico_notify_pkt_too_big(f); 01504 return -1; 01505 } 01506 01507 return 0; 01508 } 01509 01510 static int pico_ipv4_forward(struct pico_frame *f) 01511 { 01512 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; 01513 struct pico_ipv4_route *rt; 01514 if (!hdr) { 01515 return -1; 01516 } 01517 01518 rt = route_find(&hdr->dst); 01519 if (!rt) { 01520 pico_notify_dest_unreachable(f); 01521 return -1; 01522 } 01523 01524 f->dev = rt->link->dev; 01525 01526 if (pico_ipv4_pre_forward_checks(f) < 0) 01527 return -1; 01528 01529 pico_ipv4_nat_outbound(f, &rt->link->address); 01530 01531 f->start = f->net_hdr; 01532 01533 if (pico_ipv4_forward_check_dev(f) < 0) 01534 return -1; 01535 01536 pico_sendto_dev(f); 01537 return 0; 01538 01539 } 01540 01541 int pico_ipv4_is_broadcast(uint32_t addr) 01542 { 01543 struct pico_ipv4_link *link; 01544 struct pico_tree_node *index; 01545 if (addr == PICO_IP4_BCAST) 01546 return 1; 01547 01548 pico_tree_foreach(index, &Tree_dev_link) { 01549 link = index->keyValue; 01550 if ((link->address.addr | (~link->netmask.addr)) == addr) 01551 return 1; 01552 } 01553 return 0; 01554 } 01555 01556 void pico_ipv4_unreachable(struct pico_frame *f, int err) 01557 { 01558 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 01559 #if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP 01560 f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR; 01561 pico_transport_error(f, hdr->proto, err); 01562 #endif 01563 } 01564 01565 int pico_ipv4_cleanup_links(struct pico_device *dev) 01566 { 01567 struct pico_tree_node *index = NULL, *_tmp = NULL; 01568 struct pico_ipv4_link *link = NULL; 01569 01570 pico_tree_foreach_safe(index, &Tree_dev_link, _tmp) { 01571 link = index->keyValue; 01572 if (dev == link->dev) 01573 pico_ipv4_link_del(dev, link->address); 01574 } 01575 return 0; 01576 } 01577 01578 01579 #endif
Generated on Tue Jul 12 2022 15:59:22 by 1.7.2