/*---------------------------------------------------------------------------*/ 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) || uip_is_addr_routable_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); } }
/*---------------------------------------------------------------------------*/ uip_ds6_addr_t * uip_ds6_addr_add(uip_ipaddr_t * ipaddr, unsigned long vlifetime, u8_t type) { if(uip_ds6_list_loop ((uip_ds6_element_t *) uip_ds6_if.addr_list, UIP_DS6_ADDR_NB, sizeof(uip_ds6_addr_t), ipaddr, 128, (uip_ds6_element_t **) & locaddr) == FREESPACE) { locaddr->isused = 1; uip_ipaddr_copy(&locaddr->ipaddr, ipaddr); if (uip_is_addr_link_local(ipaddr)) { locaddr->state = ADDR_PREFERRED; } else { locaddr->state = ADDR_TENTATIVE; } locaddr->type = type; if(vlifetime == 0) { locaddr->isinfinite = 1; } else { locaddr->isinfinite = 0; stimer_set(&locaddr->vlifetime, vlifetime); } #if UIP_CONF_ROUTER /* * If 6LoWPAN-ND optimizations are implemented, hosts do not join the * Solicited-node multicast address. */ uip_create_solicited_node(ipaddr, &loc_fipaddr); uip_ds6_maddr_add(&loc_fipaddr); #endif /* UIP_CONF_ROUTER */ return locaddr; } return NULL; }
/*---------------------------------------------------------------------------*/ u8_t uip_ds6_is_addr_onlink(uip_ipaddr_t * ipaddr) { /* * I-D.ietf-6lowpan-nd sections 5.6 - 5.7: all prefixes but the link-local * prefix are always assumed to be off-link. */ return uip_is_addr_link_local(ipaddr); }
/* * Calling code must handle when this returns 0 (e.g. link local * address can not be used). */ int uip_ds6_dad_failed(uip_ds6_addr_t *addr) { if(uip_is_addr_link_local(&addr->ipaddr)) { PRINTF("Contiki shutdown, DAD for link local address failed\n"); return 0; } uip_ds6_addr_rm(addr); return 1; }
/* * get a global address - * state = -1 => any address is ok. Otherwise state = desired state of addr. * (TENTATIVE, PREFERRED, DEPRECATED) */ uip_ds6_addr_t * uip_ds6_get_global(int8_t state) { for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if(locaddr->isused && (state == -1 || locaddr->state == state) && !(uip_is_addr_link_local(&locaddr->ipaddr))) { return locaddr; } } return NULL; }
/* * get a link local address - * state = -1 => any address is ok. Otherwise state = desired state of addr. * (TENTATIVE, PREFERRED, DEPRECATED) */ uip_ds6_addr_t * uip_ds6_get_link_local(signed char state) { for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if((locaddr->isused) && (state == -1 || locaddr->state == state) && (uip_is_addr_link_local(&locaddr->ipaddr))) { return locaddr; } } return NULL; }
/*---------------------------------------------------------------------------*/ int simple_rpl_init_dag_immediately(void) { struct uip_ds6_addr *root_if; int i; uint8_t state; uip_ipaddr_t *ipaddr = NULL; for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && state == ADDR_PREFERRED && !uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) { ipaddr = &uip_ds6_if.addr_list[i].ipaddr; } } if(ipaddr != NULL) { root_if = uip_ds6_addr_lookup(ipaddr); if(root_if != NULL) { rpl_dag_t *dag; uip_ipaddr_t prefix; rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr); dag = rpl_get_any_dag(); /* If there are routes in this dag, we remove them all as we are from now on the new dag root and the old routes are wrong */ rpl_remove_routes(dag); if(dag->instance != NULL && dag->instance->def_route != NULL) { uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } #if CONTIKI_TARGET_TRXEB1120 || CONTIKI_TARGET_ETH1120 || CONTIKI_TARGET_TRXEB2520 || CONTIKI_TARGET_TRXEB1101 || CONTIKI_TARGET_ETH1101 || CONTIKI_TARGET_ETH2520 uip_ip6addr(&prefix, 0xfc00, 0, 0xabba, 0xabba, 0, 0, 0, 0); #else /* CONTIKI_TARGET_TRXEB1120 */ uip_ip6addr(&prefix, 0xfc00, 0, 0, 0, 0, 0, 0, 0); #endif /* CONTIKI_TARGET_TRXEB1120 */ rpl_set_prefix(dag, &prefix, 64); printf("\r\nsimple_rpl_init_dag: created a new RPL dag\n"); return 0; } else { printf("\r\nsimple_rpl_init_dag: failed to create a new RPL DAG\n"); return -1; } } else { printf("\r\nsimple_rpl_init_dag: failed to create a new RPL DAG, no preferred IP address found\n"); return -2; } }
uip_ds6_addr_t * uip_ds6_get_global_br(int8_t state, uip_ds6_border_router_t *br) { for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if(locaddr->isused && (state == -1 || locaddr->state == state) && !(uip_is_addr_link_local(&locaddr->ipaddr)) && (locprefix = uip_ds6_prefix_lookup_from_ipaddr(&locaddr->ipaddr)) && locprefix->br == br) { return locaddr; } } return NULL; }
/* * get a global address - * state = -1 => any address is ok. Otherwise state = desired state of addr. * (TENTATIVE, PREFERRED, DEPRECATED) */ uip_ds6_addr_t * uip_ds6_get_global(int8_t state) { for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if(locaddr->isused && (state == -1 || locaddr->state == state) && !(uip_is_addr_link_local(&locaddr->ipaddr))) { if((!locaddr->isinfinite) && (stimestamp_expired(&locaddr->vlifetime))) { uip_ds6_addr_rm(locaddr); } else { return locaddr; } } } return NULL; }
/*---------------------------------------------------------------------------*/ uint8_t uip_ds6_is_addr_onlink(uip_ipaddr_t *ipaddr) { #if CONF_6LOWPAN_ND return uip_is_addr_link_local(ipaddr); #else /* CONF_6LOWPAN_ND */ for(locprefix = uip_ds6_prefix_list; locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; locprefix++) { if(locprefix->isused && uip_ipaddr_prefixcmp(&locprefix->ipaddr, ipaddr, locprefix->length)) { return 1; } } return 0; #endif /* CONF_6LOWPAN_ND */ }
/*---------------------------------------------------------------------------*/ static int get_global_addr(uip_ipaddr_t *addr) { int i; int state; for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { if(!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) { memcpy(addr, &uip_ds6_if.addr_list[i].ipaddr, sizeof(uip_ipaddr_t)); return 1; } } } return 0; }
/*---------------------------------------------------------------------------*/ const uip_ipaddr_t * simple_rpl_global_address(void) { int i; uint8_t state; uip_ipaddr_t *ipaddr = NULL; for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && state == ADDR_PREFERRED && !uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) { ipaddr = &uip_ds6_if.addr_list[i].ipaddr; } } return ipaddr; }
/*---------------------------------------------------------------------------*/ void uip_netif_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst) { u8_t best = 0; /* number of bit in common with best match*/ u8_t n = 0; u8_t index = 0; if(!uip_is_addr_link_local(dst) && !uip_is_addr_mcast(dst)) { for(i = 1; i < UIP_CONF_NETIF_MAX_ADDRESSES; ++i) { if(uip_netif_physical_if.addresses[i].state == PREFERRED){ n = get_match_length(dst, &(uip_netif_physical_if.addresses[i].ipaddr)); if(n >= best){ best = n; index = i; } } } } uip_ipaddr_copy(src, &(uip_netif_physical_if.addresses[index].ipaddr)); return; }
/*---------------------------------------------------------------------------*/ uip_ds6_addr_t * uip_ds6_addr_add(uip_ipaddr_t *ipaddr, unsigned long vlifetime, uint8_t type) { if(uip_ds6_list_loop ((uip_ds6_element_t *)uip_ds6_if.addr_list, UIP_DS6_ADDR_NB, sizeof(uip_ds6_addr_t), ipaddr, 128, (uip_ds6_element_t **)&locaddr) == FREESPACE) { locaddr->isused = 1; uip_ipaddr_copy(&locaddr->ipaddr, ipaddr); locaddr->type = type; if(vlifetime == 0) { locaddr->isinfinite = 1; } else { locaddr->isinfinite = 0; stimer_set(&(locaddr->vlifetime), vlifetime); } #if UIP_ND6_DEF_MAXDADNS > 0 locaddr->state = ADDR_TENTATIVE; timer_set(&locaddr->dadtimer, random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY * CLOCK_SECOND)); locaddr->dadnscount = 0; #else /* UIP_ND6_DEF_MAXDADNS > 0 */ #if UIP_CONF_6LN || UIP_CONF_6LR locaddr->state = uip_is_addr_link_local(ipaddr) ? ADDR_PREFERRED : ADDR_TENTATIVE; #else /* UIP_CONF_6LN || UIP_CONF_6LR */ locaddr->state = ADDR_PREFERRED; #endif /* UIP_CONF_6LN || UIP_CONF_6LR */ #endif /* UIP_ND6_DEF_MAXDADNS > 0 */ uip_create_solicited_node(ipaddr, &loc_fipaddr); uip_ds6_maddr_add(&loc_fipaddr); return locaddr; } return NULL; }
static int eth_output(uip_lladdr_t * src, uip_lladdr_t * dest) { if(IS_BROADCAST_ADDR(dest)) { LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: broadcast\n"); } else { LOG6LBR_LLADDR_PRINTF(PACKET, PF_OUT, dest, "eth_output: "); } //Packet filtering //---------------- if(uip_len == 0) { LOG6LBR_ERROR("eth_output: uip_len = 0\n"); return 0; } #if CETIC_6LBR_ETH_FILTER_RPL //Filter out RPL (broadcast) traffic if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_RPL) { //LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Filtering out RPL traffic\n"); return 0; } #endif //IP packet alteration //-------------------- #if CETIC_6LBR_ROUTER //Modify source address if((nvm_data.mode & CETIC_MODE_REWRITE_ADDR_MASK) != 0 && uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) && uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) { LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Update src address\n"); uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, ð_ip_local_addr); } #endif #if CETIC_6LBR_SMARTBRIDGE //Reset Hop Limit when in smart-bridge for NDP packets //TODO: Is this still needed after #4467 ? if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && (UIP_ICMP_BUF->type == ICMP6_NS || UIP_ICMP_BUF->type == ICMP6_NA || UIP_ICMP_BUF->type == ICMP6_RS || UIP_ICMP_BUF->type == ICMP6_RA)) { UIP_IP_BUF->ttl = 255; } #endif #if CETIC_6LBR_SMARTBRIDGE || CETIC_6LBR_TRANSPARENTBRIDGE //Remove ROUTER flag when in bridge mode if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_NA) { //LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Updating NA\n"); UIP_ND6_NA_BUF->flagsreserved &= ~UIP_ND6_NA_FLAG_ROUTER; } #endif //Some IP packets have link layer in them, need to change them around! mac_translateIPLinkLayer(ll_8023_type); //IP header alteration //-------------------- //Remove Hop-by-hop extension header if(uip_ext_len > 0) { extern void remove_ext_hdr(void); uint8_t proto = *((uint8_t *) UIP_IP_BUF + 40); remove_ext_hdr(); UIP_IP_BUF->proto = proto; } //Create packet header //-------------------- //Packet type BUF->type = uip_htons(UIP_ETHTYPE_IPV6); //Destination address if(IS_BROADCAST_ADDR(dest)) { BUF->dest.addr[0] = 0x33; BUF->dest.addr[1] = 0x33; BUF->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12]; BUF->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13]; BUF->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14]; BUF->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15]; } else { mac_createEthernetAddr(BUF->dest.addr, dest); } //Source address if ( src != NULL ) { mac_createEthernetAddr(BUF->src.addr, src); } else { memcpy(BUF->src.addr, eth_mac_addr, 6); } //Sending packet //-------------- LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Sending packet to Ethernet\n"); eth_drv_send(); return 1; }
static int eth_output(const uip_lladdr_t * src, const uip_lladdr_t * dest) { if(IS_BROADCAST_ADDR(dest)) { LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: broadcast\n"); } else { LOG6LBR_LLADDR_PRINTF(PACKET, PF_OUT, dest, "eth_output: "); } //Packet filtering //---------------- if(uip_len == 0) { LOG6LBR_ERROR("eth_output: uip_len = 0\n"); return 0; } if(dest && linkaddr_cmp((linkaddr_t *) & dest, (linkaddr_t *) & eth_mac64_addr)) { LOG6LBR_ERROR("ethernet_output: sending to self\n"); return 0; } #if CETIC_6LBR_ETH_FILTER_RPL //Filter out RPL (broadcast) traffic if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_RPL) { //LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Filtering out RPL traffic\n"); return 0; } #endif //IP packet alteration //-------------------- #if CETIC_6LBR_ROUTER //Modify source address if((nvm_data.mode & CETIC_MODE_REWRITE_ADDR_MASK) != 0 && uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) && uip_ipaddr_cmp(&UIP_IP_BUF->srcipaddr, &wsn_ip_local_addr)) { LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Update src address\n"); uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, ð_ip_local_addr); if(UIP_IP_BUF->proto == UIP_PROTO_UDP) { #if UIP_UDP_CHECKSUMS /* Calculate UDP checksum. */ UIP_UDP_BUF->udpchksum = 0; UIP_UDP_BUF->udpchksum = ~(uip_udpchksum()); if(UIP_UDP_BUF->udpchksum == 0) { UIP_UDP_BUF->udpchksum = 0xffff; } #endif /* UIP_UDP_CHECKSUMS */ } else if(UIP_IP_BUF->proto == UIP_PROTO_TCP) { /* Calculate TCP checksum. */ UIP_TCP_BUF->tcpchksum = 0; UIP_TCP_BUF->tcpchksum = ~(uip_tcpchksum()); } else if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6) { /* Calculate ICMP checksum. */ UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); } } #endif #if CETIC_6LBR_SMARTBRIDGE //Reset Hop Limit when in smart-bridge for NDP packets //TODO: Is this still needed after #4467 ? if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && (UIP_ICMP_BUF->type == ICMP6_NS || UIP_ICMP_BUF->type == ICMP6_NA || UIP_ICMP_BUF->type == ICMP6_RS || UIP_ICMP_BUF->type == ICMP6_RA)) { UIP_IP_BUF->ttl = 255; } #endif #if CETIC_6LBR_SMARTBRIDGE || CETIC_6LBR_TRANSPARENTBRIDGE //Remove ROUTER flag when in bridge mode if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type == ICMP6_NA) { //LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Updating NA\n"); UIP_ND6_NA_BUF->flagsreserved &= ~UIP_ND6_NA_FLAG_ROUTER; } #endif //Some IP packets have link layer in them, need to change them around! mac_translateIPLinkLayer(ll_8023_type); //IP header alteration //-------------------- #if UIP_CONF_IPV6_RPL rpl_remove_header(); #endif //Create packet header //-------------------- //Packet type BUF->type = uip_htons(UIP_ETHTYPE_IPV6); //Destination address if(IS_BROADCAST_ADDR(dest)) { BUF->dest.addr[0] = 0x33; BUF->dest.addr[1] = 0x33; BUF->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12]; BUF->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13]; BUF->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14]; BUF->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15]; } else { mac_createEthernetAddr(BUF->dest.addr, dest); } //Source address if ( src != NULL ) { mac_createEthernetAddr(BUF->src.addr, src); } else { memcpy(BUF->src.addr, eth_mac_addr, 6); } //Sending packet //-------------- LOG6LBR_PRINTF(PACKET, PF_OUT, "eth_output: Sending packet to Ethernet\n"); eth_drv_send(uip_buf, uip_len + UIP_LLH_LEN); return 1; }
/*---------------------------------------------------------------------------*/ 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; }
/* *hc1 compression */ void LoWPANCmd::compress_hdr_hc1() { /* * Check if all the assumptions for full compression * are valid : */ if(UIP_IP_BUF->vtc != 0x60 || UIP_IP_BUF->tcflow != 0 || UIP_IP_BUF->flow != 0 || !uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) || !uip_is_addr_mac_addr_based(&UIP_IP_BUF->srcipaddr, &src_mac) || (UIP_IP_BUF->proto != UIP_PROTO_ICMP6 && UIP_IP_BUF->proto != UIP_PROTO_UDP && UIP_IP_BUF->proto != UIP_PROTO_TCP)) { /* * IPV6 DISPATCH * Something cannot be compressed, use IPV6 DISPATCH, * compress nothing, copy IPv6 header in rime buffer */ *rime_ptr = LOWPAN_DISPATCH_IPV6; rime_hdr_len += LOWPAN_IPV6_HDR_LEN; memcpy(rime_ptr + rime_hdr_len,UIP_IP_BUF,UIP_IPH_LEN); rime_hdr_len += UIP_IPH_LEN; uncomp_hdr_len = UIP_IPH_LEN; } else { /* * HC1 DISPATCH * maximum compresssion: * All fields in the IP header but Hop Limit are elided * If next header is UDP, we compress UDP header using HC2 */ RIME_HC1_PTR[RIME_HC1_DISPATCH] = LOWPAN_DISPATCH_HC1; uncomp_hdr_len += UIP_IPH_LEN; switch(UIP_IP_BUF->proto) { case UIP_PROTO_ICMP6: /* HC1 encoding and ttl */ RIME_HC1_PTR[RIME_HC1_ENCODING] = 0xFC; RIME_HC1_PTR[RIME_HC1_TTL] = UIP_IP_BUF->ttl; if (!uip_is_addr_link_local(&UIP_IP_BUF->destipaddr) || !uip_is_addr_mac_addr_based(&UIP_IP_BUF->destipaddr,&dest_mac)) { RIME_HC1_PTR[RIME_HC1_ENCODING] = RIME_HC1_PTR[RIME_HC1_ENCODING]&0xCF; memcpy(rime_ptr + rime_hdr_len+LOWPAN_HC1_HDR_LEN,(char*)UIP_IP_BUF+24,16); rime_hdr_len += 16; } rime_hdr_len += LOWPAN_HC1_HDR_LEN; break; case UIP_PROTO_TCP: /* HC1 encoding and ttl */ RIME_HC1_PTR[RIME_HC1_ENCODING] = 0xFE; RIME_HC1_PTR[RIME_HC1_TTL] = UIP_IP_BUF->ttl; rime_hdr_len += LOWPAN_HC1_HDR_LEN; break; case UIP_PROTO_UDP: /* * try to compress UDP header (we do only full compression). * This is feasible if both src and dest ports are between * SICSLOWPAN_UDP_PORT_MIN and SICSLOWPAN_UDP_PORT_MIN + 15 */ if(HTONS(UIP_UDP_BUF->srcport) >= LOWPAN_UDP_PORT_MIN && HTONS(UIP_UDP_BUF->srcport) < LOWPAN_UDP_PORT_MAX && HTONS(UIP_UDP_BUF->destport) >= LOWPAN_UDP_PORT_MIN && HTONS(UIP_UDP_BUF->destport) < LOWPAN_UDP_PORT_MAX) { /* HC1 encoding */ RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_HC1_ENCODING] = 0xFB; /* HC_UDP encoding, ttl, src and dest ports, checksum */ RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_UDP_ENCODING] = 0xE0; RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_TTL] = UIP_IP_BUF->ttl; RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_PORTS] = (u8_t)((HTONS(UIP_UDP_BUF->srcport)-LOWPAN_UDP_PORT_MIN) << 4) + (u8_t)((HTONS(UIP_UDP_BUF->destport)-LOWPAN_UDP_PORT_MIN)); /*RIME_HC1_HC_UDP_BUF->udpchksum = UIP_UDP_BUF->udpchksum; */ memcpy(&RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_CHKSUM], &UIP_UDP_BUF->udpchksum, 2); rime_hdr_len += LOWPAN_HC1_HC_UDP_HDR_LEN; uncomp_hdr_len += UIP_UDPH_LEN; } else { /* HC1 encoding and ttl */ RIME_HC1_PTR[RIME_HC1_ENCODING] = 0xFA; RIME_HC1_PTR[RIME_HC1_TTL] = UIP_IP_BUF->ttl; rime_hdr_len += LOWPAN_HC1_HDR_LEN; } break; } } }
/* * Process a Router Advertisement * * - Possible actions when receiving a RA: add router to router list, * recalculate reachable time, update link hop limit, update retrans timer. * - If MTU option: update MTU. * - If SLLAO option: update entry in neighbor cache * - If prefix option: start autoconf, add prefix to prefix list */ void ra_input(void) { PRINTF("Received RA from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); #if UIP_CONF_IPV6_CHECKS if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (!uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) || (UIP_ICMP_BUF->icode != 0)) { PRINTF("RA received is bad"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ if(UIP_ND6_RA_BUF->cur_ttl != 0) { uip_ds6_if.cur_hop_limit = UIP_ND6_RA_BUF->cur_ttl; PRINTF("uip_ds6_if.cur_hop_limit %u\n", uip_ds6_if.cur_hop_limit); } if(UIP_ND6_RA_BUF->reachable_time != 0) { if(uip_ds6_if.base_reachable_time != uip_ntohl(UIP_ND6_RA_BUF->reachable_time)) { uip_ds6_if.base_reachable_time = uip_ntohl(UIP_ND6_RA_BUF->reachable_time); uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time(); } } if(UIP_ND6_RA_BUF->retrans_timer != 0) { uip_ds6_if.retrans_timer = uip_ntohl(UIP_ND6_RA_BUF->retrans_timer); } /* Options processing */ nd6_opt_offset = UIP_ND6_RA_LEN; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("RA received is bad"); goto discard; } switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_SLLAO: PRINTF("Processing SLLAO option in RA\n"); nd6_opt_llao = (uint8_t *) UIP_ND6_OPT_HDR_BUF; nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); if(nbr == NULL) { nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 1, NBR_STALE); } else { uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); if(nbr->state == NBR_INCOMPLETE) { nbr->state = NBR_STALE; } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); nbr->state = NBR_STALE; } nbr->isrouter = 1; } break; case UIP_ND6_OPT_MTU: PRINTF("Processing MTU option in RA\n"); uip_ds6_if.link_mtu = uip_ntohl(((uip_nd6_opt_mtu *) UIP_ND6_OPT_HDR_BUF)->mtu); break; case UIP_ND6_OPT_PREFIX_INFO: PRINTF("Processing PREFIX option in RA\n"); nd6_opt_prefix_info = (uip_nd6_opt_prefix_info *) UIP_ND6_OPT_HDR_BUF; if((uip_ntohl(nd6_opt_prefix_info->validlt) >= uip_ntohl(nd6_opt_prefix_info->preferredlt)) && (!uip_is_addr_link_local(&nd6_opt_prefix_info->prefix))) { /* on-link flag related processing */ if(nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_ONLINK) { prefix = uip_ds6_prefix_lookup(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen); if(prefix == NULL) { if(nd6_opt_prefix_info->validlt != 0) { if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen, uip_ntohl(nd6_opt_prefix_info-> validlt)); } else { prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen, 0); } } } else { switch (nd6_opt_prefix_info->validlt) { case 0: uip_ds6_prefix_rm(prefix); break; case UIP_ND6_INFINITE_LIFETIME: prefix->isinfinite = 1; break; default: PRINTF("Updating timer of prefix"); PRINT6ADDR(&prefix->ipaddr); PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); stimer_set(&prefix->vlifetime, uip_ntohl(nd6_opt_prefix_info->validlt)); prefix->isinfinite = 0; break; } } } /* End of on-link flag related processing */ /* autonomous flag related processing */ if((nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_AUTONOMOUS) && (nd6_opt_prefix_info->validlt != 0) && (nd6_opt_prefix_info->preflen == UIP_DEFAULT_PREFIX_LEN)) { uip_ipaddr_copy(&ipaddr, &nd6_opt_prefix_info->prefix); uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); addr = uip_ds6_addr_lookup(&ipaddr); if((addr != NULL) && (addr->type == ADDR_AUTOCONF)) { if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { /* The processing below is defined in RFC4862 section 5.5.3 e */ if((uip_ntohl(nd6_opt_prefix_info->validlt) > 2 * 60 * 60) || (uip_ntohl(nd6_opt_prefix_info->validlt) > stimer_remaining(&addr->vlifetime))) { PRINTF("Updating timer of address"); PRINT6ADDR(&addr->ipaddr); PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); stimer_set(&addr->vlifetime, uip_ntohl(nd6_opt_prefix_info->validlt)); } else { stimer_set(&addr->vlifetime, 2 * 60 * 60); PRINTF("Updating timer of address "); PRINT6ADDR(&addr->ipaddr); PRINTF("new value %lu\n", (unsigned long)(2 * 60 * 60)); } addr->isinfinite = 0; } else { addr->isinfinite = 1; } } else { if(uip_ntohl(nd6_opt_prefix_info->validlt) == UIP_ND6_INFINITE_LIFETIME) { uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); } else { uip_ds6_addr_add(&ipaddr, uip_ntohl(nd6_opt_prefix_info->validlt), ADDR_AUTOCONF); } } } /* End of autonomous flag related processing */ } break; default: PRINTF("ND option not supported in RA"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); if(UIP_ND6_RA_BUF->router_lifetime != 0) { if(nbr != NULL) { nbr->isrouter = 1; } if(defrt == NULL) { uip_ds6_defrt_add(&UIP_IP_BUF->srcipaddr, (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); } else { stimer_set(&(defrt->lifetime), (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); } } else { if(defrt != NULL) { uip_ds6_defrt_rm(defrt); } } #if UIP_CONF_IPV6_QUEUE_PKT /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state * and we got a SLLAO), check if we had buffered a pkt for it */ /* if((nbr != NULL) && (nbr->queue_buf_len != 0)) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; }*/ if(nbr != NULL && uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); return; } #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: uip_len = 0; return; }
/** * \brief Performs periodic tasks for 6LP-GW variable management, such as * processing of neighbor lifetimes and DAD timers */ void pgw_periodic() { /* periodic processing of contexts */ for(loccontext = pgw_addr_context_table; loccontext < pgw_addr_context_table + SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; loccontext++) { if (loccontext->state != NOT_IN_USE) { if (stimer_expired(&loccontext->vlifetime)) { switch(loccontext->state) { case IN_USE_UNCOMPRESS_ONLY: loccontext->state = IN_USE_COMPRESS; stimer_set(&loccontext->vlifetime, PGW_CONTEXT_LIFETIME); context_chaged = 1; break; case IN_USE_COMPRESS: loccontext->state = EXPIRED; if (loccontext->vlifetime.interval > PGW_MIN_CONTEXT_CHANGE_DELAY) { stimer_reset(&loccontext->vlifetime); } else { /* This way we make sure that, if the context is eventually deleted, * No other context will use its id in a period of at least * MIN_CONTEXT_CHANGE_DELAY */ stimer_set(&loccontext->vlifetime, PGW_MIN_CONTEXT_CHANGE_DELAY); } context_chaged = 1; break; case EXPIRED: pgw_context_rm(loccontext); break; } } } } /* periodic processing of neighbors */ for(locnbr = pgw_6ln_cache; locnbr < pgw_6ln_cache + MAX_6LOWPAN_NEIGHBORS; locnbr++) { if(locnbr->isused) { /* * If the reachable timer is expired, we delete the NCE, * regardless of the NCE's state. */ if(stimer_expired(&(locnbr->reachable))) { /* I-D.ietf-6lowpan-nd: Should the Registration Lifetime in a NCE expire, * then the router MUST delete the cache entry. */ pgw_nbr_rm(locnbr); } else if ((locnbr->state == PGW_TENTATIVE) && (!uip_is_addr_link_local(&locnbr->ipaddr))) { if ((locnbr->dadnscount <= PGW_MAX_DAD_NS) && (timer_expired(&locnbr->dadtimer))) { pgw_dad(locnbr); /* If we found a neighbor requiring DAD, perform it. If there were * more neighbors requiring it, we'll do it in further invocations */ return; } } } } etimer_reset(&pgw_timer_periodic); return; }