/*---------------------------------------------------------------------------*/ void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst) { uint8_t best = 0; /* number of bit in common with best match */ uint8_t n = 0; uip_ds6_addr_t *matchaddr = NULL; if(!uip_is_addr_link_local(dst) && !uip_is_addr_mcast(dst)) { /* find longest match */ for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { /* Only preferred global (not link-local) addresses */ if(locaddr->isused && locaddr->state == ADDR_PREFERRED && !uip_is_addr_link_local(&locaddr->ipaddr)) { n = get_match_length(dst, &locaddr->ipaddr); if(n >= best) { best = n; matchaddr = locaddr; } } } } else { matchaddr = uip_ds6_get_link_local(ADDR_PREFERRED); } /* use the :: (unspecified address) as source if no match found */ if(matchaddr == NULL) { uip_create_unspecified(src); } else { uip_ipaddr_copy(src, &matchaddr->ipaddr); } #if UIP_CONF_LOOPBACK // FIXME: there's probably a better way to do this if(uip_is_addr_loopback(dst)) { uip_ipaddr_copy(src, dst); } #endif /* UIP_CONF_LOOPBACK */ }
/*---------------------------------------------------------------------------*/ void uip_process() { PRINTF("NEW packet\n"); /* Check validity of the IP header. */ if((UIP_IP_BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ PRINTF("Wrong IP Version\n"); goto drop; } /* * Check the size of the packet. If the size reported to us in * uip_len is smaller the size reported in the IP header, we assume * that the packet has been corrupted in transit. If the size of * uip_len is larger than the size reported in the IP packet header, * the packet has been padded and we set uip_len to the correct * value.. */ if((UIP_IP_BUF->len[0] << 8) + UIP_IP_BUF->len[1] <= uip_len) { uip_len = (UIP_IP_BUF->len[0] << 8) + UIP_IP_BUF->len[1] + UIP_IPH_LEN; /* * The length reported in the IPv6 header is the * length of the payload that follows the * header. However, uIP uses the uip_len variable * for holding the size of the entire packet, * including the IP header. For IPv4 this is not a * problem as the length field in the IPv4 header * contains the length of the entire packet. But * for IPv6 we need to add the size of the IPv6 * header (40 bytes). */ } else { PRINTF("Wrong Length\n"); goto drop; } PRINTF("IPv6 packet received from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(" to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); if(uip_is_addr_mcast(&UIP_IP_BUF->srcipaddr)){ PRINTF("Dropping packet, src is mcast\n"); goto drop; } /* * Next header field processing. In IPv6, we can have extension headers, * if present, the Hop-by-Hop Option must be processed before forwarding * the packet. */ uip_next_hdr = &UIP_IP_BUF->proto; uip_ext_len = 0; uip_ext_bitmap = 0; if (*uip_next_hdr == UIP_PROTO_HBHO) { #if UIP_CONF_IPV6_CHECKS uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_HBHO; #endif /*UIP_CONF_IPV6_CHECKS*/ switch(ext_hdr_options_process()) { case 0: /*continue*/ uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case 1: /*silently discard*/ goto drop; case 2: /* send icmp error message (created in ext_hdr_options_process) * and discard*/ goto send; } } /* TBD Some Parameter problem messages */ if(!uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr) && !uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) { if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) && !uip_is_addr_link_local(&UIP_IP_BUF->destipaddr) && !uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) && !uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr) && !uip_is_addr_loopback(&UIP_IP_BUF->destipaddr)) { /* Check MTU */ if(uip_len > UIP_LINK_MTU) { uip_icmp6_error_output(ICMP6_PACKET_TOO_BIG, 0, UIP_LINK_MTU); goto send; } /* Check Hop Limit */ if(UIP_IP_BUF->ttl <= 1) { uip_icmp6_error_output(ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); goto send; } UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1; PRINTF("Forwarding packet to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); goto send; } else { if((uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) && (!uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) && (!uip_is_addr_loopback(&UIP_IP_BUF->destipaddr)) && (!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) && (!uip_ds6_is_addr_onlink((&UIP_IP_BUF->destipaddr)))) { PRINTF("LL source address with off link destination, dropping\n"); uip_icmp6_error_output(ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR, 0); goto send; } PRINTF("Dropping packet, not for me and link local or multicast\n"); goto drop; } } while(1) { switch(*uip_next_hdr){ case UIP_PROTO_ICMP6: /* ICMPv6 */ goto icmp6_input; case UIP_PROTO_HBHO: PRINTF("Processing hbh header\n"); /* Hop by hop option header */ #if UIP_CONF_IPV6_CHECKS /* Hop by hop option header. If we saw one HBH already, drop */ if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_HBHO) { goto bad_hdr; } else { uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_HBHO; } #endif /*UIP_CONF_IPV6_CHECKS*/ switch(ext_hdr_options_process()) { case 0: /*continue*/ uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case 1: /*silently discard*/ goto drop; case 2: /* send icmp error message (created in ext_hdr_options_process) * and discard*/ goto send; } break; case UIP_PROTO_DESTO: #if UIP_CONF_IPV6_CHECKS /* Destination option header. if we saw two already, drop */ PRINTF("Processing desto header\n"); if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_DESTO1) { if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_DESTO2) { goto bad_hdr; } else{ uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_DESTO2; } } else { uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_DESTO1; } #endif /*UIP_CONF_IPV6_CHECKS*/ switch(ext_hdr_options_process()) { case 0: /*continue*/ uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case 1: /*silently discard*/ goto drop; case 2: /* send icmp error message (created in ext_hdr_options_process) * and discard*/ goto send; } break; case UIP_PROTO_ROUTING: #if UIP_CONF_IPV6_CHECKS /* Routing header. If we saw one already, drop */ if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_ROUTING) { goto bad_hdr; } else { uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_ROUTING; } #endif /*UIP_CONF_IPV6_CHECKS*/ /* * Routing Header length field is in units of 8 bytes, excluding * As per RFC2460 section 4.4, if routing type is unrecognized: * if segments left = 0, ignore the header * if segments left > 0, discard packet and send icmp error pointing * to the routing type */ PRINTF("Processing Routing header\n"); if(UIP_ROUTING_BUF->seg_left > 0) { uip_icmp6_error_output(ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, UIP_IPH_LEN + uip_ext_len + 2); goto send; } uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case UIP_PROTO_FRAG: /* Fragmentation header:call the reassembly function, then leave */ goto drop; case UIP_PROTO_NONE: goto drop; default: goto bad_hdr; } } bad_hdr: /* * RFC 2460 send error message parameterr problem, code unrecognized * next header, pointing to the next header field */ uip_icmp6_error_output(ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER, (u32_t)(uip_next_hdr - (uint8_t *)UIP_IP_BUF)); goto send; /* End of headers processing */ icmp6_input: /* This is IPv6 ICMPv6 processing code. */ PRINTF("icmp6_input: length %d\n", uip_len); #if UIP_CONF_IPV6_CHECKS /* Compute and check the ICMP header checksum */ if(uip_icmp6chksum() != 0xffff) { goto drop; } #endif /*UIP_CONF_IPV6_CHECKS*/ /* * Here we process incoming ICMPv6 packets * For echo request, we send echo reply * For ND pkts, we call the appropriate function in uip-nd6.c * We do not treat Error messages for now * If no pkt is to be sent as an answer to the incoming one, we * "goto drop". Else we just break; then at the after the "switch" * we "goto send" */ switch(UIP_ICMP_BUF->type) { case ICMP6_NS: uip_len = 0; break; case ICMP6_NA: uip_len = 0; break; case ICMP6_RS: uip_len = 0; break; case ICMP6_RA: uip_len = 0; break; case ICMP6_RPL: uip_rpl_input(); break; case ICMP6_ECHO_REQUEST: uip_icmp6_echo_request_input(); break; case ICMP6_ECHO_REPLY: /** \note We don't implement any application callback for now */ PRINTF("Received an icmp6 echo reply\n"); uip_len = 0; break; default: PRINTF("Unknown icmp6 message type %d\n", UIP_ICMP_BUF->type); uip_len = 0; break; } if(uip_len > 0) { goto send; } else { goto drop; } /* End of IPv6 ICMP processing. */ UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0x00; UIP_IP_BUF->flow = 0x00; send: PRINTF("Sending packet with length %d (%d)\n", uip_len, (UIP_IP_BUF->len[0] << 8) | UIP_IP_BUF->len[1]); /* Return and let the caller do the actual transmission. */ return; drop: uip_len = 0; uip_ext_len = 0; uip_ext_bitmap = 0; return; }