/*---------------------------------------------------------------------------*/ void rpl_remove_routes(rpl_dag_t *dag) { uip_ds6_route_t *r; #if RPL_CONF_MULTICAST uip_mcast6_route_t *mcast_route; #endif r = uip_ds6_route_head(); while(r != NULL) { if(r->state.dag == dag) { uip_ds6_route_rm(r); r = uip_ds6_route_head(); } else { r = uip_ds6_route_next(r); } } #if RPL_CONF_MULTICAST mcast_route = uip_mcast6_route_list_head(); while(mcast_route != NULL) { if(mcast_route->dag == dag) { uip_mcast6_route_rm(mcast_route); mcast_route = uip_mcast6_route_list_head(); } else { mcast_route = list_item_next(mcast_route); } } #endif }
void uip_ds6_route_info_callback(uip_nd6_opt_route_info * rio, uip_ip6addr_t * next_hop) { PRINTF("RIO received\n"); //TODO Preferences ? uip_ds6_route_t *found; if((found = uip_ds6_route_lookup(&rio->prefix)) == NULL && rio->rlifetime != 0) { //New route PRINTF("New route received\n"); PRINTF("type=%d, flags=%d, length=%d, lifetime=%"PRIu32", Preflen=%d, prefix=", rio->type, rio->flagsreserved, rio->len, uip_ntohl(rio->rlifetime), rio->preflen); uip_ds6_route_t *new_route; if((new_route = uip_ds6_route_add(&rio->prefix, rio->preflen, next_hop)) == NULL) { PRINTF("error when adding route\n"); } else { PRINTF("Route added\n"); new_route->state.lifetime = uip_ntohl(rio->rlifetime); } } else { PRINTF("Route already exists\n"); if(rio->rlifetime == 0) { uip_ds6_route_rm(found); } else { found->state.lifetime = uip_ntohl(rio->rlifetime); } } }
void rpl_remove_routes(rpl_dag_t *dag) { int i; for(i = 0; i < UIP_DS6_ROUTE_NB; i++) { if(uip_ds6_routing_table[i].state.dag == dag) { uip_ds6_route_rm(&uip_ds6_routing_table[i]); } } }
/*---------------------------------------------------------------------------*/ void rpl_purge_routes(void) { uip_ds6_route_t *r; uip_ipaddr_t prefix; rpl_dag_t *dag; rpl_instance_t *instance; //changed /* First pass, decrement lifetime */ r = uip_ds6_route_head(); while(r != NULL) { if(r->state.lifetime >= 1) { /* * If a route is at lifetime == 1, set it to 0, scheduling it for * immediate removal below. This achieves the same as the original code, * which would delete lifetime <= 1 */ r->state.lifetime--; } r = uip_ds6_route_next(r); } /* Second pass, remove dead routes */ r = uip_ds6_route_head(); while(r != NULL) { /*Pre-change handle second_instance*/ if(r->state.lifetime < 1) { /* Routes with lifetime == 1 have only just been decremented from 2 to 1, * thus we want to keep them. Hence < and not <= */ uip_ipaddr_copy(&prefix, &r->ipaddr); uip_ds6_route_rm(r); r = uip_ds6_route_head(); PRINTF("No more routes to "); PRINT6ADDR(&prefix); /*Changed*/ instance = rpl_get_instance(r->state.instance_id); dag = instance->current_dag; //dag1 = second_instance->current_dag; /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */ if(dag->rank != ROOT_RANK(instance)) { PRINTF(" -> generate No-Path DAO\n"); dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME); /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */ return; } PRINTF("\n"); } else { r = uip_ds6_route_next(r); } } }
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_lookup(uip_ipaddr_t *destipaddr) { uip_ds6_route_t *locrt = NULL; uint8_t longestmatch = 0; PRINTF("DS6: Looking up route for "); PRINT6ADDR(destipaddr); PRINTF("\n"); for(locroute = uip_ds6_routing_table; locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB; locroute++) { if((locroute->isused) && (locroute->length >= longestmatch) && (uip_ipaddr_prefixcmp (destipaddr, &locroute->ipaddr, locroute->length))) { longestmatch = locroute->length; locrt = locroute; } } if(locrt != NULL) { #ifdef UIP_DS6_ROUTE_STATE_CLEAN switch (locrt->state.learned_from) { case RPL_ROUTE_FROM_UNICAST_DAO: case RPL_ROUTE_FROM_MULTICAST_DAO: case RPL_ROUTE_FROM_DIO: if(UIP_DS6_ROUTE_STATE_CLEAN(&locrt->state)) { uip_ds6_route_rm(locrt); //TODO : verify that the prefix len is 128 mob_lost_node(locrt); PRINTF("DS6: Route timeout\n"); return NULL; } break; default: break; } #endif /* UIP_DS6_ROUTE_STATE_TYPE */ PRINTF("DS6: Found route:"); PRINT6ADDR(destipaddr); PRINTF(" via "); PRINT6ADDR(&locrt->nexthop); PRINTF("\n"); } else { PRINTF("DS6: No route found\n"); } return locrt; }
void rpl_purge_routes(void) { int i; for(i = 0; i < UIP_DS6_ROUTE_NB; i++) { if(uip_ds6_routing_table[i].isused) { if(uip_ds6_routing_table[i].state.lifetime <= 1) { uip_ds6_route_rm(&uip_ds6_routing_table[i]); } else { uip_ds6_routing_table[i].state.lifetime--; } } } }
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop, uint8_t metric) { loc_loop_state = uip_ds6_list_loop ((uip_ds6_element_t *)uip_ds6_routing_table, UIP_DS6_ROUTE_NB, sizeof(uip_ds6_route_t), ipaddr, length, (uip_ds6_element_t **)&locroute); #ifdef UIP_DS6_ROUTE_STATE_CLEAN if (loc_loop_state == NOSPACE) { for(locroute = uip_ds6_routing_table; locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB; ++locroute) { if(locroute->isused && (UIP_DS6_ROUTE_STATE_CLEAN(&locroute->state))) { uip_ds6_route_rm(locroute); loc_loop_state = FREESPACE; break; } } } if (loc_loop_state == NOSPACE) { locroute = NULL; } #endif /* UIP_DS6_ROUTE_STATE_TYPE */ if (loc_loop_state == FREESPACE) { locroute->isused = 1; uip_ipaddr_copy(&(locroute->ipaddr), ipaddr); locroute->length = length; uip_ipaddr_copy(&(locroute->nexthop), nexthop); locroute->metric = metric; #ifdef UIP_DS6_ROUTE_STATE_TYPE memset (&(locroute->state),0,sizeof(UIP_DS6_ROUTE_STATE_TYPE)); #endif PRINTF("DS6: adding route: "); PRINT6ADDR(ipaddr); PRINTF(" via "); PRINT6ADDR(nexthop); PRINTF("\n"); ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); } return locroute; }
/*---------------------------------------------------------------------------*/ void rpl_remove_routes(rpl_dag_t *dag) { uip_ds6_route_t *r; r = uip_ds6_route_head(); while(r != NULL) { if(r->state.dag == dag) { uip_ds6_route_rm(r); r = uip_ds6_route_head(); } else { r = uip_ds6_route_next(r); } } }
static httpd_cgi_call_t * webserver_network_route_rm(struct httpd_state *s) { uip_ds6_route_t *route; uip_ipaddr_t ipaddr; webserver_result_title = "Network"; webserver_result_text = "Delete route: Route not found"; if(s->query && uiplib_ipaddrconv(s->query, &ipaddr) != 0) { route = uip_ds6_route_lookup(&ipaddr); if(route) { uip_ds6_route_rm(route); webserver_result_text = "Route deleted"; } } return &webserver_result_page; }
/*---------------------------------------------------------------------------*/ void rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag) { uip_ds6_route_t *r; r = uip_ds6_route_head(); while(r != NULL) { if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) && r->state.dag == dag) { uip_ds6_route_rm(r); r = uip_ds6_route_head(); } else { r = uip_ds6_route_next(r); } } ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); }
/*---------------------------------------------------------------------------*/ static void rm_routelist(struct uip_ds6_route_neighbor_routes *routes) { #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ PRINTF("uip_ds6_route_rm_routelist\n"); if(routes != NULL && routes->route_list != NULL) { struct uip_ds6_route_neighbor_route *r; r = list_head(routes->route_list); while(r != NULL) { uip_ds6_route_rm(r->route); r = list_head(routes->route_list); } nbr_table_remove(nbr_routes, routes); } #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ }
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_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_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; } /* 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 */ #if UIP_CONF_IPV6_RPL if(rpl_update_header_final(nexthop)) { uip_clear_buf(); 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_clear_buf(); 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_NA */ uip_len = 0; return; #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_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_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_clear_buf(); return; } } /* Multicast IP destination address. */ tcpip_output(NULL); uip_clear_buf(); }
/*---------------------------------------------------------------------------*/ httpd_simple_script_t httpd_simple_get_script(const char *name) { static uip_ds6_route_t *r; static char filename[HTTPD_PATHLEN]; static int i; strcpy(filename, slip_config_www_root); strcat(filename, "/"); strcat(filename, name); redirect = 0; if(strcmp(name, "index.html") == 0 || strcmp(name, "") == 0) { return generate_index; #if CONTIKI_TARGET_NATIVE } else if (access(filename, R_OK) == 0) { return send_file; #endif #if CETIC_NODE_INFO } else if(strcmp(name, "sensors.html") == 0) { return generate_sensors; #endif } else if(strcmp(name, "rpl.html") == 0) { return generate_rpl; } else if(strcmp(name, "network.html") == 0) { return generate_network; } else if(strcmp(name, "config.html") == 0) { return generate_config; } else if(strcmp(name, "statistics.html") == 0) { return generate_statistics; } else if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) { if(strcmp(name, "rpl-gr") == 0) { #if UIP_CONF_IPV6_RPL rpl_repair_root(RPL_DEFAULT_INSTANCE); #endif return generate_rpl; } else if(memcmp(name, "route_rm?", 9) == 0) { redirect = 1; i = atoi(name + 9); for(r = uip_ds6_route_list_head(); r != NULL; r = list_item_next(r), --i) { if(i == 0) { uip_ds6_route_rm(r); break; } } return generate_network; } else if(memcmp(name, "nbr_rm?", 7) == 0) { redirect = 1; uip_ds6_nbr_rm(&uip_ds6_nbr_cache[atoi(name + 7)]); return generate_network; } else if(memcmp(name, "config?", 7) == 0) { if(update_config(name + 7)) { return generate_config; } else { return generate_reboot; } } else { return generate_404; } } else { return generate_404; } }
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop) { uip_ds6_route_t *r; struct uip_ds6_route_neighbor_route *nbrr; #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ /* Get link-layer address of next hop, make sure it is in neighbor table */ const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop); if(nexthop_lladdr == NULL) { PRINTF("uip_ds6_route_add: neighbor link-local address unknown for "); PRINT6ADDR(nexthop); PRINTF("\n"); return NULL; } /* First make sure that we don't add a route twice. If we find an existing route for our destination, we'll delete the old one first. */ r = uip_ds6_route_lookup(ipaddr); if(r != NULL) { PRINTF("uip_ds6_route_add: old route for "); PRINT6ADDR(ipaddr); PRINTF(" found, deleting it\n"); uip_ds6_route_rm(r); } { struct uip_ds6_route_neighbor_routes *routes; /* If there is no routing entry, create one. We first need to check if we have room for this route. If not, we remove the least recently used one we have. */ if(uip_ds6_route_num_routes() == UIP_DS6_ROUTE_NB) { /* Removing the oldest route entry from the route table. The least recently used route is the first route on the list. */ uip_ds6_route_t *oldest; oldest = list_tail(routelist); /* uip_ds6_route_head(); */ PRINTF("uip_ds6_route_add: dropping route to "); PRINT6ADDR(&oldest->ipaddr); PRINTF("\n"); uip_ds6_route_rm(oldest); } /* Every neighbor on our neighbor table holds a struct uip_ds6_route_neighbor_routes which holds a list of routes that go through the neighbor. We add our route entry to this list. We first check to see if we already have this neighbor in our nbr_route table. If so, the neighbor already has a route entry list. */ routes = nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)nexthop_lladdr); if(routes == NULL) { /* If the neighbor did not have an entry in our neighbor table, we create one. The nbr_table_add_lladdr() function returns a pointer to a pointer that we may use for our own purposes. We initialize this pointer with the list of routing entries that are attached to this neighbor. */ routes = nbr_table_add_lladdr(nbr_routes, (linkaddr_t *)nexthop_lladdr); if(routes == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate neighbor table entry\n"); return NULL; } LIST_STRUCT_INIT(routes, route_list); } /* Allocate a routing entry and populate it. */ r = memb_alloc(&routememb); if(r == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate route\n"); return NULL; } /* add new routes first - assuming that there is a reason to add this and that there is a packet coming soon. */ list_push(routelist, r); nbrr = memb_alloc(&neighborroutememb); if(nbrr == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate neighbor route list entry\n"); memb_free(&routememb, r); return NULL; } nbrr->route = r; /* Add the route to this neighbor */ list_add(routes->route_list, nbrr); r->neighbor_routes = routes; num_routes++; PRINTF("uip_ds6_route_add num %d\n", num_routes); } uip_ipaddr_copy(&(r->ipaddr), ipaddr); r->length = length; #ifdef UIP_DS6_ROUTE_STATE_TYPE memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE)); #endif PRINTF("uip_ds6_route_add: adding route: "); PRINT6ADDR(ipaddr); PRINTF(" via "); PRINT6ADDR(nexthop); PRINTF("\n"); ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); #if UIP_DS6_NOTIFICATIONS call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop); #endif #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ return r; }
/* Switch the ports and addresses and set route and neighbor cache. * Returns 1 if packet was sent properly, in this case it is the caller * that needs to release the net_buf. If 0 is returned, then uIP stack * has released the net_buf already because there was an some net related * error when sending the buffer. */ static inline int udp_prepare_and_send(struct net_context *context, struct net_buf *buf) { #ifdef CONFIG_NETWORKING_WITH_IPV6 uip_ds6_route_t *route_old, *route_new = NULL; uip_ds6_nbr_t *nbr; #endif uip_ipaddr_t tmp; uint16_t port; uint8_t ret; if (uip_len(buf) == 0) { /* This is expected as uIP will typically set the * packet length to 0 after receiving it. So we need * to fix the length here. The protocol specific * part is added also here. */ uip_len(buf) = uip_slen(buf) = uip_appdatalen(buf); buf->data = buf->buf + UIP_IPUDPH_LEN; } port = UIP_UDP_BUF(buf)->srcport; UIP_UDP_BUF(buf)->srcport = UIP_UDP_BUF(buf)->destport; UIP_UDP_BUF(buf)->destport = port; uip_ipaddr_copy(&tmp, &UIP_IP_BUF(buf)->srcipaddr); uip_ipaddr_copy(&UIP_IP_BUF(buf)->srcipaddr, &UIP_IP_BUF(buf)->destipaddr); uip_ipaddr_copy(&UIP_IP_BUF(buf)->destipaddr, &tmp); #ifdef CONFIG_NETWORKING_WITH_IPV6 /* The peer needs to be in neighbor cache before route can be added. */ nbr = uip_ds6_nbr_lookup((uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr); if (!nbr) { const uip_lladdr_t *lladdr = (const uip_lladdr_t *)&buf->src; nbr = uip_ds6_nbr_add( (uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr, lladdr, 0, NBR_REACHABLE); if (!nbr) { NET_DBG("Cannot add peer "); PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr); PRINT(" to neighbor cache\n"); } } /* Temporarily add route to peer, delete the route after * sending the packet. Check if there was already a * route and do not remove it if there was existing * route to this peer. */ route_old = uip_ds6_route_lookup(&UIP_IP_BUF(buf)->destipaddr); if (!route_old) { route_new = uip_ds6_route_add(&UIP_IP_BUF(buf)->destipaddr, 128, &UIP_IP_BUF(buf)->destipaddr); if (!route_new) { NET_DBG("Cannot add route to peer "); PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr); PRINT("\n"); } } #endif ret = simple_udp_sendto_port(buf, net_context_get_udp_connection(context), buf->data, buf->len, &UIP_IP_BUF(buf)->destipaddr, uip_ntohs(UIP_UDP_BUF(buf)->destport)); if (!ret) { NET_DBG("Packet could not be sent properly.\n"); } #ifdef CONFIG_NETWORKING_WITH_IPV6 if (!route_old && route_new) { /* This will also remove the neighbor cache entry */ uip_ds6_route_rm(route_new); } #endif return ret; }
int rpl_verify_header(int uip_ext_opt_offset) { rpl_instance_t *instance; int down; uint8_t sender_closer; uip_ds6_route_t *route; if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { PRINTF("RPL: Bad header option! (wrong length)\n"); return 1; } instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); if(instance == NULL) { PRINTF("RPL: Unknown instance: %u\n", UIP_EXT_HDR_OPT_RPL_BUF->instance); return 1; } if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { PRINTF("RPL: Forward error!\n"); /* We should try to repair it by removing the neighbor that caused the packet to be forwareded in the first place. We drop any routes that go through the neighbor that sent the packet to us. */ route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); if(route != NULL) { uip_ds6_route_rm(route); /* If we are the root and just needed to remove a DAO route, chances are that the network needs to be repaired. The rpl_repair_root() function will cause a global repair if we happen to be the root node of the dag. */ PRINTF("RPL: initiate global repair\n"); rpl_repair_root(instance->instance_id); } /* Remove the forwarding error flag and return 0 to let the packet be forwarded again. */ UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_FWD_ERR; return 0; } if(!instance->current_dag->joined) { PRINTF("RPL: No DAG in the instance\n"); return 1; } down = 0; if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) { down = 1; } sender_closer = UIP_EXT_HDR_OPT_RPL_BUF->senderrank < instance->current_dag->rank; PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up", sender_closer, UIP_EXT_HDR_OPT_RPL_BUF->senderrank, instance->current_dag->rank ); if((down && !sender_closer) || (!down && sender_closer)) { PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n", UIP_EXT_HDR_OPT_RPL_BUF->senderrank, instance->current_dag->rank, sender_closer); if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) { PRINTF("RPL: Rank error signalled in RPL option!\n"); /* We should try to repair it, not implemented for the moment */ rpl_reset_dio_timer(instance); /* Forward the packet anyway. */ return 0; } PRINTF("RPL: Single error tolerated\n"); UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR; return 0; } PRINTF("RPL: Rank OK\n"); return 0; }
void tcpip_ipv6_output(void) { uip_ds6_nbr_t *nbr = NULL; uip_ipaddr_t *nexthop; uip_ds6_route_t *route = NULL; if(uip_len == 0) { return; } PRINTF("IPv6 packet send from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(" to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); 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_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 { /* 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) { #if CETIC_6LBR_SMARTBRIDGE if (uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64)) { /* In smart-bridge mode, there is no route towards hosts on the Ethernet side Therefore we have to check the destination and assume the host is on-link */ nexthop = &UIP_IP_BUF->destipaddr; } else #endif #if CETIC_6LBR_ROUTER && UIP_CONF_IPV6_RPL if (is_dodag_root() && uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64)) { //In router mode, we drop packets towards unknown mote PRINTF("Dropping wsn packet with no route\n"); uip_len = 0; return; } else #endif #if CETIC_6LBR_IP64 if(ip64_addr_is_ip64(&UIP_IP_BUF->destipaddr)) { #if UIP_CONF_IPV6_RPL rpl_remove_header(); #endif IP64_CONF_UIP_FALLBACK_INTERFACE.output(); uip_len = 0; uip_ext_len = 0; return; } else #endif { 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_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 DIO before we remove the route. */ rpl_dag_t *dag; dag = (rpl_dag_t *)route->state.dag; if(dag != NULL) { rpl_reset_dio_timer(dag->instance); } #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 */ #if UIP_CONF_IPV6_RPL if(rpl_update_header_final(nexthop)) { uip_clear_buf(); return; } #endif /* UIP_CONF_IPV6_RPL */ nbr = uip_ds6_nbr_lookup(nexthop); if(nbr == NULL) { #if UIP_ND6_SEND_NA #if CETIC_6LBR && UIP_CONF_IPV6_RPL /* Don't perform NUD if it has been disabled for WSN */ if((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_WSN_NUD) != 0 && uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64) && route != NULL) { uip_clear_buf(); return; } #endif if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) { uip_clear_buf(); 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_NA */ uip_len = 0; return; #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_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 CETIC_6LBR && UIP_CONF_IPV6_RPL /* Don't update nbr state if we don't want to perform NUD for WSN */ if((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_WSN_NUD) == 0 || !uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64) || route == NULL) #endif 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_clear_buf(); return; } } /* Multicast IP destination address. */ tcpip_output(NULL); uip_clear_buf(); }
/** * Neighbor Advertisement Processing * * we might have to send a pkt that had been buffered while address * resolution was performed (if we support buffering, see UIP_CONF_QUEUE_PKT) * * As per RFC 4861, on link layer that have addresses, TLLAO options MUST be * included when responding to multicast solicitations, SHOULD be included in * response to unicast (here we assume it is for now) * * NA can be received after sending NS for DAD, Address resolution or NUD. Can * be unsolicited as well. * It can trigger update of the state of the neighbor in the neighbor cache, * router in the router list. * If the NS was for DAD, it means DAD failed * */ static void na_input(void) { #if CETIC_6LBR_SMARTBRIDGE uip_ds6_route_t * route; #endif 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); } #if CETIC_6LBR_SMARTBRIDGE /* Address Advertisement */ if ( (nvm_data.mode & CETIC_MODE_SMART_MULTI_BR) != 0 ) { if (uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) && uip_is_mcast_group_id_all_nodes(&UIP_IP_BUF->destipaddr)) { LOG6LBR_6ADDR(INFO, &UIP_ND6_NA_BUF->tgtipaddr, "Received purge NA for "); #if CETIC_NODE_INFO node_info_rm_by_addr(&UIP_ND6_NA_BUF->tgtipaddr); #endif route = uip_ds6_route_lookup(&UIP_ND6_NA_BUF->tgtipaddr); if (route != NULL ) { uip_ds6_route_rm(route); } goto discard; } } #endif 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(&UIP_ND6_NA_BUF->tgtipaddr); lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(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_clear_buf(); return; }
/*---------------------------------------------------------------------------*/ int rpl_verify_header(int uip_ext_opt_offset) { rpl_instance_t *instance; int down; uint16_t sender_rank; uint8_t sender_closer; uip_ds6_route_t *route; rpl_parent_t *sender = NULL; if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) { PRINTF("RPL: Hop-by-hop extension header has wrong size\n"); return 1; } if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) { PRINTF("RPL: Non RPL Hop-by-hop option\n"); return 1; } if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { PRINTF("RPL: Bad header option! (wrong length)\n"); return 1; } instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance); if(instance == NULL) { PRINTF("RPL: Unknown instance: %u\n", UIP_EXT_HDR_OPT_RPL_BUF->instance); return 1; } if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { PRINTF("RPL: Forward error!\n"); /* We should try to repair it by removing the neighbor that caused the packet to be forwareded in the first place. We drop any routes that go through the neighbor that sent the packet to us. */ route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); if(route != NULL) { uip_ds6_route_rm(route); } RPL_STAT(rpl_stats.forward_errors++); /* Trigger DAO retransmission */ rpl_reset_dio_timer(instance); /* drop the packet as it is not routable */ return 1; } if(!instance->current_dag->joined) { PRINTF("RPL: No DAG in the instance\n"); return 1; } down = 0; if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) { down = 1; } sender_rank = UIP_HTONS(UIP_EXT_HDR_OPT_RPL_BUF->senderrank); sender_closer = sender_rank < instance->current_dag->rank; PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up", sender_closer, sender_rank, instance->current_dag->rank ); sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER)); if(sender != NULL && (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR)) { /* A rank error was signalled, attempt to repair it by updating * the sender's rank from ext header */ sender->rank = sender_rank; rpl_select_dag(instance, sender); } if((down && !sender_closer) || (!down && sender_closer)) { PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n", sender_rank, instance->current_dag->rank, sender_closer); /* Attempt to repair the loop by sending a unicast DIO back to the sender * so that it gets a fresh update of our rank. */ if(sender != NULL) { instance->unicast_dio_target = sender; rpl_schedule_unicast_dio_immediately(instance); } if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) { RPL_STAT(rpl_stats.loop_errors++); PRINTF("RPL: Rank error signalled in RPL option!\n"); /* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */ rpl_reset_dio_timer(instance); return 1; } PRINTF("RPL: Single error tolerated\n"); RPL_STAT(rpl_stats.loop_warnings++); UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR; return 0; } PRINTF("RPL: Rank OK\n"); return 0; }