int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from) { if(dag->def_route != NULL) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&dag->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(dag->def_route); } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); if(DEFAULT_ROUTE_LIFETIME == INFINITE_LIFETIME) { dag->def_route = uip_ds6_defrt_add(from, 0); } else { dag->def_route = uip_ds6_defrt_add(from, DEFAULT_ROUTE_LIFETIME); } if(dag->def_route == NULL) { return 0; } } return 1; }
/*---------------------------------------------------------------------------*/ int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) { if(instance->def_route != NULL) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&instance->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(instance->def_route); instance->def_route = NULL; } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); #if RPL_DEFAULT_ROUTE_INFINITE_LIFETIME instance->def_route = uip_ds6_defrt_add(from, 0); #else instance->def_route = uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); #endif if(instance->def_route == NULL) { return 0; } } else { PRINTF("RPL: Removing default route\n"); if(instance->def_route != NULL) { uip_ds6_defrt_rm(instance->def_route); } else { PRINTF("RPL: Not actually removing default route, since instance had no default route\n"); } } return 1; }
int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) { if(instance->def_route != NULL) { if(instance->def_route->isused) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&instance->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(instance->def_route); } instance->def_route = NULL; } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); instance->def_route = uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); if(instance->def_route == NULL) { return 0; } } return 1; }
static inline void init_server() { PRINT("%s: run mcast tester\n", __func__); sys_rand32_init(); net_set_mac(my_mac, sizeof(my_mac)); #ifdef CONFIG_NETWORKING_WITH_IPV4 { uip_ipaddr_t addr; uip_ipaddr(&addr, 192,0,2,2); uip_sethostaddr(&addr); } #else /* IPv6 */ { uip_ipaddr_t *addr; #ifdef CONFIG_NETWORKING_IPV6_NO_ND /* Set the routes and neighbor cache only if we do not have * neighbor discovery enabled. This setting should only be * used if running in qemu and using slip (tun device). */ const uip_lladdr_t *lladdr = (const uip_lladdr_t *)&peer_mac; addr = (uip_ipaddr_t *)&in6addr_peer; uip_ds6_defrt_add(addr, 0); /* We cannot send to peer unless it is in neighbor * cache. Neighbor cache should be populated automatically * but do it here so that test works from first packet. */ uip_ds6_nbr_add(addr, lladdr, 0, NBR_REACHABLE); #else /* Hard code the route to peer just in case, not to * be done in real life applications. */ addr = (uip_ipaddr_t *)&in6addr_peer; uip_ds6_defrt_add(addr, 0); #endif addr = (uip_ipaddr_t *)&in6addr_my; uip_ds6_addr_add(addr, 0, ADDR_MANUAL); } #endif }
/*---------------------------------------------------------------------------*/ void simple_rpl_init_dag(void) { ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL); to_become_root = 1; /* We set a default route of NULL. This means that we want our default route to be the fallback interface, regardless if we learn new default routes from the RPL network. */ uip_ds6_defrt_add(NULL, 0); }
int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from) { if(dag->def_route != NULL) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&dag->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(dag->def_route); } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); dag->def_route = uip_ds6_defrt_add(from, RPL_LIFETIME(dag, dag->default_lifetime)); if(dag->def_route == NULL) { return 0; } } return 1; }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; #if RPL_CONF_MULTICAST /* If the root is advertising MOP 2 but we support MOP 3 we can still join * In that scenario, we suppress DAOs for multicast targets */ if(dio->mop < RPL_MOP_STORING_NO_MULTICAST) { #else if(dio->mop != RPL_MOP_DEFAULT) { #endif PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); #if CETIC_6LBR if(!cetic_6lbr_dio_input_hook(from, instance, dag, dio)) { return; } #endif if(dag != NULL && instance != NULL) { if(lollipop_greater_than(dio->version, dag->version)) { if(dag->rank == ROOT_RANK(instance)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); dag->version = dio->version; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); #if CETIC_6LBR nvm_data.rpl_version_id = dag->version; store_nvm_config(); #endif } else { PRINTF("RPL: Global repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } global_repair(from, dag, dio); } return; } if(lollipop_greater_than(dag->version, dio->version)) { /* The DIO sender is on an older version of the DAG. */ PRINTF("RPL: old version received => inconsistency detected\n"); if(dag->joined) { rpl_reset_dio_timer(instance); return; } } } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) { PRINTF("RPL: Root ignored DIO for different DAG\n"); return; } if(dag == NULL) { #if RPL_MAX_DAG_PER_INSTANCE > 1 PRINTF("RPL: Adding new DAG to known instance.\n"); dag = rpl_add_dag(from, dio); if(dag == NULL) { PRINTF("RPL: Failed to add DAG.\n"); return; } #else /* RPL_MAX_DAG_PER_INSTANCE > 1 */ PRINTF("RPL: Only one instance supported.\n"); return; #endif /* RPL_MAX_DAG_PER_INSTANCE > 1 */ } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } return; } /* The DIO comes from a valid DAG, we can refresh its lifetime */ dag->lifetime = (1UL << (instance->dio_intmin + instance->dio_intdoubl)) * RPL_DAG_LIFETIME / 1000; PRINTF("Set dag "); PRINT6ADDR(&dag->dag_id); PRINTF(" lifetime to %ld\n", dag->lifetime); /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ rpl_update_dag(instance, dag, dio); p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { /* Add the DIO sender as a candidate parent. */ p = rpl_add_parent(dag, dio, from); if(p == NULL) { PRINTF("RPL: Failed to add a new parent ("); PRINT6ADDR(from); PRINTF(")\n"); return; } PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); PRINT6ADDR(from); PRINTF("\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { rpl_move_parent(previous_dag, dag, p); } } } else { if(p->rank == dio->rank) { PRINTF("RPL: Received consistent DIO\n"); if(dag->joined) { instance->dio_counter++; } } } p->rank = dio->rank; /* Parent info has been updated, trigger rank recalculation */ p->flags |= RPL_PARENT_FLAG_UPDATED; PRINTF("RPL: preferred DAG "); PRINT6ADDR(&instance->current_dag->dag_id); PRINTF(", rank %u, min_rank %u, ", instance->current_dag->rank, instance->current_dag->min_rank); PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n", p->rank, -1/*p->mc.obj.etx*/, rpl_get_nbr(p)->link_metric, instance->mc.obj.etx); /* We have allocated a candidate parent; process the DIO further. */ #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } /* We don't use route control, so we can have only one official parent. */ if(dag->joined && p == dag->preferred_parent) { if(should_send_dao(instance, dio, p)) { RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_schedule_dao(instance); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); if(dag != NULL && instance != NULL) { if(lollipop_greater_than(dio->version, dag->version)) { if(dag->rank == ROOT_RANK(instance)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); dag->version = dio->version; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { PRINTF("RPL: Global Repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } global_repair(from, dag, dio); } return; } if(lollipop_greater_than(dag->version, dio->version)) { /* The DIO sender is on an older version of the DAG. */ PRINTF("RPL: old version received => inconsistency detected\n"); if(dag->joined) { rpl_reset_dio_timer(instance); return; } } } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(dag == NULL) { PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); return; } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } #if !WITH_ORPL return; /* With ORPL we want to have neighbors in the "rpl_parents" table as we need their rank and ackcount for routing set. */ #endif } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { /* Add the DIO sender as a candidate parent. */ p = rpl_add_parent(dag, dio, from); if(p == NULL) { PRINTF("RPL: Failed to add a new parent ("); PRINT6ADDR(from); PRINTF(")\n"); return; } PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); PRINT6ADDR(from); PRINTF("\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { rpl_move_parent(previous_dag, dag, p); } } } else { if(p->rank == dio->rank) { PRINTF("RPL: Received consistent DIO\n"); if(dag->joined) { instance->dio_counter++; } } else { p->rank=dio->rank; } } #if WITH_ORPL if(dag->rank == ROOT_RANK(instance)) { /* We have added the parent, now return if we are root */ return; } #endif PRINTF("RPL: preferred DAG "); PRINT6ADDR(&instance->current_dag->dag_id); PRINTF(", rank %u, min_rank %u, ", instance->current_dag->rank, instance->current_dag->min_rank); PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n", p->rank, -1/*p->mc.obj.etx*/, p->link_metric, instance->mc.obj.etx); /* We have allocated a candidate parent; process the DIO further. */ #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } /* We don't use route control, so we can have only one official parent. */ if(dag->joined && p == dag->preferred_parent) { if(should_send_dao(instance, dio, p)) { RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_schedule_dao(instance); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }
/*---------------------------------------------------------------------------*/ void cetic_6lbr_init(void) { uip_ds6_addr_t *local = uip_ds6_get_link_local(-1); uip_ipaddr_copy(&wsn_ip_local_addr, &local->ipaddr); LOG6LBR_6ADDR(INFO, &wsn_ip_local_addr, "Tentative local IPv6 address "); eth_mac64_addr.addr[0] = eth_mac_addr[0]; eth_mac64_addr.addr[1] = eth_mac_addr[1]; eth_mac64_addr.addr[2] = eth_mac_addr[2]; eth_mac64_addr.addr[3] = CETIC_6LBR_ETH_EXT_A; eth_mac64_addr.addr[4] = CETIC_6LBR_ETH_EXT_B; eth_mac64_addr.addr[5] = eth_mac_addr[3]; eth_mac64_addr.addr[6] = eth_mac_addr[4]; eth_mac64_addr.addr[7] = eth_mac_addr[5]; #if CETIC_6LBR_SMARTBRIDGE if((nvm_data.mode & CETIC_MODE_WAIT_RA_MASK) == 0) //Manual configuration { memcpy(wsn_net_prefix.u8, &nvm_data.wsn_net_prefix, sizeof(nvm_data.wsn_net_prefix)); wsn_net_prefix_len = nvm_data.wsn_net_prefix_len; if((nvm_data.mode & CETIC_MODE_WSN_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(&wsn_ip_addr, &wsn_net_prefix); uip_ds6_set_addr_iid(&wsn_ip_addr, &uip_lladdr); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(wsn_ip_addr.u8, &nvm_data.wsn_ip_addr, sizeof(nvm_data.wsn_ip_addr)); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_MANUAL); } LOG6LBR_6ADDR(INFO, &wsn_ip_addr, "Tentative global IPv6 address "); memcpy(eth_dft_router.u8, &nvm_data.eth_dft_router, sizeof(nvm_data.eth_dft_router)); if ( !uip_is_addr_unspecified(ð_dft_router) ) { uip_ds6_defrt_add(ð_dft_router, 0); } uip_ipaddr_t dns; memcpy(dns.u8, &nvm_data.dns_server, sizeof(nvm_data.dns_server)); uip_nameserver_update(&dns, UIP_NAMESERVER_INFINITE_LIFETIME); } else { //End manual configuration uip_create_unspecified(&wsn_net_prefix); wsn_net_prefix_len = 0; uip_create_unspecified(&wsn_ip_addr); } #endif #if CETIC_6LBR_ROUTER //WSN network configuration memcpy(wsn_net_prefix.u8, &nvm_data.wsn_net_prefix, sizeof(nvm_data.wsn_net_prefix)); wsn_net_prefix_len = nvm_data.wsn_net_prefix_len; if((nvm_data.mode & CETIC_MODE_WSN_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(&wsn_ip_addr, &wsn_net_prefix); uip_ds6_set_addr_iid(&wsn_ip_addr, &uip_lladdr); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(wsn_ip_addr.u8, &nvm_data.wsn_ip_addr, sizeof(nvm_data.wsn_ip_addr)); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_MANUAL); } LOG6LBR_6ADDR(INFO, &wsn_ip_addr, "Tentative global IPv6 address (WSN) "); uip_ipaddr_t dns; memcpy(dns.u8, &nvm_data.dns_server, sizeof(nvm_data.dns_server)); uip_nameserver_update(&dns, UIP_NAMESERVER_INFINITE_LIFETIME); //Ethernet network configuration memcpy(eth_net_prefix.u8, &nvm_data.eth_net_prefix, sizeof(nvm_data.eth_net_prefix)); memcpy(eth_dft_router.u8, &nvm_data.eth_dft_router, sizeof(nvm_data.eth_dft_router)); if ( !uip_is_addr_unspecified(ð_dft_router) ) { uip_ds6_defrt_add(ð_dft_router, 0); } if((nvm_data.mode & CETIC_MODE_ETH_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(ð_ip_addr, ð_net_prefix); uip_ds6_set_addr_iid(ð_ip_addr, ð_mac64_addr); uip_ds6_addr_add(ð_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(eth_ip_addr.u8, &nvm_data.eth_ip_addr, sizeof(nvm_data.eth_ip_addr)); uip_ds6_addr_add(ð_ip_addr, 0, ADDR_MANUAL); } LOG6LBR_6ADDR(INFO, ð_ip_addr, "Tentative global IPv6 address (ETH) "); //Ugly hack : in order to set WSN local address as the default address //We must add it afterwards as uip_ds6_addr_add allocates addr from the end of the list uip_ds6_addr_rm(local); uip_create_linklocal_prefix(ð_ip_local_addr); uip_ds6_set_addr_iid(ð_ip_local_addr, ð_mac64_addr); uip_ds6_addr_add(ð_ip_local_addr, 0, ADDR_AUTOCONF); uip_ds6_addr_add(&wsn_ip_local_addr, 0, ADDR_AUTOCONF); //Prefix and RA configuration #if CETIC_6LBR_WITH_RPL uint8_t publish = (nvm_data.ra_prefix_flags & CETIC_6LBR_MODE_SEND_PIO) != 0; uip_ds6_prefix_add(ð_net_prefix, nvm_data.eth_net_prefix_len, publish, nvm_data.ra_prefix_flags, nvm_data.ra_prefix_vtime, nvm_data.ra_prefix_ptime); #else uip_ds6_prefix_add(ð_net_prefix, nvm_data.eth_net_prefix_len, 0, 0, 0, 0); uint8_t publish = (nvm_data.ra_prefix_flags & CETIC_6LBR_MODE_SEND_PIO) != 0; uip_ds6_prefix_add(&wsn_net_prefix, nvm_data.wsn_net_prefix_len, publish, nvm_data.ra_prefix_flags, nvm_data.ra_prefix_vtime, nvm_data.ra_prefix_ptime); #endif #if CETIC_6LBR_WITH_RPL if ((nvm_data.ra_rio_flags & CETIC_6LBR_MODE_SEND_RIO) != 0 ) { uip_ds6_route_info_add(&wsn_net_prefix, nvm_data.wsn_net_prefix_len, nvm_data.ra_rio_flags, nvm_data.ra_rio_lifetime); } #endif if ((nvm_data.mode & CETIC_MODE_ROUTER_RA_DAEMON) != 0 ) { LOG6LBR_INFO("RA Daemon enabled\n"); } else { LOG6LBR_INFO("RA Daemon disabled\n"); } #endif }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); if(dag != NULL && instance != NULL) { if(lollipop_greater_than(dio->version, dag->version)) { if(dag->rank == ROOT_RANK(instance)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); dag->version = dio->version; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { global_repair(from, dag, dio); } return; } if(lollipop_greater_than(dag->version, dio->version)) { /* The DIO sender is on an older version of the DAG. */ PRINTF("RPL: old version received => inconsistency detected\n"); if(dag->joined) { rpl_reset_dio_timer(instance); return; } } } if(dio->rank == INFINITE_RANK) { PRINTF("RPL: Ignoring DIO from node with infinite rank: "); PRINT6ADDR(from); PRINTF("\n"); return; } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(dag == NULL) { PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); return; } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } return; } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DAG) { /* Make room for a new parent. */ remove_worst_parent(dag, dio->rank); } /* Add the DIO sender as a candidate parent. */ p = rpl_add_parent(dag, dio, from); if(p == NULL) { PRINTF("RPL: Failed to add a new parent ("); PRINT6ADDR(from); PRINTF(")\n"); return; } PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); PRINT6ADDR(from); PRINTF("\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { rpl_move_parent(previous_dag, dag, p); } } } else { if(p->rank == dio->rank) { PRINTF("RPL: Received consistent DIO\n"); if(dag->joined) { instance->dio_counter++; } } else { p->rank=dio->rank; } } PRINTF("RPL: preferred DAG "); PRINT6ADDR(&instance->current_dag->dag_id); PRINTF(", rank %u, min_rank %u, ", instance->current_dag->rank, instance->current_dag->min_rank); PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n", p->rank, p->mc.obj.etx, p->link_metric, instance->mc.obj.etx); /* We have allocated a candidate parent; process the DIO further. */ memcpy(&p->mc, &dio->mc, sizeof(p->mc)); if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } /* We don't use route control, so we can have only one official parent. */ if(dag->joined && p == dag->preferred_parent) { if(should_send_dao(instance, dio, p)) { RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_schedule_dao(instance); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }
/* * 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; }
void cetic_6lbr_init(void) { uip_ds6_addr_t *local = uip_ds6_get_link_local(-1); uip_ipaddr_copy(&wsn_ip_local_addr, &local->ipaddr); LOG6LBR_6ADDR(INFO, &wsn_ip_local_addr, "Tentative local IPv6 address "); #if CETIC_6LBR_SMARTBRIDGE if((nvm_data.mode & CETIC_MODE_WAIT_RA_MASK) == 0) //Manual configuration { memcpy(wsn_net_prefix.u8, &nvm_data.wsn_net_prefix, sizeof(nvm_data.wsn_net_prefix)); if((nvm_data.mode & CETIC_MODE_WSN_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(&wsn_ip_addr, &wsn_net_prefix); uip_ds6_set_addr_iid(&wsn_ip_addr, &uip_lladdr); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(wsn_ip_addr.u8, &nvm_data.wsn_ip_addr, sizeof(nvm_data.wsn_ip_addr)); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_MANUAL); } LOG6LBR_6ADDR(INFO, &wsn_ip_addr, "Tentative global IPv6 address "); memcpy(eth_dft_router.u8, &nvm_data.eth_dft_router, sizeof(nvm_data.eth_dft_router)); if ( !uip_is_addr_unspecified(ð_dft_router) ) { uip_ds6_defrt_add(ð_dft_router, 0); } } //End manual configuration #endif #if CETIC_6LBR_ROUTER //WSN network configuration memcpy(wsn_net_prefix.u8, &nvm_data.wsn_net_prefix, sizeof(nvm_data.wsn_net_prefix)); wsn_net_prefix_len = nvm_data.wsn_net_prefix_len; if((nvm_data.mode & CETIC_MODE_WSN_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(&wsn_ip_addr, &wsn_net_prefix); uip_ds6_set_addr_iid(&wsn_ip_addr, &uip_lladdr); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(wsn_ip_addr.u8, &nvm_data.wsn_ip_addr, sizeof(nvm_data.wsn_ip_addr)); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_MANUAL); } LOG6LBR_6ADDR(INFO, &wsn_ip_addr, "Tentative global IPv6 address (WSN) "); //Ethernet network configuration memcpy(eth_net_prefix.u8, &nvm_data.eth_net_prefix, sizeof(nvm_data.eth_net_prefix)); memcpy(eth_dft_router.u8, &nvm_data.eth_dft_router, sizeof(nvm_data.eth_dft_router)); if ( !uip_is_addr_unspecified(ð_dft_router) ) { uip_ds6_defrt_add(ð_dft_router, 0); } eth_mac64_addr.addr[0] = eth_mac_addr[0]; eth_mac64_addr.addr[1] = eth_mac_addr[1]; eth_mac64_addr.addr[2] = eth_mac_addr[2]; eth_mac64_addr.addr[3] = CETIC_6LBR_ETH_EXT_A; eth_mac64_addr.addr[4] = CETIC_6LBR_ETH_EXT_B; eth_mac64_addr.addr[5] = eth_mac_addr[3]; eth_mac64_addr.addr[6] = eth_mac_addr[4]; eth_mac64_addr.addr[7] = eth_mac_addr[5]; if((nvm_data.mode & CETIC_MODE_ETH_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(ð_ip_addr, ð_net_prefix); uip_ds6_set_addr_iid(ð_ip_addr, ð_mac64_addr); uip_ds6_addr_add(ð_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(eth_ip_addr.u8, &nvm_data.eth_ip_addr, sizeof(nvm_data.eth_ip_addr)); uip_ds6_addr_add(ð_ip_addr, 0, ADDR_MANUAL); } LOG6LBR_6ADDR(INFO, ð_ip_addr, "Tentative global IPv6 address (ETH) "); //Ugly hack : in order to set WSN local address as the default address //We must add it afterwards as uip_ds6_addr_add allocates addr from the end of the list uip_ds6_addr_rm(local); uip_create_linklocal_prefix(ð_ip_local_addr); uip_ds6_set_addr_iid(ð_ip_local_addr, ð_mac64_addr); uip_ds6_addr_add(ð_ip_local_addr, 0, ADDR_AUTOCONF); uip_ds6_addr_add(&wsn_ip_local_addr, 0, ADDR_AUTOCONF); //Prefix and RA configuration #if UIP_CONF_IPV6_RPL uint8_t publish = (nvm_data.ra_prefix_flags & CETIC_6LBR_MODE_SEND_PIO) != 0; uip_ds6_prefix_add(ð_net_prefix, nvm_data.eth_net_prefix_len, publish, nvm_data.ra_prefix_flags, nvm_data.ra_prefix_vtime, nvm_data.ra_prefix_ptime); #else uip_ds6_prefix_add(ð_net_prefix, nvm_data.eth_net_prefix_len, 0, 0, 0, 0); uint8_t publish = (nvm_data.ra_prefix_flags & CETIC_6LBR_MODE_SEND_PIO) != 0; uip_ds6_prefix_add(&wsn_net_prefix, nvm_data.wsn_net_prefix_len, publish, nvm_data.ra_prefix_flags, nvm_data.ra_prefix_vtime, nvm_data.ra_prefix_ptime); #endif #if UIP_CONF_IPV6_RPL if ((nvm_data.ra_rio_flags & CETIC_6LBR_MODE_SEND_RIO) != 0 ) { uip_ds6_route_info_add(&wsn_net_prefix, nvm_data.wsn_net_prefix_len, nvm_data.ra_rio_flags, nvm_data.ra_rio_lifetime); } #endif #endif #if UIP_CONF_IPV6_RPL && CETIC_6LBR_DODAG_ROOT //DODAGID = link-local address used ! cetic_dag = rpl_set_root(nvm_data.rpl_instance_id, &wsn_ip_local_addr); #if CETIC_6LBR_SMARTBRIDGE if((nvm_data.mode & CETIC_MODE_WAIT_RA_MASK) == 0) { rpl_set_prefix(cetic_dag, &wsn_net_prefix, nvm_data.wsn_net_prefix_len); } #else rpl_set_prefix(cetic_dag, &wsn_net_prefix, nvm_data.wsn_net_prefix_len); #endif LOG6LBR_INFO("Configured as DODAG Root\n"); #endif #if CETIC_6LBR_TRANSPARENTBRIDGE #if CETIC_6LBR_LEARN_RPL_MAC LOG6LBR_INFO("Starting as RPL Relay\n"); #else LOG6LBR_INFO("Starting as Full TRANSPARENT-BRIDGE\n"); #endif #elif CETIC_6LBR_SMARTBRIDGE LOG6LBR_INFO("Starting as SMART-BRIDGE\n"); #elif CETIC_6LBR_ROUTER #if UIP_CONF_IPV6_RPL LOG6LBR_INFO("Starting as RPL ROUTER\n"); #else LOG6LBR_INFO("Starting as NDP ROUTER\n"); #endif #elif CETIC_6LBR_6LR LOG6LBR_INFO("Starting as 6LR\n"); #else LOG6LBR_INFO("Starting in UNKNOWN mode\n"); #endif #if CONTIKI_TARGET_NATIVE if (ip_config_file_name) { char str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, (struct sockaddr_in6 *)ð_ip_addr, str, INET6_ADDRSTRLEN); FILE *ip_config_file = fopen(ip_config_file_name, "w"); fprintf(ip_config_file, "%s\n", str); fclose(ip_config_file); } #endif }
void cetic_6lbr_init(void) { #if !CETIC_6LBR_TRANSPARENTBRIDGE uip_ipaddr_t loc_fipaddr; //DODAGID = link-local address used ! uip_create_linklocal_prefix(&loc_fipaddr); uip_ds6_set_addr_iid(&loc_fipaddr, &uip_lladdr); cetic_dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &loc_fipaddr); #endif uip_ds6_addr_t *local = uip_ds6_get_link_local(-1); uip_ipaddr_copy(&wsn_ip_local_addr, &local->ipaddr); PRINTF("Tentative local IPv6 address "); PRINT6ADDR(&wsn_ip_local_addr); PRINTF("\n"); #if CETIC_6LBR_SMARTBRIDGE || CETIC_6LBR_TRANSPARENTBRIDGE if((nvm_data.mode & CETIC_MODE_WAIT_RA_MASK) == 0) //Manual configuration { memcpy(wsn_net_prefix.u8, &nvm_data.wsn_net_prefix, sizeof(nvm_data.wsn_net_prefix)); if((nvm_data.mode & CETIC_MODE_WSN_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(&wsn_ip_addr, &wsn_net_prefix); uip_ds6_set_addr_iid(&wsn_ip_addr, &uip_lladdr); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(wsn_ip_addr.u8, &nvm_data.wsn_ip_addr, sizeof(nvm_data.wsn_ip_addr)); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_MANUAL); } PRINTF("Tentative global IPv6 address "); PRINT6ADDR(&wsn_ip_addr.u8); PRINTF("\n"); memcpy(eth_dft_router.u8, &nvm_data.eth_dft_router, sizeof(nvm_data.eth_dft_router)); uip_ds6_defrt_add(ð_dft_router, 0); #if CETIC_6LBR_SMARTBRIDGE rpl_set_prefix(cetic_dag, &wsn_net_prefix, 64); #endif } //End manual configuration #if CETIC_6LBR_TRANSPARENTBRIDGE printf("Starting as Transparent-BRIDGE\n"); #else printf("Starting as Smart-BRIDGE\n"); #endif #else /* ROUTER */ //WSN network configuration memcpy(wsn_net_prefix.u8, &nvm_data.wsn_net_prefix, sizeof(nvm_data.wsn_net_prefix)); if((nvm_data.mode & CETIC_MODE_WSN_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(&wsn_ip_addr, &wsn_net_prefix); uip_ds6_set_addr_iid(&wsn_ip_addr, &uip_lladdr); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(wsn_ip_addr.u8, &nvm_data.wsn_ip_addr, sizeof(nvm_data.wsn_ip_addr)); uip_ds6_addr_add(&wsn_ip_addr, 0, ADDR_MANUAL); } PRINTF("Tentative global IPv6 address (WSN) "); PRINT6ADDR(&wsn_ip_addr.u8); PRINTF("\n"); //Ethernet network configuration memcpy(eth_net_prefix.u8, &nvm_data.eth_net_prefix, sizeof(nvm_data.eth_net_prefix)); if((nvm_data.mode & CETIC_MODE_ROUTER_SEND_CONFIG) != 0) { PRINTF("RA with autoconfig\n"); uip_ds6_prefix_add(ð_net_prefix, 64, 1, UIP_ND6_RA_FLAG_ONLINK | UIP_ND6_RA_FLAG_AUTONOMOUS, 30000, 30000); } else { PRINTF("RA without autoconfig\n"); uip_ds6_prefix_add(ð_net_prefix, 64, 0, 0, 0, 0); } memcpy(eth_dft_router.u8, &nvm_data.eth_dft_router, sizeof(nvm_data.eth_dft_router)); uip_ds6_defrt_add(ð_dft_router, 0); eth_mac64_addr.addr[0] = eth_mac_addr[0]; eth_mac64_addr.addr[1] = eth_mac_addr[1]; eth_mac64_addr.addr[2] = eth_mac_addr[2]; eth_mac64_addr.addr[3] = CETIC_6LBR_ETH_EXT_A; eth_mac64_addr.addr[4] = CETIC_6LBR_ETH_EXT_B; eth_mac64_addr.addr[5] = eth_mac_addr[3]; eth_mac64_addr.addr[6] = eth_mac_addr[4]; eth_mac64_addr.addr[7] = eth_mac_addr[5]; if((nvm_data.mode & CETIC_MODE_ETH_AUTOCONF) != 0) //Address auto configuration { uip_ipaddr_copy(ð_ip_addr, ð_net_prefix); uip_ds6_set_addr_iid(ð_ip_addr, ð_mac64_addr); uip_ds6_addr_add(ð_ip_addr, 0, ADDR_AUTOCONF); } else { memcpy(eth_ip_addr.u8, &nvm_data.eth_ip_addr, sizeof(nvm_data.eth_ip_addr)); uip_ds6_addr_add(ð_ip_addr, 0, ADDR_MANUAL); } PRINTF("Tentative global IPv6 address (ETH) "); PRINT6ADDR(ð_ip_addr.u8); PRINTF("\n"); rpl_set_prefix(cetic_dag, &wsn_net_prefix, 64); //Ugly hack : in order to set WSN local address as the default address //We must add it afterwards as uip_ds6_addr_add allocates addr from the end of the list uip_ds6_addr_rm(local); uip_create_linklocal_prefix(ð_ip_local_addr); uip_ds6_set_addr_iid(ð_ip_local_addr, ð_mac64_addr); uip_ds6_addr_add(ð_ip_local_addr, 0, ADDR_AUTOCONF); uip_ds6_addr_add(&wsn_ip_local_addr, 0, ADDR_AUTOCONF); uip_ds6_route_info_add(&wsn_net_prefix, 64, 0, 600); printf("Starting as ROUTER\n"); #endif }
/*---------------------------------------------------------------------------*/ void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio, int mobility) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p, *previous_preferred; uint32_t current_t; PRINTF("processing DIO from %u\n", from->u8[15]); if(dio->mop != RPL_MOP_DEFAULT) { PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } dag = get_dag(dio->instance_id, &dio->dag_id); instance = rpl_get_instance(dio->instance_id); previous_preferred = dag->preferred_parent; if(dag != NULL && instance != NULL) { if(lollipop_greater_than(dio->version, dag->version)) { if(dag->rank == ROOT_RANK(instance)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); dag->version = dio->version; RPL_LOLLIPOP_INCREMENT(dag->version); rpl_reset_dio_timer(instance); } else { PRINTF("RPL: Global Repair\n"); if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } global_repair(from, dag, dio); } return; } if(lollipop_greater_than(dag->version, dio->version)) { /* The DIO sender is on an older version of the DAG. */ PRINTF("RPL: old version received => inconsistency detected\n"); if(dag->joined) { rpl_reset_dio_timer(instance); return; } } } if(instance == NULL) { PRINTF("RPL: New instance detected: Joining...\n"); rpl_join_instance(from, dio); return; } if(instance->current_dag->rank == ROOT_RANK(instance) && instance->current_dag != dag) { PRINTF("RPL: Root ignored DIO for different DAG\n"); return; } if(dag == NULL) { PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); return; } if(dio->rank < ROOT_RANK(instance)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } else if(dio->rank == INFINITE_RANK && dag->joined) { rpl_reset_dio_timer(instance); } /* Prefix Information Option treated to add new prefix */ if(dio->prefix_info.length != 0) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { PRINTF("RPL : Prefix announced in DIO\n"); rpl_set_prefix(dag, &dio->prefix_info.prefix, dio->prefix_info.length); } } if(dag->rank == ROOT_RANK(instance)) { if(dio->rank != INFINITE_RANK) { instance->dio_counter++; } return; } /* * At this point, we know that this DIO pertains to a DAG that * we are already part of. We consider the sender of the DIO to be * a candidate parent, and let rpl_process_parent_event decide * whether to keep it in the set. */ p = rpl_find_parent(dag, from); if(p == NULL) { previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { /* Add the DIO sender as a candidate parent. */ p = rpl_add_parent(dag, dio, from); if(p == NULL) { PRINTF("RPL: Failed to add a new parent ("); PRINT6ADDR(from); PRINTF(")\n"); return; } PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); PRINT6ADDR(from); PRINTF("\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { rpl_move_parent(previous_dag, dag, p); } } } else { if(p->rank == dio->rank) { PRINTF("RPL: Received consistent DIO\n"); if(dag->joined) { instance->dio_counter++; } } else { p->rank = dio->rank; } } PRINTF("RPL: preferred DAG "); PRINT6ADDR(&instance->current_dag->dag_id); PRINTF(", rank %u, min_rank %u, ", instance->current_dag->rank, instance->current_dag->min_rank); PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n", p->rank, -1 /*p->mc.obj.etx */, p->link_metric, instance->mc.obj.etx); /* * If the DIO being processed came from smart-HOP decision, change default route, * schedule DAO and finish the mobility process. */ if(mobility) { rpl_remove_parent(previous_preferred); rpl_set_preferred_parent(dag, p); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); /*dao_output(p, 255);*/ /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ PRINTF("adding default route\n"); current_t = clock_time() * 1000 / CLOCK_SECOND; printf("End %u\n", current_t); rpl_set_default_route(instance, from); rpl_schedule_dao(instance); /*check_dao_ack = 1;*/ process_post(&tcpip_process, RESET_MOBILITY_FLAG, NULL); return; } if(mobility == 0) { #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ if(rpl_process_parent_event(instance, p) == 0) { PRINTF("RPL: The candidate parent is rejected\n"); return; } } /* We don't use route control, so we can have only one official parent. */ if(dag->joined && p == dag->preferred_parent) { if(should_send_dao(instance, dio, p)) { RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_schedule_dao(instance); } /* We received a new DIO from our preferred parent. * Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */ uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); } p->dtsn = dio->dtsn; }