CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2
Fork of USB_Ethernet by
pico_ipv4.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. 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 00023 #ifdef PICO_SUPPORT_IPV4 00024 00025 #ifdef PICO_SUPPORT_MCAST 00026 # define ip_mcast_dbg(...) do{}while(0) /* so_mcast_dbg in pico_socket.c */ 00027 # define PICO_MCAST_ALL_HOSTS long_be(0xE0000001) /* 224.0.0.1 */ 00028 /* Default network interface for multicast transmission */ 00029 static struct pico_ipv4_link *mcast_default_link = NULL; 00030 #endif 00031 #ifdef PICO_SUPPORT_IPFRAG 00032 # define reassembly_dbg(...) do{}while(0) 00033 #endif 00034 00035 /* Queues */ 00036 static struct pico_queue in = {}; 00037 static struct pico_queue out = {}; 00038 00039 /* Functions */ 00040 static int ipv4_route_compare(void *ka, void * kb); 00041 00042 int pico_ipv4_to_string(char *ipbuf, const uint32_t ip) 00043 { 00044 const unsigned char *addr = (unsigned char *) &ip; 00045 int i; 00046 00047 if (!ipbuf) { 00048 pico_err = PICO_ERR_EINVAL; 00049 return -1; 00050 } 00051 00052 for(i = 0; i < 4; i++) 00053 { 00054 if(addr[i] > 99){ 00055 *ipbuf++ = '0' + (addr[i] / 100); 00056 *ipbuf++ = '0' + ((addr[i] % 100) / 10); 00057 *ipbuf++ = '0' + ((addr[i] % 100) % 10); 00058 }else if(addr[i] > 9){ 00059 *ipbuf++ = '0' + (addr[i] / 10); 00060 *ipbuf++ = '0' + (addr[i] % 10); 00061 }else{ 00062 *ipbuf++ = '0' + addr[i]; 00063 } 00064 if(i < 3) 00065 *ipbuf++ = '.'; 00066 } 00067 *ipbuf = '\0'; 00068 00069 return 0; 00070 } 00071 00072 int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) 00073 { 00074 unsigned char buf[4] = {0}; 00075 int cnt = 0; 00076 int p; 00077 00078 if(!ipstr || !ip) { 00079 pico_err = PICO_ERR_EINVAL; 00080 return -1; 00081 } 00082 00083 while((p = *ipstr++) != 0) 00084 { 00085 if(pico_is_digit(p)){ 00086 buf[cnt] = (10 * buf[cnt]) + (p - '0'); 00087 }else if(p == '.'){ 00088 cnt++; 00089 }else{ 00090 return -1; 00091 } 00092 } 00093 00094 /* Handle short notation */ 00095 if(cnt == 1){ 00096 buf[3] = buf[1]; 00097 buf[1] = 0; 00098 buf[2] = 0; 00099 }else if (cnt == 2){ 00100 buf[3] = buf[2]; 00101 buf[2] = 0; 00102 }else if(cnt != 3){ 00103 /* String could not be parsed, return error */ 00104 return -1; 00105 } 00106 00107 *ip = long_from(buf); 00108 00109 return 0; 00110 00111 } 00112 00113 int pico_ipv4_valid_netmask(uint32_t mask) 00114 { 00115 int cnt = 0; 00116 int end = 0; 00117 int i; 00118 uint32_t mask_swap = long_be(mask); 00119 00120 /* 00121 * Swap bytes for convenient parsing 00122 * e.g. 0x..f8ff will become 0xfff8.. 00123 * Then, we count the consecutive bits 00124 * 00125 * */ 00126 00127 for(i = 0; i < 32; i++){ 00128 if((mask_swap << i) & (1 << 31)){ 00129 if(end) { 00130 pico_err = PICO_ERR_EINVAL; 00131 return -1; 00132 } 00133 cnt++; 00134 }else{ 00135 end = 1; 00136 } 00137 } 00138 return cnt; 00139 } 00140 00141 int pico_ipv4_is_unicast(uint32_t address) 00142 { 00143 const unsigned char *addr = (unsigned char *) &address; 00144 if((addr[0] & 0xe0) == 0xe0) 00145 return 0; /* multicast */ 00146 00147 return 1; 00148 } 00149 00150 int pico_ipv4_is_multicast(uint32_t address) 00151 { 00152 const unsigned char *addr = (unsigned char *) &address; 00153 if((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0)) 00154 return 1; /* multicast */ 00155 00156 return 0; 00157 } 00158 00159 static int pico_ipv4_checksum(struct pico_frame *f) 00160 { 00161 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00162 if (!hdr) 00163 return -1; 00164 hdr->crc = 0; 00165 hdr->crc = short_be(pico_checksum(hdr, f->net_len)); 00166 return 0; 00167 } 00168 00169 #ifdef PICO_SUPPORT_IPFRAG 00170 struct pico_ipv4_fragmented_packet { 00171 uint16_t id; 00172 uint8_t proto; 00173 struct pico_ip4 src; 00174 struct pico_ip4 dst; 00175 uint16_t total_len; 00176 struct pico_tree *t; 00177 }; 00178 00179 static int pico_ipv4_fragmented_packet_cmp(void *ka, void *kb) 00180 { 00181 struct pico_ipv4_fragmented_packet *a = ka, *b = kb; 00182 00183 if (a->id < b->id) 00184 return -1; 00185 else if (a->id > b->id) 00186 return 1; 00187 else { 00188 if (a->proto < b->proto) 00189 return -1; 00190 else if (a->proto > b->proto) 00191 return 1; 00192 else { 00193 if (a->src.addr < b->src.addr) 00194 return -1; 00195 else if (a->src.addr > b->src.addr) 00196 return 1; 00197 else { 00198 if (a->dst.addr < b->dst.addr) 00199 return -1; 00200 else if (a->dst.addr > b->dst.addr) 00201 return 1; 00202 else 00203 return 0; 00204 } 00205 } 00206 } 00207 } 00208 00209 static int pico_ipv4_fragmented_element_cmp(void *ka, void *kb) 00210 { 00211 struct pico_frame *frame_a = ka, *frame_b = kb; 00212 struct pico_ipv4_hdr *a, *b; 00213 a = (struct pico_ipv4_hdr *) frame_a->net_hdr; 00214 b = (struct pico_ipv4_hdr *) frame_b->net_hdr; 00215 00216 if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) < short_be((b->frag & PICO_IPV4_FRAG_MASK))) 00217 return -1; 00218 else if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) > short_be((b->frag & PICO_IPV4_FRAG_MASK))) 00219 return 1; 00220 else 00221 return 0; 00222 } 00223 00224 PICO_TREE_DECLARE(pico_ipv4_fragmented_tree, pico_ipv4_fragmented_packet_cmp); 00225 00226 static inline void pico_ipv4_fragmented_cleanup(struct pico_ipv4_fragmented_packet *pfrag) 00227 { 00228 struct pico_tree_node *index = NULL, *_tmp = NULL; 00229 struct pico_frame *f_frag = NULL; 00230 00231 pico_tree_foreach_safe(index, pfrag->t, _tmp) { 00232 f_frag = index->keyValue; 00233 reassembly_dbg("REASSEMBLY: remove packet with offset %u\n", short_be(((struct pico_ipv4_hdr *)f_frag->net_hdr)->frag) & PICO_IPV4_FRAG_MASK); 00234 pico_tree_delete(pfrag->t, f_frag); 00235 pico_frame_discard(f_frag); 00236 } 00237 pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag); 00238 pico_free(pfrag->t); 00239 pico_free(pfrag); 00240 } 00241 #endif /* PICO_SUPPORT_IPFRAG */ 00242 00243 #ifdef PICO_SUPPORT_IPFRAG 00244 static inline int pico_ipv4_fragmented_check(struct pico_protocol *self, struct pico_frame **f) 00245 { 00246 uint8_t *running_pointer = NULL; 00247 uint16_t running_offset = 0; 00248 uint16_t offset = 0; 00249 uint16_t data_len = 0; 00250 struct pico_ipv4_hdr *f_frag_hdr = NULL, *hdr = (struct pico_ipv4_hdr *) (*f)->net_hdr; 00251 struct pico_udp_hdr *udp_hdr = NULL; 00252 struct pico_tcp_hdr *tcp_hdr = NULL; 00253 struct pico_ipv4_fragmented_packet *pfrag = NULL, frag; 00254 struct pico_frame *f_new = NULL, *f_frag = NULL; 00255 struct pico_tree_node *index, *_tmp; 00256 00257 data_len = short_be(hdr->len) - (*f)->net_len; 00258 offset = short_be(hdr->frag) & PICO_IPV4_FRAG_MASK; 00259 if (short_be(hdr->frag) & PICO_IPV4_MOREFRAG) { 00260 if (!offset) { 00261 reassembly_dbg("REASSEMBLY: first element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); 00262 if (!pico_tree_empty(&pico_ipv4_fragmented_tree)) { 00263 reassembly_dbg("REASSEMBLY: cleanup tree\n"); 00264 // only one entry allowed in this tree 00265 pfrag = pico_tree_first(&pico_ipv4_fragmented_tree); 00266 pico_ipv4_fragmented_cleanup(pfrag); 00267 } 00268 // add entry in tree for this ID and create secondary tree to contain fragmented elements 00269 pfrag = pico_zalloc(sizeof(struct pico_ipv4_fragmented_packet)); 00270 if (!pfrag) { 00271 pico_err = PICO_ERR_ENOMEM; 00272 return -1; 00273 } 00274 pfrag->id = short_be(hdr->id); 00275 pfrag->proto = hdr->proto; 00276 pfrag->src.addr = long_be(hdr->src.addr); 00277 pfrag->dst.addr = long_be(hdr->dst.addr); 00278 pfrag->total_len = short_be(hdr->len) - (*f)->net_len; 00279 pfrag->t = pico_zalloc(sizeof(struct pico_tree)); 00280 if (!pfrag->t) { 00281 pico_free(pfrag); 00282 pico_err = PICO_ERR_ENOMEM; 00283 return -1; 00284 } 00285 pfrag->t->root = &LEAF; 00286 pfrag->t->compare = pico_ipv4_fragmented_element_cmp; 00287 00288 pico_tree_insert(pfrag->t, *f); 00289 pico_tree_insert(&pico_ipv4_fragmented_tree, pfrag); 00290 return 0; 00291 } 00292 else { 00293 reassembly_dbg("REASSEMBLY: intermediate element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); 00294 frag.id = short_be(hdr->id); 00295 frag.proto = hdr->proto; 00296 frag.src.addr = long_be(hdr->src.addr); 00297 frag.dst.addr = long_be(hdr->dst.addr); 00298 pfrag = pico_tree_findKey(&pico_ipv4_fragmented_tree, &frag); 00299 if (pfrag) { 00300 pfrag->total_len += (short_be(hdr->len) - (*f)->net_len); 00301 pico_tree_insert(pfrag->t, *f); 00302 return 0; 00303 } else { 00304 reassembly_dbg("REASSEMBLY: silently discard intermediate frame, first packet was lost or disallowed (one fragmented packet at a time)\n"); 00305 pico_frame_discard(*f); 00306 return 0; 00307 } 00308 } 00309 } else if (offset) { 00310 reassembly_dbg("REASSEMBLY: last element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); 00311 frag.id = short_be(hdr->id); 00312 frag.proto = hdr->proto; 00313 frag.src.addr = long_be(hdr->src.addr); 00314 frag.dst.addr = long_be(hdr->dst.addr); 00315 pfrag = pico_tree_findKey(&pico_ipv4_fragmented_tree, &frag); 00316 if (pfrag) { 00317 pfrag->total_len += (short_be(hdr->len) - (*f)->net_len); 00318 reassembly_dbg("REASSEMBLY: fragmented packet in tree, reassemble packet of %u data bytes\n", pfrag->total_len); 00319 f_new = self->alloc(self, pfrag->total_len); 00320 00321 f_frag = pico_tree_first(pfrag->t); 00322 reassembly_dbg("REASSEMBLY: copy IP header information len = %lu\n", f_frag->net_len); 00323 f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr; 00324 data_len = short_be(f_frag_hdr->len) - f_frag->net_len; 00325 memcpy(f_new->net_hdr, f_frag->net_hdr, f_frag->net_len); 00326 memcpy(f_new->transport_hdr, f_frag->transport_hdr, data_len); 00327 running_pointer = f_new->transport_hdr + data_len; 00328 offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK; 00329 running_offset = data_len / 8; 00330 pico_tree_delete(pfrag->t, f_frag); 00331 pico_frame_discard(f_frag); 00332 reassembly_dbg("REASSEMBLY: reassembled first packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset); 00333 00334 pico_tree_foreach_safe(index, pfrag->t, _tmp) 00335 { 00336 f_frag = index->keyValue; 00337 f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr; 00338 data_len = short_be(f_frag_hdr->len) - f_frag->net_len; 00339 memcpy(running_pointer, f_frag->transport_hdr, data_len); 00340 running_pointer += data_len; 00341 offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK; 00342 if (offset != running_offset) { 00343 reassembly_dbg("REASSEMBLY: error reassembling intermediate packet: offset %u != expected offset %u (missing fragment)\n", offset, running_offset); 00344 pico_ipv4_fragmented_cleanup(pfrag); 00345 return -1; 00346 } 00347 running_offset += (data_len / 8); 00348 pico_tree_delete(pfrag->t, f_frag); 00349 pico_frame_discard(f_frag); 00350 reassembly_dbg("REASSEMBLY: reassembled intermediate packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset); 00351 } 00352 pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag); 00353 pico_free(pfrag); 00354 00355 data_len = short_be(hdr->len) - (*f)->net_len; 00356 memcpy(running_pointer, (*f)->transport_hdr, data_len); 00357 offset = short_be(hdr->frag) & PICO_IPV4_FRAG_MASK; 00358 pico_frame_discard(*f); 00359 reassembly_dbg("REASSEMBLY: reassembled last packet of %u data bytes, offset = %u\n", data_len, offset); 00360 00361 hdr = (struct pico_ipv4_hdr *)f_new->net_hdr; 00362 hdr->len = pfrag->total_len; 00363 hdr->frag = 0; /* flags cleared and no offset */ 00364 hdr->crc = 0; 00365 hdr->crc = short_be(pico_checksum(hdr, f_new->net_len)); 00366 /* Optional, the UDP/TCP CRC should already be correct */ 00367 if (0) { 00368 #ifdef PICO_SUPPORT_TCP 00369 } else if (hdr->proto == PICO_PROTO_TCP) { 00370 tcp_hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; 00371 tcp_hdr->crc = 0; 00372 tcp_hdr->crc = short_be(pico_tcp_checksum_ipv4(f_new)); 00373 #endif 00374 #ifdef PICO_SUPPORT_UDP 00375 } else if (hdr->proto == PICO_PROTO_UDP){ 00376 udp_hdr = (struct pico_udp_hdr *) f_new->transport_hdr; 00377 udp_hdr->crc = 0; 00378 udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f_new)); 00379 #endif 00380 } 00381 reassembly_dbg("REASSEMBLY: packet with id %X reassembled correctly\n", short_be(hdr->id)); 00382 *f = f_new; 00383 return 1; 00384 } else { 00385 reassembly_dbg("REASSEMBLY: silently discard last frame, first packet was lost or disallowed (one fragmented packet at a time)\n"); 00386 pico_frame_discard(*f); 00387 return 0; 00388 } 00389 } else { 00390 return 1; 00391 } 00392 } 00393 #else 00394 static inline int pico_ipv4_fragmented_check(struct pico_protocol *self, struct pico_frame **f) 00395 { 00396 return 1; 00397 } 00398 #endif /* PICO_SUPPORT_IPFRAG */ 00399 00400 #ifdef PICO_SUPPORT_CRC 00401 static inline int pico_ipv4_crc_check(struct pico_frame *f) 00402 { 00403 uint16_t checksum_invalid = 1; 00404 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00405 00406 checksum_invalid = short_be(pico_checksum(hdr, f->net_len)); 00407 if (checksum_invalid) { 00408 dbg("IP: checksum failed!\n"); 00409 pico_frame_discard(f); 00410 return 0; 00411 } 00412 return 1; 00413 } 00414 #else 00415 static inline int pico_ipv4_crc_check(struct pico_frame *f) 00416 { 00417 return 1; 00418 } 00419 #endif /* PICO_SUPPORT_CRC */ 00420 00421 static int pico_ipv4_forward(struct pico_frame *f); 00422 #ifdef PICO_SUPPORT_MCAST 00423 static int pico_ipv4_mcast_filter(struct pico_frame *f); 00424 #endif 00425 00426 static int ipv4_link_compare(void *ka, void *kb) 00427 { 00428 struct pico_ipv4_link *a = ka, *b =kb; 00429 if (a->address.addr < b->address.addr) 00430 return -1; 00431 if (a->address.addr > b->address.addr) 00432 return 1; 00433 00434 //zero can be assigned multiple times (e.g. for DHCP) 00435 if (a->dev != NULL && b->dev != NULL && a->address.addr == PICO_IP4_ANY && b->address.addr == PICO_IP4_ANY){ 00436 if (a->dev < b->dev) 00437 return -1; 00438 if (a->dev > b->dev) 00439 return 1; 00440 } 00441 return 0; 00442 } 00443 00444 PICO_TREE_DECLARE(Tree_dev_link, ipv4_link_compare); 00445 00446 static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f) 00447 { 00448 uint8_t option_len = 0; 00449 int ret = 0; 00450 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00451 struct pico_ipv4_link test = {.address = {.addr = PICO_IP4_ANY}, .dev = NULL}; 00452 00453 /* NAT needs transport header information */ 00454 if(((hdr->vhl) & 0x0F )> 5){ 00455 option_len = 4*(((hdr->vhl) & 0x0F)-5); 00456 } 00457 f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR + option_len; 00458 f->transport_len = short_be(hdr->len) - PICO_SIZE_IP4HDR - option_len; 00459 f->net_len = PICO_SIZE_IP4HDR + option_len; 00460 00461 #ifdef PICO_SUPPORT_IPFILTER 00462 if (ipfilter(f)) { 00463 /*pico_frame is discarded as result of the filtering*/ 00464 return 0; 00465 } 00466 #endif 00467 00468 /* ret == 1 indicates to continue the function */ 00469 ret = pico_ipv4_crc_check(f); 00470 if (ret < 1) 00471 return ret; 00472 ret = pico_ipv4_fragmented_check(self, &f); 00473 if (ret < 1) 00474 return ret; 00475 00476 #ifdef PICO_SUPPORT_MCAST 00477 /* Multicast address in source, discard quietly */ 00478 if (pico_ipv4_is_multicast(hdr->src.addr)) { 00479 ip_mcast_dbg("MCAST: ERROR multicast address %08X in source address\n", hdr->src.addr); 00480 pico_frame_discard(f); 00481 return 0; 00482 } 00483 #endif 00484 if (hdr->frag & 0x80) { 00485 pico_frame_discard(f); //RFC 3514 00486 return 0; 00487 } 00488 if (0) { 00489 #ifdef PICO_SUPPORT_UDP 00490 } else if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) { 00491 /* Receiving UDP broadcast datagram */ 00492 f->flags |= PICO_FRAME_FLAG_BCAST; 00493 pico_enqueue(pico_proto_udp.q_in, f); 00494 #endif 00495 } else if (pico_ipv4_is_multicast(hdr->dst.addr)) { 00496 #ifdef PICO_SUPPORT_MCAST 00497 /* Receiving UDP multicast datagram TODO set f->flags? */ 00498 if (hdr->proto == PICO_PROTO_IGMP) { 00499 ip_mcast_dbg("MCAST: received IGMP message\n"); 00500 pico_transport_receive(f, PICO_PROTO_IGMP); 00501 } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) { 00502 pico_enqueue(pico_proto_udp.q_in, f); 00503 } else { 00504 pico_frame_discard(f); 00505 } 00506 #endif 00507 } else if (pico_ipv4_link_find(&hdr->dst)) { 00508 if (pico_ipv4_nat_isenabled_in(f) == 0) { /* if NAT enabled (dst port registerd), do NAT */ 00509 if(pico_ipv4_nat(f, hdr->dst) != 0) { 00510 return -1; 00511 } 00512 pico_ipv4_forward(f); /* Local packet became forward packet after NAT */ 00513 } else { /* no NAT so enqueue to next layer */ 00514 pico_transport_receive(f, hdr->proto); 00515 } 00516 } else if (pico_tree_findKey(&Tree_dev_link, &test)){ 00517 #ifdef PICO_SUPPORT_UDP 00518 //address of this device is apparently 0.0.0.0; might be a DHCP packet 00519 pico_enqueue(pico_proto_udp.q_in, f); 00520 #endif 00521 } else { 00522 /* Packet is not local. Try to forward. */ 00523 if (pico_ipv4_forward(f) != 0) { 00524 pico_frame_discard(f); 00525 } 00526 } 00527 return 0; 00528 } 00529 00530 PICO_TREE_DECLARE(Routes, ipv4_route_compare); 00531 00532 00533 static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f) 00534 { 00535 f->start = (uint8_t*) f->net_hdr; 00536 #ifdef PICO_SUPPORT_IPFILTER 00537 if (ipfilter(f)) { 00538 /*pico_frame is discarded as result of the filtering*/ 00539 return 0; 00540 } 00541 #endif 00542 return pico_sendto_dev(f); 00543 } 00544 00545 00546 static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, int size) 00547 { 00548 struct pico_frame *f = pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR); 00549 if (!f) 00550 return NULL; 00551 f->datalink_hdr = f->buffer; 00552 f->net_hdr = f->buffer + PICO_SIZE_ETHHDR; 00553 f->net_len = PICO_SIZE_IP4HDR; 00554 f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR; 00555 f->transport_len = size; 00556 f->len = size + PICO_SIZE_IP4HDR; 00557 return f; 00558 } 00559 00560 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f); 00561 00562 /* Interface: protocol definition */ 00563 struct pico_protocol pico_proto_ipv4 = { 00564 .name = "ipv4", 00565 .proto_number = PICO_PROTO_IPV4, 00566 .layer = PICO_LAYER_NETWORK, 00567 .alloc = pico_ipv4_alloc, 00568 .process_in = pico_ipv4_process_in, 00569 .process_out = pico_ipv4_process_out, 00570 .push = pico_ipv4_frame_sock_push, 00571 .q_in = &in, 00572 .q_out = &out, 00573 }; 00574 00575 struct pico_ipv4_route 00576 { 00577 struct pico_ip4 dest; 00578 struct pico_ip4 netmask; 00579 struct pico_ip4 gateway; 00580 struct pico_ipv4_link *link; 00581 uint32_t metric; 00582 }; 00583 00584 00585 static int ipv4_route_compare(void *ka, void * kb) 00586 { 00587 struct pico_ipv4_route *a = ka, *b = kb; 00588 00589 /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */ 00590 if (long_be(a->netmask.addr) < long_be(b->netmask.addr)) 00591 return -1; 00592 00593 if (long_be(a->netmask.addr) > long_be(b->netmask.addr)) 00594 return 1; 00595 00596 if (a->dest.addr < b->dest.addr) 00597 return -1; 00598 00599 if (a->dest.addr > b->dest.addr) 00600 return 1; 00601 00602 if (a->metric < b->metric) 00603 return -1; 00604 00605 if (a->metric > b->metric) 00606 return 1; 00607 00608 return 0; 00609 } 00610 00611 static struct pico_ipv4_route *route_find(struct pico_ip4 *addr) 00612 { 00613 struct pico_ipv4_route *r; 00614 struct pico_tree_node * index; 00615 00616 if(addr->addr != PICO_IP4_BCAST) 00617 { 00618 pico_tree_foreach_reverse(index, &Routes) { 00619 r = index->keyValue; 00620 if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) { 00621 return r; 00622 } 00623 } 00624 } 00625 else 00626 { 00627 r = pico_tree_first(&Routes); 00628 if(!r->netmask.addr) 00629 { 00630 return r; 00631 } 00632 else 00633 { 00634 dbg("WARNING: no default route for a global broadcast found\n"); 00635 } 00636 } 00637 00638 return NULL; 00639 } 00640 00641 struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr) 00642 { 00643 struct pico_ip4 nullip; 00644 struct pico_ipv4_route *route; 00645 nullip.addr = 0U; 00646 00647 if(!addr) { 00648 pico_err = PICO_ERR_EINVAL; 00649 return nullip; 00650 } 00651 00652 route = route_find(addr); 00653 if (!route) { 00654 pico_err = PICO_ERR_EHOSTUNREACH; 00655 return nullip; 00656 } 00657 else 00658 return route->gateway; 00659 } 00660 00661 struct pico_ip4 *pico_ipv4_source_find(struct pico_ip4 *dst) 00662 { 00663 struct pico_ip4 *myself = NULL; 00664 struct pico_ipv4_route *rt; 00665 00666 if(!dst) { 00667 pico_err = PICO_ERR_EINVAL; 00668 return NULL; 00669 } 00670 00671 rt = route_find(dst); 00672 if (rt) { 00673 myself = &rt->link->address; 00674 } else 00675 pico_err = PICO_ERR_EHOSTUNREACH; 00676 return myself; 00677 } 00678 00679 00680 #ifdef PICO_SUPPORT_MCAST 00681 /* link 00682 * | 00683 * MCASTGroups 00684 * | | | 00685 * ------------ | ------------ 00686 * | | | 00687 * MCASTSources MCASTSources MCASTSources 00688 * | | | | | | | | | | | | 00689 * S S S S S S S S S S S S 00690 * 00691 * MCASTGroups: RBTree(mcast_group) 00692 * MCASTSources: RBTree(source) 00693 */ 00694 static int ipv4_mcast_groups_cmp(void * ka, void * kb) 00695 { 00696 struct pico_mcast_group *a = ka, *b = kb; 00697 if (a->mcast_addr.addr < b->mcast_addr.addr) { 00698 return -1; 00699 } else if (a->mcast_addr.addr > b->mcast_addr.addr) { 00700 return 1; 00701 } else { 00702 return 0; 00703 } 00704 } 00705 00706 static int ipv4_mcast_sources_cmp(void *ka, void *kb) 00707 { 00708 struct pico_ip4 *a = ka, *b = kb; 00709 if (a->addr < b->addr) 00710 return -1; 00711 if (a->addr > b->addr) 00712 return 1; 00713 return 0; 00714 } 00715 00716 static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link) 00717 { 00718 uint16_t i = 0; 00719 struct pico_mcast_group __attribute__ ((unused)) *g = NULL; 00720 struct pico_ip4 __attribute__ ((unused)) *source = NULL; 00721 struct pico_tree_node *index = NULL, *index2 = NULL; 00722 00723 ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); 00724 ip_mcast_dbg("+ MULTICAST list interface %-16s +\n", mcast_link->dev->name); 00725 ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); 00726 ip_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n"); 00727 ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); 00728 00729 pico_tree_foreach(index, mcast_link->MCASTGroups) 00730 { 00731 g = index->keyValue; 00732 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, ""); 00733 pico_tree_foreach(index2, &g->MCASTSources) 00734 { 00735 source = index2->keyValue; 00736 ip_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %08X +\n", "", "", "", "", "", source->addr); 00737 } 00738 i++; 00739 } 00740 ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); 00741 } 00742 00743 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) 00744 { 00745 struct pico_mcast_group *g = NULL, test = {0}; 00746 struct pico_ipv4_link *link = NULL; 00747 struct pico_tree_node *index = NULL, *_tmp = NULL; 00748 struct pico_ip4 *source = NULL; 00749 00750 if (mcast_link) 00751 link = pico_ipv4_link_get(mcast_link); 00752 else 00753 link = mcast_default_link; 00754 00755 test.mcast_addr = *mcast_group; 00756 g = pico_tree_findKey(link->MCASTGroups, &test); 00757 if (g) { 00758 if (reference_count) 00759 g->reference_count++; 00760 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); 00761 } else { 00762 g = pico_zalloc(sizeof(struct pico_mcast_group)); 00763 if (!g) { 00764 pico_err = PICO_ERR_ENOMEM; 00765 return -1; 00766 } 00767 /* "non-existent" state of filter mode INCLUDE and empty source list */ 00768 g->filter_mode = PICO_IP_MULTICAST_INCLUDE; 00769 g->reference_count = 1; 00770 g->mcast_addr = *mcast_group; 00771 g->MCASTSources.root = &LEAF; 00772 g->MCASTSources.compare = ipv4_mcast_sources_cmp; 00773 pico_tree_insert(link->MCASTGroups, g); 00774 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE); 00775 } 00776 00777 /* cleanup filter */ 00778 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) 00779 { 00780 source = index->keyValue; 00781 pico_tree_delete(&g->MCASTSources, source); 00782 pico_free(source); 00783 } 00784 /* insert new filter */ 00785 if (MCASTFilter) { 00786 pico_tree_foreach(index, MCASTFilter) 00787 { 00788 source = pico_zalloc(sizeof(struct pico_ip4)); 00789 if (!source) { 00790 pico_err = PICO_ERR_ENOMEM; 00791 return -1; 00792 } 00793 source->addr = ((struct pico_ip4 *)index->keyValue)->addr; 00794 pico_tree_insert(&g->MCASTSources, source); 00795 } 00796 } 00797 g->filter_mode = filter_mode; 00798 00799 pico_ipv4_mcast_print_groups(link); 00800 return 0; 00801 } 00802 00803 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) 00804 { 00805 00806 struct pico_mcast_group *g = NULL, test = {0}; 00807 struct pico_ipv4_link *link = NULL; 00808 struct pico_tree_node *index = NULL, *_tmp = NULL; 00809 struct pico_ip4 *source = NULL; 00810 00811 if (mcast_link) 00812 link = pico_ipv4_link_get(mcast_link); 00813 else 00814 link = mcast_default_link; 00815 00816 test.mcast_addr = *mcast_group; 00817 g = pico_tree_findKey(link->MCASTGroups, &test); 00818 if (!g) { 00819 pico_err = PICO_ERR_EINVAL; 00820 return -1; 00821 } else { 00822 if (reference_count && (--(g->reference_count) < 1)) { 00823 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE); 00824 /* cleanup filter */ 00825 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) 00826 { 00827 source = index->keyValue; 00828 pico_tree_delete(&g->MCASTSources, source); 00829 pico_free(source); 00830 } 00831 pico_tree_delete(link->MCASTGroups, g); 00832 pico_free(g); 00833 } else { 00834 pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); 00835 /* cleanup filter */ 00836 pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) 00837 { 00838 source = index->keyValue; 00839 pico_tree_delete(&g->MCASTSources, source); 00840 pico_free(source); 00841 } 00842 /* insert new filter */ 00843 if (MCASTFilter) { 00844 pico_tree_foreach(index, MCASTFilter) 00845 { 00846 source = pico_zalloc(sizeof(struct pico_ip4)); 00847 if (!source) { 00848 pico_err = PICO_ERR_ENOMEM; 00849 return -1; 00850 } 00851 source->addr = ((struct pico_ip4 *)index->keyValue)->addr; 00852 pico_tree_insert(&g->MCASTSources, source); 00853 } 00854 } 00855 g->filter_mode = filter_mode; 00856 } 00857 } 00858 00859 pico_ipv4_mcast_print_groups(link); 00860 return 0; 00861 } 00862 00863 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) 00864 { 00865 return mcast_default_link; 00866 } 00867 00868 static int pico_ipv4_mcast_filter(struct pico_frame *f) 00869 { 00870 struct pico_ipv4_link *link = NULL; 00871 struct pico_tree_node *index = NULL, *index2 = NULL; 00872 struct pico_mcast_group *g = NULL, test = {0}; 00873 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00874 00875 test.mcast_addr = hdr->dst; 00876 00877 pico_tree_foreach(index, &Tree_dev_link) 00878 { 00879 link = index->keyValue; 00880 g = pico_tree_findKey(link->MCASTGroups, &test); 00881 if (g) { 00882 if (f->dev == link->dev) { 00883 ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name); 00884 /* perform source filtering */ 00885 switch (g->filter_mode) 00886 { 00887 case PICO_IP_MULTICAST_INCLUDE: 00888 pico_tree_foreach(index2, &g->MCASTSources) 00889 { 00890 if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { 00891 ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr); 00892 return 0; 00893 } 00894 } 00895 ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr); 00896 return -1; 00897 break; 00898 00899 case PICO_IP_MULTICAST_EXCLUDE: 00900 pico_tree_foreach(index2, &g->MCASTSources) 00901 { 00902 if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { 00903 ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr); 00904 return -1; 00905 } 00906 } 00907 ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr); 00908 return 0; 00909 break; 00910 00911 default: 00912 return -1; 00913 break; 00914 } 00915 } else { 00916 ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name); 00917 } 00918 } else { 00919 ip_mcast_dbg("MCAST: IP %08X is not a group member of link %s\n", hdr->dst.addr, f->dev->name); 00920 } 00921 } 00922 return -1; 00923 } 00924 00925 #else 00926 00927 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) 00928 { 00929 pico_err = PICO_ERR_EPROTONOSUPPORT; 00930 return -1; 00931 } 00932 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) 00933 { 00934 pico_err = PICO_ERR_EPROTONOSUPPORT; 00935 return -1; 00936 } 00937 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) 00938 { 00939 pico_err = PICO_ERR_EPROTONOSUPPORT; 00940 return NULL; 00941 } 00942 #endif /* PICO_SUPPORT_MCAST */ 00943 00944 int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto) 00945 { 00946 00947 struct pico_ipv4_route *route; 00948 struct pico_ipv4_link *link; 00949 struct pico_ipv4_hdr *hdr; 00950 uint8_t ttl = PICO_IPV4_DEFAULT_TTL; 00951 uint8_t vhl = 0x45; /* version 4, header length 20 */ 00952 static uint16_t ipv4_progressive_id = 0x91c0; 00953 #ifdef PICO_SUPPORT_MCAST 00954 struct pico_tree_node *index; 00955 #endif 00956 00957 if(!f || !dst) { 00958 pico_err = PICO_ERR_EINVAL; 00959 return -1; 00960 } 00961 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00962 if (!hdr) { 00963 dbg("IP header error\n"); 00964 pico_err = PICO_ERR_EINVAL; 00965 goto drop; 00966 } 00967 00968 if (dst->addr == 0) { 00969 dbg("IP destination addr error\n"); 00970 pico_err = PICO_ERR_EINVAL; 00971 goto drop; 00972 } 00973 00974 route = route_find(dst); 00975 if (!route) { 00976 dbg("Route to %08x not found.\n", long_be(dst->addr)); 00977 pico_err = PICO_ERR_EHOSTUNREACH; 00978 goto drop; 00979 } else { 00980 link = route->link; 00981 #ifdef PICO_SUPPORT_MCAST 00982 if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */ 00983 switch (proto) { 00984 case PICO_PROTO_UDP: 00985 if(pico_udp_get_mc_ttl(f->sock, &ttl) < 0) 00986 ttl = PICO_IP_DEFAULT_MULTICAST_TTL; 00987 break; 00988 case PICO_PROTO_IGMP: 00989 vhl = 0x46; /* header length 24 */ 00990 ttl = 1; 00991 /* router alert (RFC 2113) */ 00992 hdr->options[0] = 0x94; 00993 hdr->options[1] = 0x04; 00994 hdr->options[2] = 0x00; 00995 hdr->options[3] = 0x00; 00996 if (f->dev && link->dev != f->dev) { /* default link is not requested link */ 00997 pico_tree_foreach(index, &Tree_dev_link) { 00998 link = index->keyValue; 00999 if (link->dev == f->dev) 01000 break; 01001 } 01002 } 01003 break; 01004 default: 01005 ttl = PICO_IPV4_DEFAULT_TTL; 01006 } 01007 } 01008 #endif 01009 } 01010 01011 hdr->vhl = vhl; 01012 hdr->len = short_be(f->transport_len + f->net_len); 01013 if (f->transport_hdr != f->payload) 01014 ipv4_progressive_id++; 01015 hdr->id = short_be(ipv4_progressive_id); 01016 hdr->dst.addr = dst->addr; 01017 hdr->src.addr = link->address.addr; 01018 hdr->ttl = ttl; 01019 hdr->proto = proto; 01020 hdr->frag = short_be(PICO_IPV4_DONTFRAG); 01021 #ifdef PICO_SUPPORT_IPFRAG 01022 # ifdef PICO_SUPPORT_UDP 01023 if (proto == PICO_PROTO_UDP) { 01024 /* first fragment, can not use transport_len to calculate IP length */ 01025 if (f->transport_hdr != f->payload) 01026 hdr->len = short_be(f->payload_len + sizeof(struct pico_udp_hdr) + f->net_len); 01027 /* set fragmentation flags and offset calculated in socket layer */ 01028 hdr->frag = f->frag; 01029 } 01030 # endif /* PICO_SUPPORT_UDP */ 01031 #endif /* PICO_SUPPORT_IPFRAG */ 01032 pico_ipv4_checksum(f); 01033 01034 if (f->sock && f->sock->dev){ 01035 //if the socket has its device set, use that (currently used for DHCP) 01036 f->dev = f->sock->dev; 01037 } else { 01038 f->dev = link->dev; 01039 } 01040 01041 #ifdef PICO_SUPPORT_MCAST 01042 if (pico_ipv4_is_multicast(hdr->dst.addr)) { 01043 struct pico_frame *cpy; 01044 /* Sending UDP multicast datagram, am I member? If so, loopback copy */ 01045 if ((proto != PICO_PROTO_IGMP) && (pico_ipv4_mcast_filter(f) == 0)) { 01046 ip_mcast_dbg("MCAST: sender is member of group, loopback copy\n"); 01047 cpy = pico_frame_copy(f); 01048 pico_enqueue(&in, cpy); 01049 } 01050 } 01051 #endif 01052 01053 if(pico_ipv4_link_get(&hdr->dst)){ 01054 //it's our own IP 01055 return pico_enqueue(&in, f); 01056 }else{ 01057 /* TODO: Check if there are members subscribed here */ 01058 return pico_enqueue(&out, f); 01059 } 01060 01061 drop: 01062 pico_frame_discard(f); 01063 return -1; 01064 } 01065 01066 01067 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f) 01068 { 01069 struct pico_ip4 *dst; 01070 struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info; 01071 if (!f->sock) { 01072 pico_frame_discard(f); 01073 return -1; 01074 } 01075 01076 if (remote_duple) { 01077 dst = &remote_duple->remote_addr.ip4; 01078 } else { 01079 dst = &f->sock->remote_addr.ip4; 01080 } 01081 01082 return pico_ipv4_frame_push(f, dst, f->sock->proto->proto_number); 01083 } 01084 01085 01086 #ifdef DEBUG_ROUTE 01087 static void dbg_route(void) 01088 { 01089 struct pico_ipv4_route *r; 01090 struct pico_tree_node * index; 01091 pico_tree_foreach(index,&Routes){ 01092 r = index->keyValue; 01093 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); 01094 } 01095 } 01096 #else 01097 #define dbg_route() do{ }while(0) 01098 #endif 01099 01100 int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) 01101 { 01102 struct pico_ipv4_route test, *new; 01103 test.dest.addr = address.addr; 01104 test.netmask.addr = netmask.addr; 01105 test.metric = metric; 01106 01107 if(pico_tree_findKey(&Routes,&test)){ 01108 pico_err = PICO_ERR_EINVAL; 01109 return -1; 01110 } 01111 01112 new = pico_zalloc(sizeof(struct pico_ipv4_route)); 01113 if (!new) { 01114 pico_err = PICO_ERR_ENOMEM; 01115 return -1; 01116 } 01117 new->dest.addr = address.addr; 01118 new->netmask.addr = netmask.addr; 01119 new->gateway.addr = gateway.addr; 01120 new->metric = metric; 01121 if (gateway.addr == 0) { 01122 /* No gateway provided, use the link */ 01123 new->link = link; 01124 } else { 01125 struct pico_ipv4_route *r = route_find(&gateway); 01126 if (!r ) { /* Specified Gateway is unreachable */ 01127 pico_err = PICO_ERR_EHOSTUNREACH; 01128 pico_free(new); 01129 return -1; 01130 } 01131 if (r->gateway.addr) { /* Specified Gateway is not a neighbor */ 01132 pico_err = PICO_ERR_ENETUNREACH; 01133 pico_free(new); 01134 return -1; 01135 } 01136 new->link = r->link; 01137 } 01138 if (!new->link) { 01139 pico_err = PICO_ERR_EINVAL; 01140 pico_free(new); 01141 return -1; 01142 } 01143 01144 pico_tree_insert(&Routes,new); 01145 dbg_route(); 01146 return 0; 01147 } 01148 01149 int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) 01150 { 01151 struct pico_ipv4_route test, *found; 01152 if (!link) { 01153 pico_err = PICO_ERR_EINVAL; 01154 return -1; 01155 } 01156 test.dest.addr = address.addr; 01157 test.netmask.addr = netmask.addr; 01158 test.metric = metric; 01159 01160 found = pico_tree_findKey(&Routes,&test); 01161 if (found) { 01162 01163 pico_tree_delete(&Routes,found); 01164 pico_free(found); 01165 01166 dbg_route(); 01167 return 0; 01168 } 01169 pico_err = PICO_ERR_EINVAL; 01170 return -1; 01171 } 01172 01173 01174 int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask) 01175 { 01176 struct pico_ipv4_link test, *new; 01177 struct pico_ip4 network, gateway; 01178 char ipstr[30]; 01179 01180 if(!dev) { 01181 pico_err = PICO_ERR_EINVAL; 01182 return -1; 01183 } 01184 test.address.addr = address.addr; 01185 test.netmask.addr = netmask.addr; 01186 test.dev = dev; 01187 /** XXX: Valid netmask / unicast address test **/ 01188 01189 if(pico_tree_findKey(&Tree_dev_link, &test)) { 01190 dbg("IPv4: Trying to assign an invalid address (in use)\n"); 01191 pico_err = PICO_ERR_EADDRINUSE; 01192 return -1; 01193 } 01194 01195 /** 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) **/ 01196 new = pico_zalloc(sizeof(struct pico_ipv4_link)); 01197 if (!new) { 01198 dbg("IPv4: Out of memory!\n"); 01199 pico_err = PICO_ERR_ENOMEM; 01200 return -1; 01201 } 01202 new->address.addr = address.addr; 01203 new->netmask.addr = netmask.addr; 01204 new->dev = dev; 01205 #ifdef PICO_SUPPORT_MCAST 01206 new->MCASTGroups = pico_zalloc(sizeof(struct pico_tree)); 01207 if (!new->MCASTGroups) { 01208 pico_free(new); 01209 dbg("IPv4: Out of memory!\n"); 01210 pico_err = PICO_ERR_ENOMEM; 01211 return -1; 01212 } 01213 01214 new->MCASTGroups->root = &LEAF; 01215 new->MCASTGroups->compare = ipv4_mcast_groups_cmp; 01216 new->mcast_compatibility = PICO_IGMPV3; /* default RFC 3376 $7.2.1 */ 01217 new->mcast_last_query_interval = PICO_IGMP_QUERY_INTERVAL; 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 mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; 01232 pico_ipv4_mcast_join(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); 01233 } while(0); 01234 #endif 01235 01236 network.addr = address.addr & netmask.addr; 01237 gateway.addr = 0U; 01238 pico_ipv4_route_add(network, netmask, gateway, 1, new); 01239 pico_ipv4_to_string(ipstr, new->address.addr); 01240 dbg("Assigned ipv4 %s to device %s\n", ipstr, new->dev->name); 01241 return 0; 01242 } 01243 01244 01245 int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address) 01246 { 01247 struct pico_ipv4_link test, *found; 01248 struct pico_ip4 network; 01249 01250 if(!dev) { 01251 pico_err = PICO_ERR_EINVAL; 01252 return -1; 01253 } 01254 test.address.addr = address.addr; 01255 test.dev = dev; 01256 found = pico_tree_findKey(&Tree_dev_link, &test); 01257 if (!found) { 01258 pico_err = PICO_ERR_ENXIO; 01259 return -1; 01260 } 01261 01262 network.addr = found->address.addr & found->netmask.addr; 01263 pico_ipv4_route_del(network, found->netmask,pico_ipv4_route_get_gateway(&found->address), 1, found); 01264 #ifdef PICO_SUPPORT_MCAST 01265 do { 01266 struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw; 01267 struct pico_mcast_group *g = NULL; 01268 struct pico_tree_node * index, * _tmp; 01269 if (found == mcast_default_link) { 01270 mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ 01271 mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ 01272 mcast_gw.addr = long_be(0x00000000); 01273 mcast_default_link = NULL; 01274 pico_ipv4_route_del(mcast_addr, mcast_nm, mcast_gw, 1, found); 01275 } 01276 mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; 01277 pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); 01278 pico_tree_foreach_safe(index,found->MCASTGroups, _tmp) 01279 { 01280 g = index->keyValue; 01281 pico_tree_delete(found->MCASTGroups, g); 01282 pico_free(g); 01283 } 01284 } while(0); 01285 #endif 01286 01287 pico_tree_delete(&Tree_dev_link, found); 01288 /* XXX: pico_free(found); */ 01289 /* XXX: cleanup all routes containing the removed link */ 01290 return 0; 01291 } 01292 01293 01294 struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address) 01295 { 01296 struct pico_ipv4_link test = {0}, *found = NULL; 01297 test.address.addr = address->addr; 01298 01299 found = pico_tree_findKey(&Tree_dev_link, &test); 01300 if (!found) 01301 return NULL; 01302 else 01303 return found; 01304 } 01305 01306 struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev) 01307 { 01308 struct pico_tree_node *index = NULL; 01309 struct pico_ipv4_link *link = NULL; 01310 01311 pico_tree_foreach(index, &Tree_dev_link) 01312 { 01313 link = index->keyValue; 01314 if (link->dev == dev) 01315 return link; 01316 } 01317 return NULL; 01318 } 01319 01320 01321 struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address) 01322 { 01323 struct pico_ipv4_link test, *found; 01324 if(!address) { 01325 pico_err = PICO_ERR_EINVAL; 01326 return NULL; 01327 } 01328 test.dev = NULL; 01329 test.address.addr = address->addr; 01330 found = pico_tree_findKey(&Tree_dev_link, &test); 01331 if (!found) { 01332 pico_err = PICO_ERR_ENXIO; 01333 return NULL; 01334 } 01335 return found->dev; 01336 } 01337 01338 int pico_ipv4_rebound(struct pico_frame *f) 01339 { 01340 struct pico_ip4 dst; 01341 struct pico_ipv4_hdr *hdr; 01342 if(!f) { 01343 pico_err = PICO_ERR_EINVAL; 01344 return -1; 01345 } 01346 01347 hdr = (struct pico_ipv4_hdr *) f->net_hdr; 01348 if (!hdr) { 01349 pico_err = PICO_ERR_EINVAL; 01350 return -1; 01351 } 01352 dst.addr = hdr->src.addr; 01353 return pico_ipv4_frame_push(f, &dst, hdr->proto); 01354 } 01355 01356 static int pico_ipv4_forward(struct pico_frame *f) 01357 { 01358 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; 01359 struct pico_ipv4_route *rt; 01360 if (!hdr) { 01361 return -1; 01362 } 01363 01364 //dbg("IP> FORWARDING.\n"); 01365 rt = route_find(&hdr->dst); 01366 if (!rt) { 01367 pico_notify_dest_unreachable(f); 01368 return -1; 01369 } 01370 //dbg("ROUTE: valid..\n"); 01371 f->dev = rt->link->dev; 01372 hdr->ttl-=1; 01373 if (hdr->ttl < 1) { 01374 pico_notify_ttl_expired(f); 01375 return -1; 01376 } 01377 hdr->crc++; 01378 01379 /* check if NAT enbled on link and do NAT if so */ 01380 if (pico_ipv4_nat_isenabled_out(rt->link) == 0) 01381 pico_ipv4_nat(f, rt->link->address); 01382 01383 //dbg("Routing towards %s\n", f->dev->name); 01384 f->start = f->net_hdr; 01385 if(f->dev->eth != NULL) 01386 f->len -= PICO_SIZE_ETHHDR; 01387 pico_sendto_dev(f); 01388 return 0; 01389 01390 } 01391 01392 int pico_ipv4_is_broadcast(uint32_t addr) 01393 { 01394 struct pico_ipv4_link *link; 01395 struct pico_tree_node * index; 01396 if (addr == PICO_IP4_ANY) 01397 return 1; 01398 if (addr == PICO_IP4_BCAST) 01399 return 1; 01400 01401 pico_tree_foreach(index,&Tree_dev_link) { 01402 link = index->keyValue; 01403 if ((link->address.addr | (~link->netmask.addr)) == addr) 01404 return 1; 01405 } 01406 return 0; 01407 } 01408 01409 void pico_ipv4_unreachable(struct pico_frame *f, int err) 01410 { 01411 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 01412 #if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP 01413 f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR; 01414 pico_transport_error(f, hdr->proto, err); 01415 #endif 01416 } 01417 01418 #endif
Generated on Wed Jul 13 2022 02:20:45 by 1.7.2