/*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) { static struct etimer periodic; static struct ctimer backoff_timer; PROCESS_BEGIN(); PRINTF("Configuring sensors... "); leds_on(LEDS_GREEN); i2c_init(); leds_on(LEDS_YELLOW); if(i2c_start(ADG715_A|I2C_WRITE)){ leds_on(LEDS_RED); } i2c_write(0xFF); leds_off(LEDS_YELLOW); PRINTF("done!\n"); PROCESS_PAUSE(); set_global_address(); PRINTF("UDP client process started\n"); print_local_addresses(); /* new connection with remote host */ /* TEST PARA RAFA */ uip_ipaddr_t ipaddr; get_node_address(&ipaddr); ipaddr.u16[7] = 0xFFFF; PRINT6ADDR(&ipaddr); client_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL); udp_bind(client_conn, UIP_HTONS(UDP_CLIENT_PORT)); PRINTF("Created a connection with the server "); PRINT6ADDR(&client_conn->ripaddr); PRINTF(" local/remote port %u/%u\n", UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); etimer_set(&periodic, SEND_INTERVAL); while(1) { PROCESS_YIELD(); if(ev == tcpip_event) { tcpip_handler(); } if(etimer_expired(&periodic)) { etimer_reset(&periodic); ctimer_set(&backoff_timer, SEND_TIME, send_packet, NULL); } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ void uip_nd6_ra_output(uip_ipaddr_t * dest) { 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_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr); } else { /* For sollicited RA */ uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest); } uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); UIP_ICMP_BUF->type = ICMP6_RA; UIP_ICMP_BUF->icode = 0; UIP_ND6_RA_BUF->cur_ttl = uip_ds6_if.cur_hop_limit; UIP_ND6_RA_BUF->flags_reserved = (UIP_ND6_M_FLAG << 7) | (UIP_ND6_O_FLAG << 6); UIP_ND6_RA_BUF->router_lifetime = uip_htons(UIP_ND6_ROUTER_LIFETIME); //UIP_ND6_RA_BUF->reachable_time = uip_htonl(uip_ds6_if.reachable_time); //UIP_ND6_RA_BUF->retrans_timer = uip_htonl(uip_ds6_if.retrans_timer); UIP_ND6_RA_BUF->reachable_time = 0; UIP_ND6_RA_BUF->retrans_timer = 0; uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_RA_LEN; nd6_opt_offset = UIP_ND6_RA_LEN; /* Prefix list */ for(prefix = uip_ds6_prefix_list; prefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; prefix++) { if((prefix->isused) && (prefix->advertise)) { UIP_ND6_OPT_PREFIX_BUF->type = UIP_ND6_OPT_PREFIX_INFO; UIP_ND6_OPT_PREFIX_BUF->len = UIP_ND6_OPT_PREFIX_INFO_LEN / 8; UIP_ND6_OPT_PREFIX_BUF->preflen = prefix->length; UIP_ND6_OPT_PREFIX_BUF->flagsreserved1 = prefix->l_a_reserved; UIP_ND6_OPT_PREFIX_BUF->validlt = uip_htonl(prefix->vlifetime); UIP_ND6_OPT_PREFIX_BUF->preferredlt = uip_htonl(prefix->plifetime); UIP_ND6_OPT_PREFIX_BUF->reserved2 = 0; uip_ipaddr_copy(&(UIP_ND6_OPT_PREFIX_BUF->prefix), &(prefix->ipaddr)); nd6_opt_offset += UIP_ND6_OPT_PREFIX_INFO_LEN; uip_len += UIP_ND6_OPT_PREFIX_INFO_LEN; } } /* Source link-layer option */ create_llao((uint8_t *)UIP_ND6_OPT_HDR_BUF, UIP_ND6_OPT_SLLAO); uip_len += UIP_ND6_OPT_LLAO_LEN; nd6_opt_offset += UIP_ND6_OPT_LLAO_LEN; /* MTU */ UIP_ND6_OPT_MTU_BUF->type = UIP_ND6_OPT_MTU; UIP_ND6_OPT_MTU_BUF->len = UIP_ND6_OPT_MTU_LEN >> 3; UIP_ND6_OPT_MTU_BUF->reserved = 0; //UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(uip_ds6_if.link_mtu); UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(1500); uip_len += UIP_ND6_OPT_MTU_LEN; nd6_opt_offset += UIP_ND6_OPT_MTU_LEN; #if UIP_ND6_RA_RDNSS if(uip_nameserver_count() > 0) { uint8_t i = 0; uip_ipaddr_t *ip = &UIP_ND6_OPT_RDNSS_BUF->ip; uip_ipaddr_t *dns = NULL; UIP_ND6_OPT_RDNSS_BUF->type = UIP_ND6_OPT_RDNSS; UIP_ND6_OPT_RDNSS_BUF->reserved = 0; UIP_ND6_OPT_RDNSS_BUF->lifetime = uip_nameserver_next_expiration(); if(UIP_ND6_OPT_RDNSS_BUF->lifetime != UIP_NAMESERVER_INFINITE_LIFETIME) { UIP_ND6_OPT_RDNSS_BUF->lifetime -= clock_seconds(); } while((dns = uip_nameserver_get(i)) != NULL) { uip_ipaddr_copy(ip++, dns); i++; } UIP_ND6_OPT_RDNSS_BUF->len = UIP_ND6_OPT_RDNSS_LEN + (i << 1); PRINTF("%d nameservers reported\n", i); uip_len += UIP_ND6_OPT_RDNSS_BUF->len << 3; nd6_opt_offset += UIP_ND6_OPT_RDNSS_BUF->len << 3; } #endif /* UIP_ND6_RA_RDNSS */ UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); /*ICMP checksum */ UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); UIP_STAT(++uip_stat.nd6.sent); PRINTF("Sending RA to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF(" from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("\n"); return; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_server_process, ev, data) { uip_ipaddr_t ipaddr; struct uip_ds6_addr *root_if; PROCESS_BEGIN(); PROCESS_PAUSE(); SENSORS_ACTIVATE(button_sensor); PRINTF("UDP server started\n"); #if UIP_CONF_ROUTER uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 1); /* uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); */ uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL); root_if = uip_ds6_addr_lookup(&ipaddr); if(root_if != NULL) { /*Changed*/ rpl_dag_t *dag; dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr); uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); rpl_set_prefix(dag, &ipaddr, 64); PRINTF("created a new RPL dag\n"); #if PROJ_SMLT_TYPE rpl_dag_t *dag1; dag1 = rpl_set_root(RPL_SECOND_INSTANCE,(uip_ip6addr_t *)&ipaddr); rpl_set_prefix(dag1, &ipaddr, 64); PRINTF("created a new RPL dag\n"); #endif } else { PRINTF("failed to create a new RPL DAG\n"); } #endif /* UIP_CONF_ROUTER */ print_local_addresses(); /* The data sink runs with a 100% duty cycle in order to ensure high packet reception rates. */ NETSTACK_RDC.off(1); server_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL); udp_bind(server_conn, UIP_HTONS(UDP_SERVER_PORT)); PRINTF("Created a server connection with remote address "); PRINT6ADDR(&server_conn->ripaddr); PRINTF(" local/remote port %u/%u\n", UIP_HTONS(server_conn->lport), UIP_HTONS(server_conn->rport)); while(1) { PROCESS_YIELD(); if(ev == tcpip_event) { tcpip_handler(); } else if (ev == sensors_event && data == &button_sensor) { PRINTF("Initiaing global repair\n"); rpl_repair_root(RPL_DEFAULT_INSTANCE); #if PROJ_SMLT_TYPE /*Changed*/ rpl_repair_root(RPL_SECOND_INSTANCE); #endif } } PROCESS_END(); }
static int coap_receive(void) { coap_error_code = NO_ERROR; PRINTF("handle_incoming_data(): received uip_datalen=%u \n", (uint16_t)uip_datalen()); if (uip_newdata()) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() ); PRINTBITS(uip_appdata, uip_datalen()); PRINTF("\n"); coap_error_code = coap_parse_message(message, uip_appdata, uip_datalen()); if (coap_error_code==NO_ERROR) { /*TODO duplicates suppression, if required by application */ PRINTF(" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version, message->type, message->token_len, message->code, message->mid); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); /* Handle requests. */ if (message->code >= COAP_GET && message->code <= COAP_DELETE) { #if COAP_CEU int ret; TCEU_Transaction t = { message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, request1, NULL, NULL, NULL, 0, {} }; tceu__int___void_ ps = { &ret, &t }; ceu_go_event(CEU_IN_COAP_REQUEST, &ps); if (! ret) { coap_error_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } #else /* Use transaction buffer for response to confirmable request. */ if ( (transaction = coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) ) { request1(transaction,NULL); } else { coap_error_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if (transaction buffer) */ #endif } else { /* Responses */ if (message->type==COAP_TYPE_CON && message->code==0) { PRINTF("Received Ping\n"); coap_error_code = PING_RESPONSE; } else if (message->type==COAP_TYPE_ACK) { /* Transactions are closed through lookup below */ PRINTF("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ #ifdef COAP_OBSERVER coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); #endif } #if COAP_CEU ceu_go_event(CEU_IN_COAP_RESPONSE, message); #else if ( (transaction = coap_get_transaction_by_mid(message->mid)) ) { /* Free transaction memory before callback, as it may create a new transaction. */ restful_response_handler callback = transaction->callback; void *callback_data = transaction->callback_data; coap_clear_transaction(transaction); /* Check if someone registered for the response */ if (callback) { callback(callback_data, message); } } /* if (ACKed transaction) */ transaction = NULL; #endif } /* Request or Response */ } /* if (parsed correctly) */ if (coap_error_code==NO_ERROR) { #if ! COAP_CEU if (transaction) coap_send_transaction(transaction); #endif } else if (coap_error_code==MANUAL_RESPONSE) /* TODO! */ { PRINTF("Clearing transaction for manual response"); #if ! COAP_CEU coap_clear_transaction(transaction); #endif } else { coap_message_type_t reply_type = COAP_TYPE_ACK; PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message); #if ! COAP_CEU coap_clear_transaction(transaction); #endif /* Set to sendable error code. */ if (coap_error_code >= 192) { coap_error_code = INTERNAL_SERVER_ERROR_5_00; } if (coap_error_code == PING_RESPONSE) { coap_error_code = 0; reply_type = COAP_TYPE_RST; } /* Reuse input buffer for error message. */ coap_init_message(message, reply_type, coap_error_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); } } /* if (new data) */ return coap_error_code; }
/** * 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) { uint8_t is_llchange; uint8_t is_router; uint8_t is_solicited; uint8_t is_override; uip_lladdr_t lladdr_aligned; 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 { const uip_lladdr_t *lladdr; nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); if(nbr == NULL) { goto discard; } lladdr = uip_ds6_nbr_get_ll(nbr); if(lladdr == NULL) { goto discard; } if(nd6_opt_llao != NULL) { is_llchange = memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN); } if(nbr->state == NBR_INCOMPLETE) { if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) { goto discard; } if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { /* failed to update the lladdr */ goto discard; } /* Note: No need to refresh the state of the nbr here. * It has already been refreshed upon receiving the unicast IPv6 ND packet. * See: uip_ds6_nbr_refresh_reachable_state() */ if(!is_solicited) { nbr->state = NBR_STALE; } nbr->isrouter = is_router; } else { /* NBR is not INCOMPLETE */ if(!is_override && is_llchange) { if(nbr->state == NBR_REACHABLE) { nbr->state = NBR_STALE; } goto discard; } else { /** * If this is an cache override, or same lladdr, or no llao - * do updates of nbr states. */ if(is_override || !is_llchange || nd6_opt_llao == NULL) { if(nd6_opt_llao != NULL && is_llchange) { if(!extract_lladdr_from_llao_aligned(&lladdr_aligned) || nbr_table_update_lladdr((const linkaddr_t *) lladdr, (const linkaddr_t *) &lladdr_aligned, 1) == 0) { /* failed to update the lladdr */ goto discard; } } /* Note: No need to refresh the state of the nbr here. * It has already been refreshed upon receiving the unicast IPv6 ND packet. * See: uip_ds6_nbr_refresh_reachable_state() */ } } 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; }
/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id) { rpl_dag_t *dag; rpl_instance_t *instance; uint8_t version; int i; version = RPL_LOLLIPOP_INIT; instance = rpl_get_instance(instance_id); if(instance != NULL) { for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) { dag = &instance->dag_table[i]; if(dag->used) { if(uip_ipaddr_cmp(&dag->dag_id, dag_id)) { version = dag->version; RPL_LOLLIPOP_INCREMENT(version); } if(dag == dag->instance->current_dag) { PRINTF("RPL: Dropping a joined DAG when setting this node as root"); dag->instance->current_dag = NULL; } else { PRINTF("RPL: Dropping a DAG when setting this node as root"); } rpl_free_dag(dag); } } } dag = rpl_alloc_dag(instance_id, dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG\n"); return NULL; } instance = dag->instance; dag->version = version; dag->joined = 1; dag->grounded = RPL_GROUNDED; dag->preference = RPL_PREFERENCE; instance->mop = RPL_MOP_DEFAULT; instance->of = &RPL_OF; rpl_set_preferred_parent(dag, NULL); memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS; instance->dio_intmin = RPL_DIO_INTERVAL_MIN; /* The current interval must differ from the minimum interval in order to trigger a DIO timer reset. */ instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN + RPL_DIO_INTERVAL_DOUBLINGS; instance->dio_redundancy = RPL_DIO_REDUNDANCY; instance->max_rankinc = RPL_MAX_RANKINC; instance->min_hoprankinc = RPL_MIN_HOPRANKINC; instance->default_lifetime = RPL_DEFAULT_LIFETIME; instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; dag->rank = ROOT_RANK(instance); if(instance->current_dag != dag && instance->current_dag != NULL) { /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_dag); instance->current_dag->joined = 0; } instance->current_dag = dag; instance->dtsn_out = RPL_LOLLIPOP_INIT; instance->of->update_metric_container(instance); default_instance = instance; PRINTF("RPL: Node set to be a DAG root with DAG ID "); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); ANNOTATE("#A root=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_reset_dio_timer(instance); return dag; }
/*---------------------------------------------------------------------------*/ void rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag; rpl_parent_t *p; rpl_of_t *of; /* Determine the objective function by using the objective code point of the DIO. */ of = rpl_find_of(dio->ocp); if(of == NULL) { PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF: %u\n", dio->instance_id, dio->ocp); return; } dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG object!\n"); return; } instance = dag->instance; p = rpl_add_parent(dag, dio, from); PRINTF("RPL: Adding "); PRINT6ADDR(from); PRINTF(" as a parent: "); if(p == NULL) { PRINTF("failed\n"); instance->used = 0; return; } p->dtsn = dio->dtsn; PRINTF("succeeded\n"); /* Autoconfigure an address if this node does not already have an address with this prefix. */ if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { check_prefix(NULL, &dio->prefix_info); } dag->joined = 1; dag->preference = dio->preference; dag->grounded = dio->grounded; dag->version = dio->version; instance->of = of; instance->mop = dio->mop; instance->current_dag = dag; instance->dtsn_out = RPL_LOLLIPOP_INIT; instance->max_rankinc = dio->dag_max_rankinc; instance->min_hoprankinc = dio->dag_min_hoprankinc; instance->dio_intdoubl = dio->dag_intdoubl; instance->dio_intmin = dio->dag_intmin; instance->dio_intcurrent = instance->dio_intmin + instance->dio_intdoubl; instance->dio_redundancy = dio->dag_redund; instance->default_lifetime = dio->default_lifetime; instance->lifetime_unit = dio->lifetime_unit; memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id)); /* Copy prefix information from the DIO into the DAG object. */ memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t)); rpl_set_preferred_parent(dag, p); instance->of->update_metric_container(instance); dag->rank = instance->of->calculate_rank(p, 0); /* So far this is the lowest rank we are aware of. */ dag->min_rank = dag->rank; if(default_instance == NULL) { default_instance = instance; } PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", dio->instance_id, dag->rank); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_reset_dio_timer(instance); rpl_set_default_route(instance, from); if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { rpl_schedule_dao(instance); } else { PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n"); } }
/*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * uip_ds6_nbr_add(uip_ipaddr_t *ipaddr, uip_lladdr_t * lladdr, uint8_t isrouter, uint8_t state) { int r; PRINTF("NBR ADD"); r = uip_ds6_list_loop ((uip_ds6_element_t *)uip_ds6_nbr_cache, UIP_DS6_NBR_NB, sizeof(uip_ds6_nbr_t), ipaddr, 128, (uip_ds6_element_t **)&locnbr); if(r == FREESPACE) { locnbr->isused = 1; uip_ipaddr_copy(&locnbr->ipaddr, ipaddr); if(lladdr != NULL) { memcpy(&locnbr->lladdr, lladdr, UIP_LLADDR_LEN); } else { memset(&locnbr->lladdr, 0, UIP_LLADDR_LEN); } locnbr->isrouter = isrouter; locnbr->state = state; #if UIP_CONF_IPV6_QUEUE_PKT uip_packetqueue_new(&locnbr->packethandle); #endif /* UIP_CONF_IPV6_QUEUE_PKT */ /* timers are set separately, for now we put them in expired state */ stimer_set(&locnbr->reachable, 0); stimer_set(&locnbr->sendns, 0); locnbr->nscount = 0; PRINTF("Adding neighbor with ip addr "); PRINT6ADDR(ipaddr); PRINTF("link addr "); PRINTLLADDR((&(locnbr->lladdr))); PRINTF("state u");//, state); NEIGHBOR_STATE_CHANGED(locnbr); locnbr->last_lookup = clock_time(); return locnbr; } else if(r == NOSPACE) { /* We did not find any empty slot on the neighbor list, so we need to remove one old entry to make room. */ uip_ds6_nbr_t *n, *oldest; clock_time_t oldest_time; oldest = NULL; oldest_time = clock_time(); for(n = uip_ds6_nbr_cache; n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB]; n++) { if(n->isused) { if(n->last_lookup < oldest_time) { oldest = n; oldest_time = n->last_lookup; } } } if(oldest != NULL) { uip_ds6_nbr_rm(oldest); return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state); } } PRINTF("uip_ds6_nbr_add drop"); return NULL; }
/* N: the node joins the DAG - Directed Acyclic Graph */ static void join_dag(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_dag_t *dag; rpl_parent_t *p; rpl_of_t *of; dag = rpl_alloc_dag(dio->instance_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG object!\n"); return; } p = rpl_add_parent(dag, dio, from); PRINTF("RPL: Adding "); PRINT6ADDR(from); PRINTF(" as a parent: "); if(p == NULL) { PRINTF("failed\n"); return; } PRINTF("succeeded\n"); /* Determine the objective function by using the objective code point of the DIO. */ of = rpl_find_of(dio->ocp); if(of == NULL) { PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF\n", dio->instance_id); return; } /* Autoconfigure an address if this node does not already have an address with this prefix. */ if((dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) { uip_ipaddr_t ipaddr; /* assume that the prefix ends with zeros! */ memcpy(&ipaddr, &dio->prefix_info.prefix, 16); uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); if(uip_ds6_addr_lookup(&ipaddr) == NULL) { PRINTF("RPL: adding global IP address "); PRINT6ADDR(&ipaddr); PRINTF("\n"); uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); } } dag->joined = 1; dag->used = 1; dag->of = of; dag->grounded = dio->grounded; dag->mop = dio->mop; dag->preference = dio->preference; dag->instance_id = dio->instance_id; dag->max_rankinc = dio->dag_max_rankinc; dag->min_hoprankinc = dio->dag_min_hoprankinc; dag->version = dio->version; dag->preferred_parent = p; dag->of->update_metric_container(dag); dag->dio_intdoubl = dio->dag_intdoubl; dag->dio_intmin = dio->dag_intmin; dag->dio_redundancy = dio->dag_redund; memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id)); /* copy prefix information into the dag */ memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t)); dag->rank = dag->of->calculate_rank(p, dio->rank); dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */ PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", dio->instance_id, dag->rank); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); ANNOTATE("#A join=%u\n",dag->dag_id.u8[sizeof(dag->dag_id) - 1]); dag->default_lifetime = dio->default_lifetime; dag->lifetime_unit = dio->lifetime_unit; rpl_reset_dio_timer(dag, 1); rpl_set_default_route(dag, from); if(should_send_dao(dag, dio, p)) { rpl_schedule_dao(dag); } else { PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n"); } }
/** * 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) { 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(&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_len = 0; return; }
/*---------------------------------------------------------------------------*/ void uip_ds6_periodic(void) { /* Periodic processing on unicast addresses */ for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if(locaddr->isused) { if((!locaddr->isinfinite) && (stimer_expired(&locaddr->vlifetime))) { uip_ds6_addr_rm(locaddr); } else if((locaddr->state == ADDR_TENTATIVE) && (locaddr->dadnscount <= uip_ds6_if.maxdadns) && (timer_expired(&locaddr->dadtimer))) { uip_ds6_dad(locaddr); } } } /* Periodic processing on default routers */ for(locdefrt = uip_ds6_defrt_list; locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) { if((locdefrt->isused) && (!locdefrt->isinfinite) && (stimer_expired(&(locdefrt->lifetime)))) { uip_ds6_defrt_rm(locdefrt); } } #if !UIP_CONF_ROUTER /* Periodic processing on prefixes */ for(locprefix = uip_ds6_prefix_list; locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; locprefix++) { if(locprefix->isused && !locprefix->isinfinite && stimer_expired(&(locprefix->vlifetime))) { uip_ds6_prefix_rm(locprefix); } } #endif /* !UIP_CONF_ROUTER */ /* Periodic processing on neighbors */ for(locnbr = uip_ds6_nbr_cache; locnbr < uip_ds6_nbr_cache + UIP_DS6_NBR_NB; locnbr++) { if(locnbr->isused) { switch(locnbr->state) { case NBR_INCOMPLETE: if(locnbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&locnbr->sendns)) { locnbr->nscount++; PRINTF("NBR_INCOMPLETE: NS u");//, locnbr->nscount); uip_nd6_ns_output(NULL, NULL, &locnbr->ipaddr); stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; case NBR_REACHABLE: if(stimer_expired(&locnbr->reachable)) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&locnbr->ipaddr); PRINTF(")"); locnbr->state = NBR_STALE; } break; case NBR_DELAY: if(stimer_expired(&locnbr->reachable)) { locnbr->state = NBR_PROBE; locnbr->nscount = 1; PRINTF("DELAY: moving to PROBE + NS u");//, locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr); stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; case NBR_PROBE: if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { PRINTF("PROBE END"); if((locdefrt = uip_ds6_defrt_lookup(&locnbr->ipaddr)) != NULL) { uip_ds6_defrt_rm(locdefrt); } uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&locnbr->sendns)) { locnbr->nscount++; PRINTF("PROBE: NS u");//, locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr); stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; default: break; } } } #if UIP_CONF_ROUTER & UIP_ND6_SEND_RA /* Periodic RA sending */ if(stimer_expired(&uip_ds6_timer_ra)) { uip_ds6_send_ra_periodic(); } #endif /* UIP_CONF_ROUTER & UIP_ND6_SEND_RA */ etimer_reset(&uip_ds6_timer_periodic); return; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) { static struct etimer periodic; static struct ctimer backoff_timer; #if WITH_COMPOWER static int print = 0; #endif PROCESS_BEGIN(); PROCESS_PAUSE(); set_global_address(); PRINTF("UDP client process started\n"); print_local_addresses(); /* new connection with remote host */ client_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL); if(client_conn == NULL) { PRINTF("No UDP connection available, exiting the process!\n"); PROCESS_EXIT(); } udp_bind(client_conn, UIP_HTONS(UDP_CLIENT_PORT)); PRINTF("Created a connection with the server "); PRINT6ADDR(&client_conn->ripaddr); PRINTF(" local/remote port %u/%u\n", UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); // printf("%d \n", CLOCK_SECOND); #if WITH_COMPOWER powertrace_sniff(POWERTRACE_ON); #endif configure_adc(); //etimer_set(&periodic, SEND_INTERVAL); while(1) { PROCESS_YIELD(); if(ev == tcpip_event) { // tcpip_handler(); } //if(etimer_expired(&periodic)) { //PRINTF("Timer Expired "); //etimer_reset(&periodic); //} if(ev==event_data_ready) { /*if(counter == 33) { memmove(buf+2, buffer, 66); counter = 0; ctimer_set(&backoff_timer, SEND_TIME, send_packet, NULL); //printf("Counter %d \n",counter); }*/ #if WITH_COMPOWER if (print == 0) { powertrace_print("#P"); } if (++print == 3) { print = 0; } #endif } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop) { uip_ds6_route_t *r; #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 */ 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 "); PRINT6ADDR(ipaddr); 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 just update the old one. */ r = uip_ds6_route_lookup(ipaddr); if(r != NULL) { PRINTF("uip_ds6_route_add: old route already found, updating this one instead: "); PRINT6ADDR(ipaddr); PRINTF("\n"); } else { struct uip_ds6_route_neighbor_routes *routes; /* If there is no routing entry, create one */ /* 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, (rimeaddr_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, (rimeaddr_t *)nexthop_lladdr); if(routes == NULL) { PRINTF("uip_ds6_route_add: could not allocate a neighbor table entri for new route to "); PRINT6ADDR(ipaddr); PRINTF(", dropping it\n"); return NULL; } LIST_STRUCT_INIT(routes, route_list); } /* Allocate a routing entry and populate it. */ r = memb_alloc(&routememb); if(r == NULL) { PRINTF("uip_ds6_route_add: could not allocate memory for new route to "); PRINT6ADDR(ipaddr); PRINTF(", dropping it\n"); return NULL; } /* Add the route to this neighbor */ list_add(routes->route_list, r); num_routes++; PRINTF("uip_ds6_route_add num %d\n", num_routes); r->routes = 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 //QUICK INIT HACK ADILA EDIT 10/11/14 /*if(r->nbrCh == 0) { r->nbrCh = 26; }*/ //r->nbrCh = cc2420_get_channel(); //------------------- 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; }
/*---------------------------------------------------------------------------*/ void uip_process() { PRINTF("NEW packet\n"); /* Check validity of the IP header. */ if((UIP_IP_BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ PRINTF("Wrong IP Version\n"); goto drop; } /* * Check the size of the packet. If the size reported to us in * uip_len is smaller the size reported in the IP header, we assume * that the packet has been corrupted in transit. If the size of * uip_len is larger than the size reported in the IP packet header, * the packet has been padded and we set uip_len to the correct * value.. */ if((UIP_IP_BUF->len[0] << 8) + UIP_IP_BUF->len[1] <= uip_len) { uip_len = (UIP_IP_BUF->len[0] << 8) + UIP_IP_BUF->len[1] + UIP_IPH_LEN; /* * The length reported in the IPv6 header is the * length of the payload that follows the * header. However, uIP uses the uip_len variable * for holding the size of the entire packet, * including the IP header. For IPv4 this is not a * problem as the length field in the IPv4 header * contains the length of the entire packet. But * for IPv6 we need to add the size of the IPv6 * header (40 bytes). */ } else { PRINTF("Wrong Length\n"); goto drop; } PRINTF("IPv6 packet received from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(" to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); if(uip_is_addr_mcast(&UIP_IP_BUF->srcipaddr)){ PRINTF("Dropping packet, src is mcast\n"); goto drop; } /* * Next header field processing. In IPv6, we can have extension headers, * if present, the Hop-by-Hop Option must be processed before forwarding * the packet. */ uip_next_hdr = &UIP_IP_BUF->proto; uip_ext_len = 0; uip_ext_bitmap = 0; if (*uip_next_hdr == UIP_PROTO_HBHO) { #if UIP_CONF_IPV6_CHECKS uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_HBHO; #endif /*UIP_CONF_IPV6_CHECKS*/ switch(ext_hdr_options_process()) { case 0: /*continue*/ uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case 1: /*silently discard*/ goto drop; case 2: /* send icmp error message (created in ext_hdr_options_process) * and discard*/ goto send; } } /* TBD Some Parameter problem messages */ if(!uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr) && !uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) { if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) && !uip_is_addr_link_local(&UIP_IP_BUF->destipaddr) && !uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) && !uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr) && !uip_is_addr_loopback(&UIP_IP_BUF->destipaddr)) { /* Check MTU */ if(uip_len > UIP_LINK_MTU) { uip_icmp6_error_output(ICMP6_PACKET_TOO_BIG, 0, UIP_LINK_MTU); goto send; } /* Check Hop Limit */ if(UIP_IP_BUF->ttl <= 1) { uip_icmp6_error_output(ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); goto send; } UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1; PRINTF("Forwarding packet to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); goto send; } else { if((uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) && (!uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) && (!uip_is_addr_loopback(&UIP_IP_BUF->destipaddr)) && (!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) && (!uip_ds6_is_addr_onlink((&UIP_IP_BUF->destipaddr)))) { PRINTF("LL source address with off link destination, dropping\n"); uip_icmp6_error_output(ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR, 0); goto send; } PRINTF("Dropping packet, not for me and link local or multicast\n"); goto drop; } } while(1) { switch(*uip_next_hdr){ case UIP_PROTO_ICMP6: /* ICMPv6 */ goto icmp6_input; case UIP_PROTO_HBHO: PRINTF("Processing hbh header\n"); /* Hop by hop option header */ #if UIP_CONF_IPV6_CHECKS /* Hop by hop option header. If we saw one HBH already, drop */ if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_HBHO) { goto bad_hdr; } else { uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_HBHO; } #endif /*UIP_CONF_IPV6_CHECKS*/ switch(ext_hdr_options_process()) { case 0: /*continue*/ uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case 1: /*silently discard*/ goto drop; case 2: /* send icmp error message (created in ext_hdr_options_process) * and discard*/ goto send; } break; case UIP_PROTO_DESTO: #if UIP_CONF_IPV6_CHECKS /* Destination option header. if we saw two already, drop */ PRINTF("Processing desto header\n"); if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_DESTO1) { if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_DESTO2) { goto bad_hdr; } else{ uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_DESTO2; } } else { uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_DESTO1; } #endif /*UIP_CONF_IPV6_CHECKS*/ switch(ext_hdr_options_process()) { case 0: /*continue*/ uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case 1: /*silently discard*/ goto drop; case 2: /* send icmp error message (created in ext_hdr_options_process) * and discard*/ goto send; } break; case UIP_PROTO_ROUTING: #if UIP_CONF_IPV6_CHECKS /* Routing header. If we saw one already, drop */ if(uip_ext_bitmap & UIP_EXT_HDR_BITMAP_ROUTING) { goto bad_hdr; } else { uip_ext_bitmap |= UIP_EXT_HDR_BITMAP_ROUTING; } #endif /*UIP_CONF_IPV6_CHECKS*/ /* * Routing Header length field is in units of 8 bytes, excluding * As per RFC2460 section 4.4, if routing type is unrecognized: * if segments left = 0, ignore the header * if segments left > 0, discard packet and send icmp error pointing * to the routing type */ PRINTF("Processing Routing header\n"); if(UIP_ROUTING_BUF->seg_left > 0) { uip_icmp6_error_output(ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, UIP_IPH_LEN + uip_ext_len + 2); goto send; } uip_next_hdr = &UIP_EXT_BUF->next; uip_ext_len += (UIP_EXT_BUF->len << 3) + 8; break; case UIP_PROTO_FRAG: /* Fragmentation header:call the reassembly function, then leave */ goto drop; case UIP_PROTO_NONE: goto drop; default: goto bad_hdr; } } bad_hdr: /* * RFC 2460 send error message parameterr problem, code unrecognized * next header, pointing to the next header field */ uip_icmp6_error_output(ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER, (u32_t)(uip_next_hdr - (uint8_t *)UIP_IP_BUF)); goto send; /* End of headers processing */ icmp6_input: /* This is IPv6 ICMPv6 processing code. */ PRINTF("icmp6_input: length %d\n", uip_len); #if UIP_CONF_IPV6_CHECKS /* Compute and check the ICMP header checksum */ if(uip_icmp6chksum() != 0xffff) { goto drop; } #endif /*UIP_CONF_IPV6_CHECKS*/ /* * Here we process incoming ICMPv6 packets * For echo request, we send echo reply * For ND pkts, we call the appropriate function in uip-nd6.c * We do not treat Error messages for now * If no pkt is to be sent as an answer to the incoming one, we * "goto drop". Else we just break; then at the after the "switch" * we "goto send" */ switch(UIP_ICMP_BUF->type) { case ICMP6_NS: uip_len = 0; break; case ICMP6_NA: uip_len = 0; break; case ICMP6_RS: uip_len = 0; break; case ICMP6_RA: uip_len = 0; break; case ICMP6_RPL: uip_rpl_input(); break; case ICMP6_ECHO_REQUEST: uip_icmp6_echo_request_input(); break; case ICMP6_ECHO_REPLY: /** \note We don't implement any application callback for now */ PRINTF("Received an icmp6 echo reply\n"); uip_len = 0; break; default: PRINTF("Unknown icmp6 message type %d\n", UIP_ICMP_BUF->type); uip_len = 0; break; } if(uip_len > 0) { goto send; } else { goto drop; } /* End of IPv6 ICMP processing. */ UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0x00; UIP_IP_BUF->flow = 0x00; send: PRINTF("Sending packet with length %d (%d)\n", uip_len, (UIP_IP_BUF->len[0] << 8) | UIP_IP_BUF->len[1]); /* Return and let the caller do the actual transmission. */ return; drop: uip_len = 0; uip_ext_len = 0; uip_ext_bitmap = 0; return; }
/*---------------------------------------------------------------------------*/ void rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_instance_t *instance; rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; rpl_of_t *of; dag = rpl_alloc_dag(dio->instance_id, &dio->dag_id); if(dag == NULL) { PRINTF("RPL: Failed to allocate a DAG object!\n"); return; } instance = dag->instance; previous_dag = find_parent_dag(instance, from); if(previous_dag == NULL) { PRINTF("RPL: Adding "); PRINT6ADDR(from); PRINTF(" as a parent: "); p = rpl_add_parent(dag, dio, from); if(p == NULL) { PRINTF("failed\n"); dag->used = 0; return; } PRINTF("succeeded\n"); } else { p = rpl_find_parent(previous_dag, from); if(p != NULL) { rpl_move_parent(previous_dag, dag, p); } } p->rank = dio->rank; /* Determine the objective function by using the objective code point of the DIO. */ of = rpl_find_of(dio->ocp); if(of != instance->of || instance->mop != dio->mop || instance->max_rankinc != dio->dag_max_rankinc || instance->min_hoprankinc != dio->dag_min_hoprankinc || instance->dio_intdoubl != dio->dag_intdoubl || instance->dio_intmin != dio->dag_intmin || instance->dio_redundancy != dio->dag_redund || instance->default_lifetime != dio->default_lifetime || instance->lifetime_unit != dio->lifetime_unit) { PRINTF("RPL: DIO for DAG instance %u incompatible with previous DIO\n", dio->instance_id); rpl_remove_parent(p); dag->used = 0; return; } dag->used = 1; dag->grounded = dio->grounded; dag->preference = dio->preference; dag->version = dio->version; memcpy(&dag->dag_id, &dio->dag_id, sizeof(dio->dag_id)); /* copy prefix information into the dag */ memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t)); rpl_set_preferred_parent(dag, p); dag->rank = instance->of->calculate_rank(p, 0); dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */ PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ", dio->instance_id, dag->rank); PRINT6ADDR(&dag->dag_id); PRINTF("\n"); ANNOTATE("#A join=%u\n", dag->dag_id.u8[sizeof(dag->dag_id) - 1]); rpl_process_parent_event(instance, p); p->dtsn = dio->dtsn; }
void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_dag_t *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 = rpl_get_dag(dio->instance_id); if(dag == NULL) { /* Join the first possible DAG of this RPL instance. */ if(dio->rank != INFINITE_RANK) { join_dag(from, dio); } else { PRINTF("RPL: Ignoring DIO from node with infinite rank: "); PRINT6ADDR(from); PRINTF("\n"); } return; } if(memcmp(&dag->dag_id, &dio->dag_id, sizeof(dag->dag_id))) { PRINTF("RPL: Ignoring DIO for another DAG within our instance\n"); return; } if(dio->version > dag->version) { if(dag->rank == ROOT_RANK(dag)) { PRINTF("RPL: Root received inconsistent DIO version number\n"); dag->version = dio->version + 1; rpl_reset_dio_timer(dag, 1); } else { global_repair(from, dag, dio); } return; } else if(dio->version < dag->version) { /* Inconsistency detected - someone is still on old version */ PRINTF("RPL: old version received => inconsistency detected\n"); rpl_reset_dio_timer(dag, 1); return; } if(dio->rank == INFINITE_RANK) { rpl_reset_dio_timer(dag, 1); } else if(dio->rank < ROOT_RANK(dag)) { PRINTF("RPL: Ignoring DIO with too low rank: %u\n", (unsigned)dio->rank); return; } if(dag->rank == ROOT_RANK(dag)) { if(dio->rank != INFINITE_RANK) { dag->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) { if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS) { /* 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 if(DAG_RANK(p->rank, dag) == DAG_RANK(dio->rank, dag)) { PRINTF("RPL: Received consistent DIO\n"); dag->dio_counter++; } /* We have allocated a candidate parent; process the DIO further. */ memcpy(&p->mc, &dio->mc, sizeof(p->mc)); p->rank = dio->rank; if(rpl_process_parent_event(dag, p) == 0) { /* The candidate parent no longer exists. */ return; } if(should_send_dao(dag, dio, p)) { rpl_schedule_dao(dag); } 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 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(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) { #if RPL_MAX_DAG_PER_INSTANCE > 1 PRINTF("RPL: Adding new DAG to known instance.\n"); rpl_add_dag(from, dio); 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)) / 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. */ 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_purge_routes(void) { uip_ds6_route_t *r; uip_ipaddr_t prefix; rpl_dag_t *dag; #if RPL_CONF_MULTICAST uip_mcast6_route_t *mcast_route; #endif /* 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) { 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); dag = default_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(default_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); } } #if RPL_CONF_MULTICAST mcast_route = uip_mcast6_route_list_head(); while(mcast_route != NULL) { if(mcast_route->lifetime <= 1) { uip_mcast6_route_rm(mcast_route); mcast_route = uip_mcast6_route_list_head(); } else { mcast_route->lifetime--; mcast_route = list_item_next(mcast_route); } } #endif }
/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) { rpl_parent_t *last_parent; rpl_dag_t *dag, *end, *best_dag; rpl_rank_t old_rank; old_rank = instance->current_dag->rank; last_parent = instance->current_dag->preferred_parent; best_dag = instance->current_dag; if(best_dag->rank != ROOT_RANK(instance)) { if(rpl_select_parent(p->dag) != NULL) { if(p->dag != best_dag) { best_dag = instance->of->best_dag(best_dag, p->dag); } } else if(p->dag == best_dag) { best_dag = NULL; for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) { if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) { if(best_dag == NULL) { best_dag = dag; } else { best_dag = instance->of->best_dag(best_dag, dag); } } } } } if(best_dag == NULL) { /* No parent found: the calling function handle this problem. */ return NULL; } if(instance->current_dag != best_dag) { /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_dag); PRINTF("RPL: New preferred DAG: "); PRINT6ADDR(&best_dag->dag_id); PRINTF("\n"); if(best_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { check_prefix(&instance->current_dag->prefix_info, &best_dag->prefix_info); } else if(instance->current_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { check_prefix(&instance->current_dag->prefix_info, NULL); } best_dag->joined = 1; instance->current_dag->joined = 0; instance->current_dag = best_dag; } instance->of->update_metric_container(instance); /* Update the DAG rank. */ best_dag->rank = instance->of->calculate_rank(best_dag->preferred_parent, 0); if(last_parent == NULL || best_dag->rank < best_dag->min_rank) { best_dag->min_rank = best_dag->rank; } else if(!acceptable_rank(best_dag, best_dag->rank)) { PRINTF("RPL: New rank unacceptable!\n"); rpl_set_preferred_parent(instance->current_dag, NULL); if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) { /* Send a No-Path DAO to the removed preferred parent. */ dao_output(last_parent, RPL_ZERO_LIFETIME); } return NULL; } if(best_dag->preferred_parent != last_parent) { rpl_set_default_route(instance, rpl_get_parent_ipaddr(best_dag->preferred_parent)); PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); RPL_STAT(rpl_stats.parent_switch++); if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { if(last_parent != NULL) { /* Send a No-Path DAO to the removed preferred parent. */ dao_output(last_parent, RPL_ZERO_LIFETIME); } /* The DAO parent set changed - schedule a DAO transmission. */ RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_schedule_dao(instance); } rpl_reset_dio_timer(instance); #if DEBUG rpl_print_neighbor_list(); #endif } else if(best_dag->rank != old_rank) { PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); } return best_dag; }
/*---------------------------------------------------------------------------*/ 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) { uip_ipaddr_t *current_nexthop; current_nexthop = uip_ds6_route_nexthop(r); if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) { /* no need to update route - already correct! */ return r; } 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); /* lock this entry so that nexthop is not removed */ nbr_table_lock(nbr_routes, 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; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_server_process, ev, data) { uip_ipaddr_t ipaddr; struct uip_ds6_addr *root_if; PROCESS_BEGIN(); PROCESS_PAUSE(); SENSORS_ACTIVATE(button_sensor); PRINTF("UDP server started\n"); #if UIP_CONF_ROUTER /* The choice of server address determines its 6LoPAN header compression. * Obviously the choice made here must also be selected in udp-client.c. * * For correct Wireshark decoding using a sniffer, add the /64 prefix to the 6LowPAN protocol preferences, * e.g. set Context 0 to aaaa::. At present Wireshark copies Context/128 and then overwrites it. * (Setting Context 0 to aaaa::1111:2222:3333:4444 will report a 16 bit compressed address of aaaa::1111:22ff:fe33:xxxx) * Note Wireshark's IPCMV6 checksum verification depends on the correct uncompressed addresses. */ #if 0 /* Mode 1 - 64 bits inline */ uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 1); #elif 1 /* Mode 2 - 16 bits inline */ uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0x00ff, 0xfe00, 1); #else /* Mode 3 - derived from link local (MAC) address */ uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); #endif uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL); root_if = uip_ds6_addr_lookup(&ipaddr); if(root_if != NULL) { rpl_dag_t *dag; dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr); uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); rpl_set_prefix(dag, &ipaddr, 64); PRINTF("created a new RPL dag\n"); } else { PRINTF("failed to create a new RPL DAG\n"); } #endif /* UIP_CONF_ROUTER */ print_local_addresses(); /* The data sink runs with a 100% duty cycle in order to ensure high packet reception rates. */ NETSTACK_MAC.off(1); server_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL); if(server_conn == NULL) { PRINTF("No UDP connection available, exiting the process!\n"); PROCESS_EXIT(); } udp_bind(server_conn, UIP_HTONS(UDP_SERVER_PORT)); PRINTF("Created a server connection with remote address "); PRINT6ADDR(&server_conn->ripaddr); PRINTF(" local/remote port %u/%u\n", UIP_HTONS(server_conn->lport), UIP_HTONS(server_conn->rport)); while(1) { PROCESS_YIELD(); if(ev == tcpip_event) { tcpip_handler(); } else if (ev == sensors_event && data == &button_sensor) { PRINTF("Initiaing global repair\n"); rpl_repair_root(RPL_DEFAULT_INSTANCE); } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ void uip_ds6_route_rm(uip_ds6_route_t *route) { struct uip_ds6_route_neighbor_route *neighbor_route; #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ if(route != NULL && route->neighbor_routes != NULL) { PRINTF("uip_ds6_route_rm: removing route: "); PRINT6ADDR(&route->ipaddr); PRINTF("\n"); /* Remove the route from the route list */ list_remove(routelist, route); /* Find the corresponding neighbor_route and remove it. */ for(neighbor_route = list_head(route->neighbor_routes->route_list); neighbor_route != NULL && neighbor_route->route != route; neighbor_route = list_item_next(neighbor_route)); if(neighbor_route == NULL) { PRINTF("uip_ds6_route_rm: neighbor_route was NULL for "); PRINT6ADDR(&route->ipaddr); } list_remove(route->neighbor_routes->route_list, neighbor_route); if(list_head(route->neighbor_routes->route_list) == NULL) { /* If this was the only route using this neighbor, remove the neighbor from the table - this implicitly unlocks nexthop */ PRINTF("uip_ds6_route_rm: removing neighbor too\n"); nbr_table_remove(nbr_routes, route->neighbor_routes->route_list); } memb_free(&routememb, route); memb_free(&neighborroutememb, neighbor_route); num_routes--; PRINTF("uip_ds6_route_rm num %d\n", num_routes); #if UIP_DS6_NOTIFICATIONS call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM, &route->ipaddr, uip_ds6_route_nexthop(route)); #endif #if 0 //(DEBUG & DEBUG_ANNOTATE) == DEBUG_ANNOTATE /* we need to check if this was the last route towards "nexthop" */ /* if so - remove that link (annotation) */ uip_ds6_route_t *r; for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) { uip_ipaddr_t *nextr, *nextroute; nextr = uip_ds6_route_nexthop(r); nextroute = uip_ds6_route_nexthop(route); if(nextr != NULL && nextroute != NULL && uip_ipaddr_cmp(nextr, nextroute)) { /* we found another link using the specific nexthop, so keep the #L */ return; } } ANNOTATE("#L %u 0\n", uip_ds6_route_nexthop(route)->u8[sizeof(uip_ipaddr_t) - 1]); #endif } #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ return; }
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 */ uip_lladdr_t lladdr_aligned; extract_lladdr_from_llao_aligned(&lladdr_aligned); nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); if(nbr == NULL) { uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); } else { const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); if(lladdr == NULL) { goto discard; } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { /* failed to update the lladdr */ goto discard; } 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_io_ns_input(void) { 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); u8_t flags; #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)) { goto badpkt; } #endif /* UIP_CONF_IPV6_CHECKS */ /* Options reading: we handle only SLLAO for now */ 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) { goto badpkt; } #endif /* UIP_CONF_IPV6_CHECKS */ switch(UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_SLLAO: nd6_opt_llao = (struct uip_nd6_opt_llao *)UIP_ND6_OPT_HDR_BUF; break; default: UIP_LOG("ND option not supported in NS"); 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 /* There must be NO option in a DAD NS */ if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { goto badpkt; } else { #endif /*UIP_CONF_IPV6_CHECKS*/ neighbor = uip_nd6_nbrcache_lookup(&UIP_IP_BUF->srcipaddr); if(neighbor == NULL) { /* we need to add the neighbor*/ uip_nd6_nbrcache_add(&UIP_IP_BUF->srcipaddr, &nd6_opt_llao->addr, 0, STALE); } else { /* If LL address changed, set neighbor state to stale */ if(memcmp(&nd6_opt_llao->addr, &neighbor->lladdr, UIP_LLADDR_LEN) != 0) { memcpy(&neighbor->lladdr, &nd6_opt_llao->addr, UIP_LLADDR_LEN); neighbor->state = STALE; } else { /* If neighbor state is INCOMPLETE, set to STALE */ if(neighbor->state == INCOMPLETE) { neighbor->state = STALE; } } } #if UIP_CONF_IPV6_CHECKS } #endif /*UIP_CONF_IPV6_CHECKS*/ } /* * Rest of NS processing: Depends on the purpose of the NS: NUD or DAD or * Address Resolution */ /** \note we use ifaddr to remember the target address */ ifaddr = uip_netif_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr, 128, 0); if(ifaddr != NULL) { if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)){ /* DAD CASE */ #if UIP_CONF_IPV6_CHECKS /* Dst address must be solicited node mcast address */ if(!uip_netif_is_addr_my_solicited(&UIP_IP_BUF->destipaddr)){ goto badpkt; } #endif /* UIP_CONF_IPV6_CHECKS */ /* * If my address is not tentative, then send a NA to all nodes with * TLLAO flags are: override = yes. */ if(ifaddr->state!=TENTATIVE) { /* * we need to send a NA, we set the src, dest, flags. tgt remains the * same and the rest is done at "create_na" */ uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr); uip_netif_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_netif_dad_failed(&UIP_ND6_NS_BUF->tgtipaddr); goto discard; } } #if UIP_CONF_IPV6_CHECKS /* Duplicate check */ if(uip_netif_is_addr_my_unicast(&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! */ goto badpkt; } #endif /*UIP_CONF_IPV6_CHECKS*/ /* Address resolution case */ if(uip_netif_is_addr_my_solicited(&UIP_IP_BUF->destipaddr)){ /* * we need to send a NA, we set the src, dest, flags. The rest is * set at the "create_na" label. */ 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. at this point the packet must be for us! we check this, * and at the same time if target == dest */ if(uip_netif_addr_lookup(&UIP_IP_BUF->destipaddr, 128, 0) == ifaddr){ /* * we need to send a NA, we set the src, dest, flags. The rest is set * at the "create_na" label. */ 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 goto badpkt; #endif /* UIP_CONF_IPV6_CHECKS */ } } else { goto discard; } create_na: /* * Fill the part of the NA which is common to all NAs. If the NS contained * extension headers, we must set the target address properly */ uip_ext_len = 0; /* IP header */ 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; /* ICMP header */ UIP_ICMP_BUF->type = ICMP6_NA; UIP_ICMP_BUF->icode = 0; /* NA static part */ UIP_ND6_NA_BUF->flagsreserved = flags; memcpy(&UIP_ND6_NA_BUF->tgtipaddr, &ifaddr->ipaddr, sizeof(uip_ipaddr_t)); /* NA option: TLLAO. note that length field is in unit of 8 bytes */ uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; nd6_opt_llao = (struct uip_nd6_opt_llao *)&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN]; nd6_opt_llao->type = UIP_ND6_OPT_TLLAO; nd6_opt_llao->len = UIP_ND6_OPT_LLAO_LEN >> 3; memcpy(&(nd6_opt_llao->addr), &uip_lladdr, UIP_LLADDR_LEN); /* padding if needed */ memset((void *)(&nd6_opt_llao->addr) + UIP_LLADDR_LEN, 0, UIP_ND6_OPT_LLAO_LEN - 2 - UIP_LLADDR_LEN); /*ICMP checksum*/ UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); 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; #if UIP_CONF_IPV6_CHECKS badpkt: UIP_STAT(++uip_stat.nd6.drop); UIP_LOG("NS received is bad"); #endif /* UIP_CONF_IPV6_CHECKS */ discard: uip_len = 0; return; }
/*---------------------------------------------------------------------------*/ static void 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 */ uip_lladdr_t lladdr_aligned; extract_lladdr_from_llao_aligned(&lladdr_aligned); if((nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr)) == NULL) { /* we need to add the neighbor */ uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); } else { /* If LL address changed, set neighbor state to stale */ const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); if(lladdr == NULL) { goto discard; } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { uip_ds6_nbr_t nbr_data; nbr_data = *nbr; uip_ds6_nbr_rm(nbr); nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); 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_clear_buf(); return; }
/*---------------------------------------------------------------------------*/ void uip_ds6_neighbor_periodic(struct net_buf *buf) { /* Periodic processing on neighbors */ uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors); while(nbr != NULL) { switch(nbr->state) { case NBR_REACHABLE: if(stimer_expired(&nbr->reachable)) { #if UIP_CONF_IPV6_RPL /* when a neighbor leave it's REACHABLE state and is a default router, instead of going to STALE state it enters DELAY state in order to force a NUD on it. Otherwise, if there is no upward traffic, the node never knows if the default router is still reachable. This mimics the 6LoWPAN-ND behavior. */ if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) { PRINTF("REACHABLE: defrt moving to DELAY ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; } else { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_STALE; } #else /* UIP_CONF_IPV6_RPL */ PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_STALE; #endif /* UIP_CONF_IPV6_RPL */ } break; #if UIP_ND6_SEND_NA case NBR_INCOMPLETE: if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len(buf) == 0)) { nbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount); uip_nd6_ns_output(buf, NULL, NULL, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; case NBR_DELAY: if(stimer_expired(&nbr->reachable)) { nbr->state = NBR_PROBE; nbr->nscount = 0; PRINTF("DELAY: moving to PROBE\n"); stimer_set(&nbr->sendns, 0); } break; case NBR_PROBE: if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { uip_ds6_defrt_t *locdefrt; PRINTF("PROBE END\n"); if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) { if (!locdefrt->isinfinite) { uip_ds6_defrt_rm(locdefrt); } } uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len(buf) == 0)) { nbr->nscount++; PRINTF("PROBE: NS %u\n", nbr->nscount); uip_nd6_ns_output(buf, NULL, &nbr->ipaddr, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; #endif /* UIP_ND6_SEND_NA */ default: break; } nbr = nbr_table_next(ds6_neighbors, nbr); } }
/** * 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) { uip_lladdr_t lladdr_aligned; 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_linklocal(&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(!extract_lladdr_from_llao_aligned(&lladdr_aligned)) { /* failed to extract llao - discard packet */ goto discard; } if(nbr == NULL) { nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 1, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); } else { const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); if(lladdr == NULL) { goto discard; } if(nbr->state == NBR_INCOMPLETE) { nbr->state = NBR_STALE; } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { /* change of link layer address */ if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { /* failed to update the lladdr */ goto discard; } 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_linklocal(&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; #if UIP_ND6_RA_RDNSS case UIP_ND6_OPT_RDNSS: if(UIP_ND6_RA_BUF->flags_reserved & (UIP_ND6_O_FLAG << 6)) { PRINTF("Processing RDNSS option\n"); uint8_t naddr = (UIP_ND6_OPT_RDNSS_BUF->len - 1) / 2; uip_ipaddr_t *ip = (uip_ipaddr_t *)(&UIP_ND6_OPT_RDNSS_BUF->ip); PRINTF("got %d nameservers\n", naddr); while(naddr-- > 0) { PRINTF(" nameserver: "); PRINT6ADDR(ip); PRINTF(" lifetime: %lx\n", uip_ntohl(UIP_ND6_OPT_RDNSS_BUF->lifetime)); uip_nameserver_update(ip, uip_ntohl(UIP_ND6_OPT_RDNSS_BUF->lifetime)); ip++; } } break; #endif /* UIP_ND6_RA_RDNSS */ 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_clear_buf(); return; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) { static struct etimer periodic; static struct ctimer backoff_timer; #if WITH_COMPOWER static int print = 0; #endif PROCESS_BEGIN(); PROCESS_PAUSE(); set_global_address(); PRINTF("UDP client process started\n"); print_local_addresses(); /* new connection with remote host */ client_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL); if(client_conn == NULL) { PRINTF("No UDP connection available, exiting the process!\n"); PROCESS_EXIT(); } udp_bind(client_conn, UIP_HTONS(UDP_CLIENT_PORT)); PRINTF("Created a connection with the server "); PRINT6ADDR(&client_conn->ripaddr); PRINTF(" local/remote port %u/%u ", UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); PRINTF(" to the endpoint "); PRINT6ADDR(&server_ipaddr); PRINTF("\n"); #if WITH_COMPOWER powertrace_sniff(POWERTRACE_ON); #endif etimer_set(&periodic, SEND_INTERVAL); while(1) { PROCESS_YIELD(); if(ev == tcpip_event) { tcpip_handler(); } if(etimer_expired(&periodic)) { etimer_reset(&periodic); ctimer_set(&backoff_timer, SEND_TIME, send_packet, NULL); #if WITH_COMPOWER if (print == 0) { powertrace_print("#P"); } if (++print == 3) { print = 0; } #endif } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ static uint8_t ping6handler(process_event_t ev, process_data_t data) { if(count == 0){ #if MACDEBUG // Setup destination address. addr[0] = 0xFE80; addr[4] = 0x6466; addr[5] = 0x6666; addr[6] = 0x6666; addr[7] = 0x6666; uip_ip6addr(&dest_addr, addr[0], addr[1],addr[2], addr[3],addr[4],addr[5],addr[6],addr[7]); // Set the command to fool the 'if' below. memcpy(command, (void *)"ping6", 5); #else /* prompt */ printf("> "); /** \note the scanf here is blocking (the all stack is blocked waiting * for user input). This is far from ideal and could be improved */ scanf("%s", command); if(strcmp(command,"ping6") != 0){ PRINTF("> invalid command\n"); return 0; } if(scanf(" %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", &addr[0],&addr[1],&addr[2],&addr[3], &addr[4],&addr[5],&addr[6],&addr[7]) == 8){ uip_ip6addr(&dest_addr, addr[0], addr[1],addr[2], addr[3],addr[4],addr[5],addr[6],addr[7]); } else { PRINTF("> invalid ipv6 address format\n"); return 0; } #endif } if((strcmp(command,"ping6") == 0) && (count < PING6_NB)){ UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 1; UIP_IP_BUF->flow = 0; UIP_IP_BUF->proto = UIP_PROTO_ICMP6; UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit; uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &dest_addr); uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); UIP_ICMP_BUF->type = ICMP6_ECHO_REQUEST; UIP_ICMP_BUF->icode = 0; /* set identifier and sequence number to 0 */ memset((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, 0, 4); /* put one byte of data */ memset((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN + UIP_ICMP6_ECHO_REQUEST_LEN, count, PING6_DATALEN); uip_len = UIP_ICMPH_LEN + UIP_ICMP6_ECHO_REQUEST_LEN + UIP_IPH_LEN + PING6_DATALEN; UIP_IP_BUF->len[0] = (uint8_t)((uip_len - 40) >> 8); UIP_IP_BUF->len[1] = (uint8_t)((uip_len - 40) & 0x00FF); UIP_ICMP_BUF->icmpchksum = 0; UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); PRINTF("Sending Echo Request to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("\n"); UIP_STAT(++uip_stat.icmp.sent); tcpip_ipv6_output(); count++; etimer_set(&ping6_periodic_timer, 3 * CLOCK_SECOND); return 1; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) { static struct etimer periodic; static struct ctimer backoff_timer; static struct etimer wait; static int tx[] = { 31, 27, 23, 19, 15, 11, 7, 3}; static int i ; #if WITH_COMPOWER static int print = 0; #endif PROCESS_BEGIN(); powertrace_start(CLOCK_SECOND * 2); //elnaz PROCESS_PAUSE(); set_global_address(); PRINTF("UDP client process started\n"); print_local_addresses(); /* new connection with remote host */ client_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL); if(client_conn == NULL) { PRINTF("No UDP connection available, exiting the process!\n"); PROCESS_EXIT(); } udp_bind(client_conn, UIP_HTONS(UDP_CLIENT_PORT)); PRINTF("Created a connection with the server "); PRINT6ADDR(&client_conn->ripaddr); PRINTF(" local/remote port %u/%u\n", UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport)); #if WITH_COMPOWER powertrace_sniff(POWERTRACE_ON); #endif etimer_set(&periodic, SEND_INTERVAL); for(i = 0 ; i<8 ; i++) { cc2420_set_txpower(tx[i]); printf(" Tx=%d\n", cc2420_get_txpower()); while(seq<100) { PROCESS_YIELD(); if(ev == tcpip_event) { tcpip_handler(); } if(etimer_expired(&periodic)) { etimer_reset(&periodic); ctimer_set(&backoff_timer, SEND_TIME, send_packet, NULL); } //end etimer_expired } seq = 0; etimer_stop(&periodic); etimer_set(&wait, WAIT_INTERVAL); PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER); etimer_set(&periodic, SEND_INTERVAL); } // end loop on Tx PROCESS_END(); }