void tcpip_ipv6_output(void) { uip_ds6_nbr_t *nbr = NULL; uip_ipaddr_t *nexthop; if(uip_len == 0) { return; } if(uip_len > UIP_LINK_MTU) { UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_len = 0; return; } if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){ UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_len = 0; return; } if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { /* Next hop determination */ nbr = NULL; /* We first check if the destination address is on our immediate link. If so, we simply use the destination address as our nexthop address. */ if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){ nexthop = &UIP_IP_BUF->destipaddr; } else { uip_ds6_route_t *route; /* Check if we have a route to the destination address. */ route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); /* No route was found - we send to the default route instead. */ if(route == NULL) { PRINTF("tcpip_ipv6_output: no route found, using default route\n"); nexthop = uip_ds6_defrt_choose(); if(nexthop == NULL) { #ifdef UIP_FALLBACK_INTERFACE PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40)); if(uip_ext_len > 0) { extern void remove_ext_hdr(void); uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40); remove_ext_hdr(); /* This should be copied from the ext header... */ UIP_IP_BUF->proto = proto; } UIP_FALLBACK_INTERFACE.output(); #else PRINTF("tcpip_ipv6_output: Destination off-link but no route\n"); #endif /* !UIP_FALLBACK_INTERFACE */ uip_len = 0; return; } } else { /* A route was found, so we look up the nexthop neighbor for the route. */ nexthop = uip_ds6_route_nexthop(route); /* If the nexthop is dead, for example because the neighbor never responded to link-layer acks, we drop its route. */ if(nexthop == NULL) { #if UIP_CONF_IPV6_RPL /* If we are running RPL, and if we are the root of the network, we'll trigger a global repair berfore we remove the route. */ rpl_dag_t *dag; rpl_instance_t *instance; dag = (rpl_dag_t *)route->state.dag; if(dag != NULL) { instance = dag->instance; rpl_repair_root(instance->instance_id); } #endif /* UIP_CONF_RPL */ uip_ds6_route_rm(route); /* We don't have a nexthop to send the packet to, so we drop it. */ return; } } #if TCPIP_CONF_ANNOTATE_TRANSMISSIONS if(nexthop != NULL) { static uint8_t annotate_last; static uint8_t annotate_has_last = 0; if(annotate_has_last) { printf("#L %u 0; red\n", annotate_last); } printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); annotate_last = nexthop->u8[sizeof(uip_ipaddr_t) - 1]; annotate_has_last = 1; } #endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */ } /* End of next hop determination */ #if UIP_CONF_IPV6_RPL if(rpl_update_header_final(nexthop)) { uip_len = 0; return; } #endif /* UIP_CONF_IPV6_RPL */ nbr = uip_ds6_nbr_lookup(nexthop); if(nbr == NULL) { #if UIP_ND6_SEND_NA if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) { uip_len = 0; return; } else { #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /* RFC4861, 7.2.2: * "If the source address of the packet prompting the solicitation is the * same as one of the addresses assigned to the outgoing interface, that * address SHOULD be placed in the IP Source Address of the outgoing * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used."*/ if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)){ uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr); } else { uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); } stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); nbr->nscount = 1; } #endif /* UIP_ND6_SEND_NA */ } else { #if UIP_ND6_SEND_NA if(nbr->state == NBR_INCOMPLETE) { PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit and set the destination nbr to nbr. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } /* Send in parallel if we are running NUD (nbc state is either STALE, DELAY, or PROBE). See RFC 4861, section 7.3.3 on node behavior. */ if(nbr->state == NBR_STALE) { nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n"); } #endif /* UIP_ND6_SEND_NA */ tcpip_output(uip_ds6_nbr_get_ll(nbr)); #if UIP_CONF_IPV6_QUEUE_PKT /* * Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves * to STALE, and you must both send a NA and the queued packet. */ if(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); tcpip_output(uip_ds6_nbr_get_ll(nbr)); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } return; } printf("########### Now multicast\n"); // now check for transient site local mcast address. // these addresses should be forwarded on the rpl-border-router if(uip_is_addr_mcast_site_local(&UIP_IP_BUF->destipaddr) && uip_is_addr_mcast_transient(&UIP_IP_BUF->destipaddr)) { printf("##### SITE LOCAL TRANSIENT MCAST ADDRESS!\n"); } /* Multicast IP destination address. */ tcpip_output(NULL); uip_len = 0; uip_ext_len = 0; }
static void ns_input(void) { uint8_t flags; PRINTF("Received NS from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(" to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF(" with target address"); PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NS_BUF->tgtipaddr)); 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_mcast(&UIP_ND6_NS_BUF->tgtipaddr)) || (UIP_ICMP_BUF->icode != 0)) { PRINTF("NS received is bad\n"); goto discard; } #endif /* UIP_CONF_IPV6_CHECKS */ /* Options processing */ nd6_opt_llao = NULL; nd6_opt_offset = UIP_ND6_NS_LEN; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { #if UIP_CONF_IPV6_CHECKS if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("NS received is bad\n"); goto discard; } #endif /* UIP_CONF_IPV6_CHECKS */ switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_SLLAO: nd6_opt_llao = &uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]; #if UIP_CONF_IPV6_CHECKS /* There must be NO option in a DAD NS */ if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { PRINTF("NS received is bad\n"); goto discard; } else { #endif /*UIP_CONF_IPV6_CHECKS */ nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); if(nbr == NULL) { uip_lladdr_t lladdr_aligned; extract_lladdr_aligned(&lladdr_aligned); uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 0, NBR_STALE); } else { uip_lladdr_t *lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr); 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; } else { if(nbr->state == NBR_INCOMPLETE) { nbr->state = NBR_STALE; } } } #if UIP_CONF_IPV6_CHECKS } #endif /*UIP_CONF_IPV6_CHECKS */ break; default: PRINTF("ND option not supported in NS"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr); if(addr != NULL) { #if UIP_ND6_DEF_MAXDADNS > 0 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { /* DAD CASE */ #if UIP_CONF_IPV6_CHECKS if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) { PRINTF("NS received is bad\n"); goto discard; } #endif /* UIP_CONF_IPV6_CHECKS */ if(addr->state != ADDR_TENTATIVE) { uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr); uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); flags = UIP_ND6_NA_FLAG_OVERRIDE; goto create_na; } else { /** \todo if I sent a NS before him, I win */ uip_ds6_dad_failed(addr); goto discard; } #else /* UIP_ND6_DEF_MAXDADNS > 0 */ if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { /* DAD CASE */ goto discard; #endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } #if UIP_CONF_IPV6_CHECKS if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) { /** * \NOTE do we do something here? we both are using the same address. * If we are doing dad, we could cancel it, though we should receive a * NA in response of DAD NS we sent, hence DAD will fail anyway. If we * were not doing DAD, it means there is a duplicate in the network! */ PRINTF("NS received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ /* Address resolution case */ if(uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) { uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr); uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr); flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE; goto create_na; } /* NUD CASE */ if(uip_ds6_addr_lookup(&UIP_IP_BUF->destipaddr) == addr) { uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr); uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr); flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE; goto create_na; } else { #if UIP_CONF_IPV6_CHECKS PRINTF("NS received is bad\n"); goto discard; #endif /* UIP_CONF_IPV6_CHECKS */ } } else { goto discard; } create_na: /* If the node is a router it should set R flag in NAs */ #if UIP_CONF_ROUTER flags = flags | UIP_ND6_NA_FLAG_ROUTER; #endif uip_ext_len = 0; UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0; UIP_IP_BUF->flow = 0; UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */ UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; UIP_IP_BUF->proto = UIP_PROTO_ICMP6; UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; UIP_ICMP_BUF->type = ICMP6_NA; UIP_ICMP_BUF->icode = 0; UIP_ND6_NA_BUF->flagsreserved = flags; memcpy(&UIP_ND6_NA_BUF->tgtipaddr, &addr->ipaddr, sizeof(uip_ipaddr_t)); create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN], UIP_ND6_OPT_TLLAO); UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; UIP_STAT(++uip_stat.nd6.sent); PRINTF("Sending NA to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF(" from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(" with target address "); PRINT6ADDR(&UIP_ND6_NA_BUF->tgtipaddr); PRINTF("\n"); return; discard: uip_clear_buf(); return; } #endif /* UIP_ND6_SEND_NA */ /*------------------------------------------------------------------*/ void uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt) { uip_ext_len = 0; UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0; UIP_IP_BUF->flow = 0; UIP_IP_BUF->proto = UIP_PROTO_ICMP6; UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; if(dest == NULL) { uip_create_solicited_node(tgt, &UIP_IP_BUF->destipaddr); } else { uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest); } UIP_ICMP_BUF->type = ICMP6_NS; UIP_ICMP_BUF->icode = 0; UIP_ND6_NS_BUF->reserved = 0; uip_ipaddr_copy((uip_ipaddr_t *) &UIP_ND6_NS_BUF->tgtipaddr, tgt); UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */ /* * check if we add a SLLAO option: for DAD, MUST NOT, for NUD, MAY * (here yes), for Address resolution , MUST */ if(!(uip_ds6_is_my_addr(tgt))) { if(src != NULL) { uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, src); } else { uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); } if (uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { PRINTF("Dropping NS due to no suitable source address\n"); uip_clear_buf(); return; } UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN; create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NS_LEN], UIP_ND6_OPT_SLLAO); uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN; } else { uip_create_unspecified(&UIP_IP_BUF->srcipaddr); UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NS_LEN; uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN; } UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); UIP_STAT(++uip_stat.nd6.sent); PRINTF("Sending NS to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("with target address"); PRINT6ADDR(tgt); PRINTF("\n"); return; }
/*---------------------------------------------------------------------------*/ void uip_nd6_rs_input(void) { PRINTF("Received RS 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 /* * Check hop limit / icmp code * target address must not be multicast * if the NA is solicited, dest must not be multicast */ if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0)) { PRINTF("RS received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ /* Only valid option is Source Link-Layer Address option any thing else is discarded */ nd6_opt_offset = UIP_ND6_RS_LEN; nd6_opt_llao = NULL; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { #if UIP_CONF_IPV6_CHECKS if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("RS received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_SLLAO: nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; break; default: PRINTF("ND option not supported in RS\n"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } /* Options processing: only SLLAO */ if(nd6_opt_llao != NULL) { #if UIP_CONF_IPV6_CHECKS if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { PRINTF("RS received is bad\n"); goto discard; } else { #endif /*UIP_CONF_IPV6_CHECKS */ if((nbr = uip_ds6_nbr_lookup(ds6_neighbors,&UIP_IP_BUF->srcipaddr)) == NULL) { /* we need to add the neighbor */ uip_ds6_nbr_add(ds6_neighbors,&UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 0, NBR_STALE); } else { /* If LL address changed, set neighbor state to stale */ if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], uip_ds6_nbr_get_ll(ds6_neighbors, nbr), UIP_LLADDR_LEN) != 0) { uip_ds6_nbr_t nbr_data = *nbr; uip_ds6_nbr_rm(ds6_neighbors, nbr); nbr = uip_ds6_nbr_add(ds6_neighbors,&UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 0, NBR_STALE); nbr->reachable = nbr_data.reachable; nbr->sendns = nbr_data.sendns; nbr->nscount = nbr_data.nscount; } nbr->isrouter = 0; } #if UIP_CONF_IPV6_CHECKS } #endif /*UIP_CONF_IPV6_CHECKS */ } /* Schedule a sollicited RA */ uip_ds6_send_ra_sollicited(); discard: uip_len = 0; return; }
/*---------------------------------------------------------------------------*/ void uip_nd6_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(ds6_neighbors,&UIP_IP_BUF->srcipaddr); if(nbr == NULL) { nbr = uip_ds6_nbr_add(ds6_neighbors, &UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 1, NBR_STALE); } else { if(nbr->state == NBR_INCOMPLETE) { nbr->state = NBR_STALE; } uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_neighbors, nbr); 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; }
/*------------------------------------------------------------------*/ void uip_nd6_na_input(void) { uint8_t is_llchange; uint8_t is_router; uint8_t is_solicited; uint8_t is_override; PRINTF("Received NA from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("with target address"); PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NA_BUF->tgtipaddr)); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); /* * booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40, 0x20 * but it works. Be careful though, do not use tests such as is_router == 1 */ is_llchange = 0; is_router = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_ROUTER)); is_solicited = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED)); is_override = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE)); #if UIP_CONF_IPV6_CHECKS if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0) || (uip_is_addr_mcast(&UIP_ND6_NA_BUF->tgtipaddr)) || (is_solicited && uip_is_addr_mcast(&UIP_IP_BUF->destipaddr))) { PRINTF("NA received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ /* Options processing: we handle TLLAO, and must ignore others */ nd6_opt_offset = UIP_ND6_NA_LEN; nd6_opt_llao = NULL; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { #if UIP_CONF_IPV6_CHECKS if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("NA received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_TLLAO: nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; break; default: PRINTF("ND option not supported in NA\n"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); /* Message processing, including TLLAO if any */ if(addr != NULL) { #if UIP_ND6_DEF_MAXDADNS > 0 if(addr->state == ADDR_TENTATIVE) { uip_ds6_dad_failed(addr); } #endif /*UIP_ND6_DEF_MAXDADNS > 0 */ PRINTF("NA received is bad\n"); goto discard; } else { uip_lladdr_t *lladdr; nbr = uip_ds6_nbr_lookup(ds6_neighbors,&UIP_ND6_NA_BUF->tgtipaddr); lladdr = uip_ds6_nbr_get_ll(ds6_neighbors, nbr); if(nbr == NULL) { goto discard; } if(nd6_opt_llao != 0) { is_llchange = memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], (void *)lladdr, UIP_LLADDR_LEN); } if(nbr->state == NBR_INCOMPLETE) { if(nd6_opt_llao == NULL) { goto discard; } memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); if(is_solicited) { nbr->state = NBR_REACHABLE; nbr->nscount = 0; /* reachable time is stored in ms */ stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000); } else { nbr->state = NBR_STALE; } nbr->isrouter = is_router; } else { if(!is_override && is_llchange) { if(nbr->state == NBR_REACHABLE) { nbr->state = NBR_STALE; } goto discard; } else { if(is_override || (!is_override && nd6_opt_llao != 0 && !is_llchange) || nd6_opt_llao == 0) { if(nd6_opt_llao != 0) { memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); } if(is_solicited) { nbr->state = NBR_REACHABLE; /* reachable time is stored in ms */ stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000); } else { if(nd6_opt_llao != 0 && is_llchange) { nbr->state = NBR_STALE; } } } } if(nbr->isrouter && !is_router) { defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); if(defrt != NULL) { uip_ds6_defrt_rm(defrt); } } nbr->isrouter = is_router; } } #if UIP_CONF_IPV6_QUEUE_PKT /* The nbr is now reachable, check if we had buffered a pkt for it */ /*if(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(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; }
/*---------------------------------------------------------------------------*/ const uip_lladdr_t * uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr) { uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr); return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL; }
static PT_THREAD(generate_network(struct httpd_state *s)) { static int i; static uip_ds6_route_t *r; static uip_ds6_defrt_t *dr; static uip_ds6_nbr_t *nbr; #if CETIC_6LBR_WITH_MULTICAST static uip_mcast6_route_t *mcast_route; #endif #if RPL_WITH_NON_STORING static rpl_ns_node_t *link; #endif PSOCK_BEGIN(&s->sout); add("<br /><h2>Addresses</h2><pre>"); SEND_STRING(&s->sout, buf); reset_buf(); for(i = 0; i < UIP_DS6_ADDR_NB; i++) { if(uip_ds6_if.addr_list[i].isused) { ipaddr_add(&uip_ds6_if.addr_list[i].ipaddr); add(" "); add_address_type(uip_ds6_if.addr_list[i].type); add(" "); add_address_state(uip_ds6_if.addr_list[i].state); if(!uip_ds6_if.addr_list[i].isinfinite) { add(" %u s", stimer_remaining(&uip_ds6_if.addr_list[i].vlifetime)); } add("\n"); SEND_STRING(&s->sout, buf); reset_buf(); } } add("</pre><h2>Multicast groups</h2><pre>"); for(i = 0; i < UIP_DS6_MADDR_NB; i++) { if(uip_ds6_if.maddr_list[i].isused) { ipaddr_add(&uip_ds6_if.maddr_list[i].ipaddr); add("\n"); SEND_STRING(&s->sout, buf); reset_buf(); } } add("</pre><h2>Prefixes</h2><pre>"); for(i = 0; i < UIP_DS6_PREFIX_NB; i++) { if(uip_ds6_prefix_list[i].isused) { ipaddr_add(&uip_ds6_prefix_list[i].ipaddr); #if UIP_CONF_ROUTER if(uip_ds6_prefix_list[i].advertise) { add(" Adv"); } #else if(uip_ds6_prefix_list[i].isinfinite) { add(" Inf"); } #endif add("\n"); } } SEND_STRING(&s->sout, buf); reset_buf(); #if CETIC_6LBR_WITH_IP64 if((nvm_data.global_flags & CETIC_GLOBAL_IP64) != 0) { add("</pre><h2>IP64</h2><pre>"); if((nvm_data.eth_ip64_flags & CETIC_6LBR_IP64_DHCP) == 0 || ip64_hostaddr_is_configured()) { add("Address : "); ip4addr_add(ip64_get_hostaddr()); add("<br />"); add("Netmask : "); ip4addr_add(ip64_get_netmask()); add("<br />"); add("Gateway : "); ip4addr_add(ip64_get_draddr()); add("<br />"); if((nvm_data.eth_ip64_flags & CETIC_6LBR_IP64_DHCP) != 0) { add("DHCP Server : "); ip4addr_add_u8(cetic_6lbr_ip64_dhcp_state->serverid); add("<br />"); add("DHCP lease time : %d s<br />", uip_ntohs(cetic_6lbr_ip64_dhcp_state->lease_time[0])*65536ul + uip_ntohs(cetic_6lbr_ip64_dhcp_state->lease_time[1])); } } else { add("Waiting configuration<br />"); } SEND_STRING(&s->sout, buf); reset_buf(); } #endif add("</pre><h2>Neighbors</h2><pre>"); for(nbr = nbr_table_head(ds6_neighbors); nbr != NULL; nbr = nbr_table_next(ds6_neighbors, nbr)) { if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) { add("[<a href=\"nbr-rm?"); ipaddr_add(&nbr->ipaddr); add("\">del</a>] "); } #if CETIC_6LBR_NODE_CONFIG_HAS_NAME if ( node_config_loaded ) { add("%s : ", node_config_get_name(node_config_find_by_lladdr(uip_ds6_nbr_get_ll(nbr)))); } #endif ipaddr_add(&nbr->ipaddr); add(" "); lladdr_add(uip_ds6_nbr_get_ll(nbr)); add(" "); add_network_cases(nbr->state); #if UIP_SWITCH_LOOKUP if(nbr->ifindex != NETWORK_ITF_UNKNOWN) { add(" if:%u", nbr->ifindex); } #endif add("\n"); SEND_STRING(&s->sout, buf); reset_buf(); } add("</pre><h2>Routes</h2><pre>"); SEND_STRING(&s->sout, buf); reset_buf(); for(r = uip_ds6_route_head(), i = 0; r != NULL; r = uip_ds6_route_next(r), ++i) { if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) { add("[<a href=\"route-rm?"); ipaddr_add(&r->ipaddr); add("\">del</a>] "); } #if CETIC_6LBR_NODE_CONFIG_HAS_NAME if ( node_config_loaded ) { add("%s (", node_config_get_name(node_config_find_by_ip(&r->ipaddr))); ipaddr_add(&r->ipaddr); add("/%u) via ", r->length); } else { ipaddr_add(&r->ipaddr); add("/%u via ", r->length); } if ( node_config_loaded ) { add("%s (", node_config_get_name(node_config_find_by_ip(uip_ds6_route_nexthop(r)))); ipaddr_add(uip_ds6_route_nexthop(r)); add(")"); } else { ipaddr_add(uip_ds6_route_nexthop(r)); } #else ipaddr_add(&r->ipaddr); add("/%u via ", r->length); ipaddr_add(uip_ds6_route_nexthop(r)); #endif #if CETIC_6LBR_WITH_RPL if(r->state.lifetime != RPL_ROUTE_INFINITE_LIFETIME) { #else if(r->neighbor_routes != NULL) { #endif add(" %lu s\n", r->state.lifetime); } else { add("Inf\n"); } SEND_STRING(&s->sout, buf); reset_buf(); } #if RPL_WITH_NON_STORING add("</pre><h2>Links</h2><pre>"); for(link = rpl_ns_node_head(); link != NULL; link = rpl_ns_node_next(link)) { if(link->parent != NULL) { uip_ipaddr_t child_ipaddr; uip_ipaddr_t parent_ipaddr; rpl_ns_get_node_global_addr(&child_ipaddr, link); rpl_ns_get_node_global_addr(&parent_ipaddr, link->parent); #if CETIC_6LBR_NODE_CONFIG_HAS_NAME if ( node_config_loaded ) { add("%s (", node_config_get_name(node_config_find_by_ip(&child_ipaddr))); ipaddr_add(&child_ipaddr); add(") via "); } else { ipaddr_add(&child_ipaddr); add(" via "); } if ( node_config_loaded ) { add("%s (", node_config_get_name(node_config_find_by_ip(&parent_ipaddr))); ipaddr_add(&parent_ipaddr); add(")"); } else { ipaddr_add(&parent_ipaddr); } #else ipaddr_add(&child_ipaddr); add(" via "); ipaddr_add(&parent_ipaddr); #endif add(" %lu s\n", link->lifetime); SEND_STRING(&s->sout, buf); reset_buf(); } } #endif #if CETIC_6LBR_WITH_MULTICAST add("</pre><h2>Routed multicast groups</h2><pre>"); for(mcast_route = uip_mcast6_route_list_head(), i = 0; mcast_route != NULL; mcast_route = list_item_next(mcast_route), ++i) { if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) { add("[<a href=\"mcast-rm?"); ipaddr_add(&mcast_route->group); add("\">del</a>] "); } ipaddr_add(&mcast_route->group); add(" %lu s\n", mcast_route->lifetime); SEND_STRING(&s->sout, buf); reset_buf(); } #endif add("</pre><h2>Default Routers</h2><pre>"); for(dr = uip_ds6_defrt_head(); dr != NULL; dr = list_item_next(r)) { ipaddr_add(&dr->ipaddr); if(dr->isinfinite) { add(" Inf"); } else { add(" %u s", stimer_remaining(&dr->lifetime)); } add("\n"); SEND_STRING(&s->sout, buf); reset_buf(); } #if UIP_CONF_DS6_ROUTE_INFORMATION add("</pre><h2>Route info</h2><pre>"); for(i = 0; i < UIP_DS6_ROUTE_INFO_NB; i++) { if(uip_ds6_route_info_list[i].isused) { ipaddr_add(&uip_ds6_route_info_list[i].ipaddr); add("/%u (%x) %u s\n", uip_ds6_route_info_list[i].length, uip_ds6_route_info_list[i].flags, uip_ds6_route_info_list[i].lifetime); } } SEND_STRING(&s->sout, buf); reset_buf(); #endif add("</pre><h2>DNS server</h2><pre>"); //Note: Currently we assume only one DNS server uip_ipaddr_t * dns = uip_nameserver_get(0); if(!uip_is_addr_unspecified(dns)) { ipaddr_add(dns); add(" %u s\n", uip_nameserver_next_expiration()); } SEND_STRING(&s->sout, buf); reset_buf(); #if CETIC_6LBR_WITH_IP64 if((nvm_data.global_flags & CETIC_GLOBAL_IP64) != 0) { add("</pre><h2>IP64 connections mapping</h2><pre>"); static struct ip64_addrmap_entry *m; for(m = ip64_addrmap_list(); m != NULL; m = list_item_next(m)) { if(timer_expired(&m->timer)) continue; ipaddr_add(&m->ip6addr); add("%%%d (%d)", m->ip6port, m->protocol); if(m->ip6to4 && m->ip4to6) { add(" <-> "); } else if(m->ip6to4) { add(" -> "); } else { add(" <- "); } ip4addr_add(&m->ip4addr); add("%%%d : %d (%x) %us\n", m->ip4port, m->mapped_port, m->flags, (m->timer.interval - (clock_time() - m->timer.start)) / CLOCK_SECOND); SEND_STRING(&s->sout, buf); reset_buf(); } } #endif #if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 add("</pre><h2>6LoWPAN Prefix contexts</h2><pre>"); for(i = 0; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) { if(addr_contexts[i].used == 1) { add("%d : ", addr_contexts[i].number); ipaddr_add_u8_len(addr_contexts[i].prefix, 8); add("\n"); } } add("</pre><br />"); SEND_STRING(&s->sout, buf); reset_buf(); #endif #if CETIC_6LBR_TRANSPARENTBRIDGE add("<h2>HW Prefixes cache</h2><pre>"); for(i = 0; i < prefixCounter; i++) { add("%02x:%02x:%02x\n", prefixBuffer[i][0], prefixBuffer[i][1], prefixBuffer[i][2]); } SEND_STRING(&s->sout, buf); add("</pre><br />"); reset_buf(); #endif PSOCK_END(&s->sout); } static void add_network_cases(const uint8_t state) { switch (state) { case NBR_INCOMPLETE: add("Incomplete"); break; case NBR_REACHABLE: add("Reachable"); break; case NBR_STALE: add("Stale"); break; case NBR_DELAY: add("Delay"); break; case NBR_PROBE: add("Probe"); break; } } static httpd_cgi_call_t * webserver_network_route_add(struct httpd_state *s) { #if UIP_DS6_STATIC_ROUTES uip_ds6_route_t *route; uip_ipaddr_t ipaddr; uint8_t length; uip_ipaddr_t nexthop; char *p; char *sep; webserver_result_title = "Network"; webserver_result_text = "Add route: Route not created"; do { if(!s->query) break; p = s->query; sep = index(p, '='); if(sep == NULL) break; *sep = 0; if(strcmp(p, "target") != 0) break; p = sep + 1; sep = index(p, '&'); if(sep == NULL) break; *sep = 0; if(uiplib_ipaddrconv(p, &ipaddr) == 0) break; p = sep + 1; sep = index(p, '='); if(sep == NULL) break; *sep = 0; if(strcmp(p, "length") != 0) break; p = sep + 1; sep = index(p, '&'); if(sep == NULL) break; *sep = 0; length = atoi(p); p = sep + 1; sep = index(p, '='); if(sep == NULL) break; *sep = 0; if(strcmp(p, "nexthop") != 0) break; p = sep + 1; if(uiplib_ipaddrconv(p, &nexthop) == 0) break; route = uip_ds6_route_add_static(&ipaddr, length, &nexthop); if(route) { webserver_result_text = "Route created"; } } while (0); #else webserver_result_title = "Network"; webserver_result_text = "Add route: not supported"; #endif return &webserver_result_page; }
void tcpip_ipv6_output(void) { uip_ds6_nbr_t *nbr = NULL; uip_ipaddr_t *nexthop = NULL; if(uip_len == 0) { return; } if(uip_len > UIP_LINK_MTU) { UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_clear_buf(); return; } if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){ UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_clear_buf(); return; } #if UIP_CONF_IPV6_RPL if(!rpl_update_header()) { /* Packet can not be forwarded */ PRINTF("tcpip_ipv6_output: RPL header update error\n"); uip_clear_buf(); return; } #endif /* UIP_CONF_IPV6_RPL */ /* Let's go ahead and get the "best" parent. We'll use it for default (blind) sending. */ /*#if UIP_CONF_IPV6_RPL && RPL_CONF_OPP_ROUTING if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) && !rpl_is_addr_opp(&UIP_IP_BUF->destipaddr)) { #else*/ if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { //#endif /* Next hop determination */ #if UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING uip_ipaddr_t ipaddr; /* Look for a RPL Source Route */ if(rpl_srh_get_next_hop(&ipaddr)) { nexthop = &ipaddr; } #endif /* UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING */ nbr = NULL; /* We first check if the destination address is on our immediate link. If so, we simply use the destination address as our nexthop address. */ PRINTF("tcpip a %d\n", nexthop); if(nexthop == NULL && uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){ nexthop = &UIP_IP_BUF->destipaddr; PRINTF("tcpip b\n"); } if(nexthop == NULL) { uip_ds6_route_t *route; /* Check if we have a route to the destination address. */ route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); /* No route was found - we send to the default route instead. */ if(route == NULL) { PRINTF("tcpip_ipv6_output: no route found, using default route\n"); nexthop = uip_ds6_defrt_choose(); if(nexthop == NULL) { #ifdef UIP_FALLBACK_INTERFACE PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40)); if(uip_ext_len > 0) { extern void remove_ext_hdr(void); uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40); remove_ext_hdr(); /* This should be copied from the ext header... */ UIP_IP_BUF->proto = proto; } /* Inform the other end that the destination is not reachable. If it's * not informed routes might get lost unexpectedly until there's a need * to send a new packet to the peer */ if(UIP_FALLBACK_INTERFACE.output() < 0) { PRINTF("FALLBACK: output error. Reporting DST UNREACH\n"); uip_icmp6_error_output(ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); uip_flags = 0; tcpip_ipv6_output(); return; } #else PRINTF("tcpip_ipv6_output: Destination off-link but no route\n"); #endif /* !UIP_FALLBACK_INTERFACE */ uip_clear_buf(); return; } } else { /* A route was found, so we look up the nexthop neighbor for the route. */ nexthop = uip_ds6_route_nexthop(route); /* If the nexthop is dead, for example because the neighbor never responded to link-layer acks, we drop its route. */ if(nexthop == NULL) { #if UIP_CONF_IPV6_RPL /* If we are running RPL, and if we are the root of the network, we'll trigger a global repair berfore we remove the route. */ rpl_dag_t *dag; rpl_instance_t *instance; dag = (rpl_dag_t *)route->state.dag; if(dag != NULL) { instance = dag->instance; rpl_repair_root(instance->instance_id); } #endif /* UIP_CONF_IPV6_RPL */ uip_ds6_route_rm(route); /* We don't have a nexthop to send the packet to, so we drop it. */ return; } } #if TCPIP_CONF_ANNOTATE_TRANSMISSIONS if(nexthop != NULL) { static uint8_t annotate_last; static uint8_t annotate_has_last = 0; if(annotate_has_last) { printf("#L %u 0; red\n", annotate_last); } printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); annotate_last = nexthop->u8[sizeof(uip_ipaddr_t) - 1]; annotate_has_last = 1; } #endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */ } /* End of next hop determination */ nbr = uip_ds6_nbr_lookup(nexthop); if(nbr == NULL) { #if UIP_ND6_SEND_NS if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE, NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) { uip_clear_buf(); PRINTF("tcpip_ipv6_output: failed to add neighbor to cache\n"); return; } else { #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /* RFC4861, 7.2.2: * "If the source address of the packet prompting the solicitation is the * same as one of the addresses assigned to the outgoing interface, that * address SHOULD be placed in the IP Source Address of the outgoing * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used."*/ if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)){ uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr); } else { uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); } stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); nbr->nscount = 1; /* Send the first NS try from here (multicast destination IP address). */ } #else /* UIP_ND6_SEND_NS */ PRINTF("tcpip_ipv6_output: neighbor not in cache\n"); uip_len = 0; return; #endif /* UIP_ND6_SEND_NS */ } else { #if UIP_ND6_SEND_NS if(nbr->state == NBR_INCOMPLETE) { PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit and set the destination nbr to nbr. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_clear_buf(); return; } /* Send in parallel if we are running NUD (nbc state is either STALE, DELAY, or PROBE). See RFC 4861, section 7.3.3 on node behavior. */ if(nbr->state == NBR_STALE) { nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n"); } #endif /* UIP_ND6_SEND_NS */ tcpip_output(uip_ds6_nbr_get_ll(nbr)); #if UIP_CONF_IPV6_QUEUE_PKT /* * Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves * to STALE, and you must both send a NA and the queued packet. */ if(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); tcpip_output(uip_ds6_nbr_get_ll(nbr)); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_clear_buf(); return; } } /* Multicast IP destination address. */ tcpip_output(NULL); uip_clear_buf(); }
/*---------------------------------------------------------------------------*/ void collect_common_send(void) { static uint8_t seqno; struct { uint8_t seqno; uint8_t for_alignment; struct collect_view_data_msg msg; } msg; /* struct collect_neighbor *n; */ uint16_t parent_etx; uint16_t rtmetric; uint16_t num_neighbors; uint16_t beacon_interval; rpl_parent_t *preferred_parent; rimeaddr_t parent; rpl_dag_t *dag; if(client_conn == NULL) { /* Not setup yet */ return; } memset(&msg, 0, sizeof(msg)); seqno++; if(seqno == 0) { /* Wrap to 128 to identify restarts */ seqno = 128; } msg.seqno = seqno; rimeaddr_copy(&parent, &rimeaddr_null); parent_etx = 0; /* Let's suppose we have only one instance */ dag = rpl_get_any_dag(); if(dag != NULL) { preferred_parent = dag->preferred_parent; if(preferred_parent != NULL) { uip_ds6_nbr_t *nbr; nbr = uip_ds6_nbr_lookup(rpl_get_parent_ipaddr(preferred_parent)); if(nbr != NULL) { /* Use parts of the IPv6 address as the parent address, in reversed byte order. */ parent.u8[RIMEADDR_SIZE - 1] = nbr->ipaddr.u8[sizeof(uip_ipaddr_t) - 2]; parent.u8[RIMEADDR_SIZE - 2] = nbr->ipaddr.u8[sizeof(uip_ipaddr_t) - 1]; parent_etx = rpl_get_parent_rank((rimeaddr_t *) uip_ds6_nbr_get_ll(nbr)) / 2; } } rtmetric = dag->rank; beacon_interval = (uint16_t) ((2L << dag->instance->dio_intcurrent) / 1000); num_neighbors = RPL_PARENT_COUNT(dag); } else { rtmetric = 0; beacon_interval = 0; num_neighbors = 0; } /* num_neighbors = collect_neighbor_list_num(&tc.neighbor_list); */ collect_view_construct_message(&msg.msg, &parent, parent_etx, rtmetric, num_neighbors, beacon_interval); uip_udp_packet_sendto(client_conn, &msg, sizeof(msg), &server_ipaddr, UIP_HTONS(UDP_SERVER_PORT)); }