void tcpip_ipv6_output(void) { uip_ds6_nbr_t *nbr = NULL; uip_ipaddr_t *nexthop; if(uip_len == 0) { return; } if(uip_len > UIP_LINK_MTU) { UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_len = 0; return; } if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){ UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_len = 0; return; } if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { /* Next hop determination */ nbr = NULL; /* We first check if the destination address is on our immediate link. If so, we simply use the destination address as our nexthop address. */ if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){ nexthop = &UIP_IP_BUF->destipaddr; } else { uip_ds6_route_t *route; /* Check if we have a route to the destination address. */ route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); /* No route was found - we send to the default route instead. */ if(route == NULL) { PRINTF("tcpip_ipv6_output: no route found, using default route\n"); nexthop = uip_ds6_defrt_choose(); if(nexthop == NULL) { #ifdef UIP_FALLBACK_INTERFACE PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40)); if(uip_ext_len > 0) { extern void remove_ext_hdr(void); uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40); remove_ext_hdr(); /* This should be copied from the ext header... */ UIP_IP_BUF->proto = proto; } UIP_FALLBACK_INTERFACE.output(); #else PRINTF("tcpip_ipv6_output: Destination off-link but no route\n"); #endif /* !UIP_FALLBACK_INTERFACE */ uip_len = 0; return; } } else { /* A route was found, so we look up the nexthop neighbor for the route. */ nexthop = uip_ds6_route_nexthop(route); /* If the nexthop is dead, for example because the neighbor never responded to link-layer acks, we drop its route. */ if(nexthop == NULL) { #if UIP_CONF_IPV6_RPL /* If we are running RPL, and if we are the root of the network, we'll trigger a global repair berfore we remove the route. */ rpl_dag_t *dag; rpl_instance_t *instance; dag = (rpl_dag_t *)route->state.dag; if(dag != NULL) { instance = dag->instance; rpl_repair_root(instance->instance_id); } #endif /* UIP_CONF_RPL */ uip_ds6_route_rm(route); /* We don't have a nexthop to send the packet to, so we drop it. */ return; } } #if TCPIP_CONF_ANNOTATE_TRANSMISSIONS if(nexthop != NULL) { static uint8_t annotate_last; static uint8_t annotate_has_last = 0; if(annotate_has_last) { printf("#L %u 0; red\n", annotate_last); } printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); annotate_last = nexthop->u8[sizeof(uip_ipaddr_t) - 1]; annotate_has_last = 1; } #endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */ } /* End of next hop determination */ #if UIP_CONF_IPV6_RPL if(rpl_update_header_final(nexthop)) { uip_len = 0; return; } #endif /* UIP_CONF_IPV6_RPL */ nbr = uip_ds6_nbr_lookup(nexthop); if(nbr == NULL) { #if UIP_ND6_SEND_NA if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) { uip_len = 0; return; } else { #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /* RFC4861, 7.2.2: * "If the source address of the packet prompting the solicitation is the * same as one of the addresses assigned to the outgoing interface, that * address SHOULD be placed in the IP Source Address of the outgoing * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used."*/ if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)){ uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr); } else { uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); } stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); nbr->nscount = 1; } #endif /* UIP_ND6_SEND_NA */ } else { #if UIP_ND6_SEND_NA if(nbr->state == NBR_INCOMPLETE) { PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit and set the destination nbr to nbr. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } /* Send in parallel if we are running NUD (nbc state is either STALE, DELAY, or PROBE). See RFC 4861, section 7.3.3 on node behavior. */ if(nbr->state == NBR_STALE) { nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n"); } #endif /* UIP_ND6_SEND_NA */ tcpip_output(uip_ds6_nbr_get_ll(nbr)); #if UIP_CONF_IPV6_QUEUE_PKT /* * Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves * to STALE, and you must both send a NA and the queued packet. */ if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); tcpip_output(uip_ds6_nbr_get_ll(nbr)); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } return; } /* Multicast IP destination address. */ tcpip_output(NULL); uip_len = 0; uip_ext_len = 0; }
/* * Process a Router Advertisement * * - Possible actions when receiving a RA: add router to router list, * recalculate reachable time, update link hop limit, update retrans timer. * - If MTU option: update MTU. * - If SLLAO option: update entry in neighbor cache * - If prefix option: start autoconf, add prefix to prefix list */ void ra_input(void) { PRINTF("Received RA from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); #if UIP_CONF_IPV6_CHECKS if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (!uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) || (UIP_ICMP_BUF->icode != 0)) { PRINTF("RA received is bad"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ if(UIP_ND6_RA_BUF->cur_ttl != 0) { uip_ds6_if.cur_hop_limit = UIP_ND6_RA_BUF->cur_ttl; PRINTF("uip_ds6_if.cur_hop_limit %u\n", uip_ds6_if.cur_hop_limit); } if(UIP_ND6_RA_BUF->reachable_time != 0) { if(uip_ds6_if.base_reachable_time != uip_ntohl(UIP_ND6_RA_BUF->reachable_time)) { uip_ds6_if.base_reachable_time = uip_ntohl(UIP_ND6_RA_BUF->reachable_time); uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time(); } } if(UIP_ND6_RA_BUF->retrans_timer != 0) { uip_ds6_if.retrans_timer = uip_ntohl(UIP_ND6_RA_BUF->retrans_timer); } /* Options processing */ nd6_opt_offset = UIP_ND6_RA_LEN; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("RA received is bad"); goto discard; } switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_SLLAO: PRINTF("Processing SLLAO option in RA\n"); nd6_opt_llao = (uint8_t *) UIP_ND6_OPT_HDR_BUF; nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); if(nbr == NULL) { nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 1, NBR_STALE); } else { uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); if(nbr->state == NBR_INCOMPLETE) { nbr->state = NBR_STALE; } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); nbr->state = NBR_STALE; } nbr->isrouter = 1; } break; case UIP_ND6_OPT_MTU: PRINTF("Processing MTU option in RA\n"); uip_ds6_if.link_mtu = uip_ntohl(((uip_nd6_opt_mtu *) UIP_ND6_OPT_HDR_BUF)->mtu); break; case UIP_ND6_OPT_PREFIX_INFO: PRINTF("Processing PREFIX option in RA\n"); nd6_opt_prefix_info = (uip_nd6_opt_prefix_info *) UIP_ND6_OPT_HDR_BUF; if((uip_ntohl(nd6_opt_prefix_info->validlt) >= uip_ntohl(nd6_opt_prefix_info->preferredlt)) && (!uip_is_addr_link_local(&nd6_opt_prefix_info->prefix))) { /* on-link flag related processing */ if(nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_ONLINK) { prefix = uip_ds6_prefix_lookup(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen); if(prefix == NULL) { if(nd6_opt_prefix_info->validlt != 0) { if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen, uip_ntohl(nd6_opt_prefix_info-> validlt)); } else { prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen, 0); } } } else { switch (nd6_opt_prefix_info->validlt) { case 0: uip_ds6_prefix_rm(prefix); break; case UIP_ND6_INFINITE_LIFETIME: prefix->isinfinite = 1; break; default: PRINTF("Updating timer of prefix"); PRINT6ADDR(&prefix->ipaddr); PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); stimer_set(&prefix->vlifetime, uip_ntohl(nd6_opt_prefix_info->validlt)); prefix->isinfinite = 0; break; } } } /* End of on-link flag related processing */ /* autonomous flag related processing */ if((nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_AUTONOMOUS) && (nd6_opt_prefix_info->validlt != 0) && (nd6_opt_prefix_info->preflen == UIP_DEFAULT_PREFIX_LEN)) { uip_ipaddr_copy(&ipaddr, &nd6_opt_prefix_info->prefix); uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); addr = uip_ds6_addr_lookup(&ipaddr); if((addr != NULL) && (addr->type == ADDR_AUTOCONF)) { if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { /* The processing below is defined in RFC4862 section 5.5.3 e */ if((uip_ntohl(nd6_opt_prefix_info->validlt) > 2 * 60 * 60) || (uip_ntohl(nd6_opt_prefix_info->validlt) > stimer_remaining(&addr->vlifetime))) { PRINTF("Updating timer of address"); PRINT6ADDR(&addr->ipaddr); PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); stimer_set(&addr->vlifetime, uip_ntohl(nd6_opt_prefix_info->validlt)); } else { stimer_set(&addr->vlifetime, 2 * 60 * 60); PRINTF("Updating timer of address "); PRINT6ADDR(&addr->ipaddr); PRINTF("new value %lu\n", (unsigned long)(2 * 60 * 60)); } addr->isinfinite = 0; } else { addr->isinfinite = 1; } } else { if(uip_ntohl(nd6_opt_prefix_info->validlt) == UIP_ND6_INFINITE_LIFETIME) { uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); } else { uip_ds6_addr_add(&ipaddr, uip_ntohl(nd6_opt_prefix_info->validlt), ADDR_AUTOCONF); } } } /* End of autonomous flag related processing */ } break; default: PRINTF("ND option not supported in RA"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); if(UIP_ND6_RA_BUF->router_lifetime != 0) { if(nbr != NULL) { nbr->isrouter = 1; } if(defrt == NULL) { uip_ds6_defrt_add(&UIP_IP_BUF->srcipaddr, (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); } else { stimer_set(&(defrt->lifetime), (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); } } else { if(defrt != NULL) { uip_ds6_defrt_rm(defrt); } } #if UIP_CONF_IPV6_QUEUE_PKT /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state * and we got a SLLAO), check if we had buffered a pkt for it */ /* if((nbr != NULL) && (nbr->queue_buf_len != 0)) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; }*/ if(nbr != NULL && uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); return; } #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: uip_len = 0; return; }
/** Periodic processing on neighbors */ void uip_ds6_neighbor_periodic(void) { 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 its 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; case NBR_INCOMPLETE: if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) { nbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount); uip_nd6_ns_output(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 == 0)) { nbr->nscount++; PRINTF("PROBE: NS %u\n", nbr->nscount); uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; default: break; } nbr = nbr_table_next(ds6_neighbors, nbr); } }
void tcpip_ipv6_output(void) { uip_ds6_nbr_t *nbr = NULL; uip_ipaddr_t *nexthop; if(uip_len == 0) { return; } if(uip_len > UIP_LINK_MTU) { UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_len = 0; return; } if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){ UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_len = 0; return; } if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { /* Next hop determination */ nbr = NULL; if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){ nexthop = &UIP_IP_BUF->destipaddr; } else { uip_ds6_route_t* locrt; locrt = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); if(locrt == NULL) { if((nexthop = uip_ds6_defrt_choose()) == NULL) { #ifdef UIP_FALLBACK_INTERFACE PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40)); if(uip_ext_len > 0) { extern void remove_ext_hdr(void); uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40); remove_ext_hdr(); /* This should be copied from the ext header... */ UIP_IP_BUF->proto = proto; } UIP_FALLBACK_INTERFACE.output(); #else PRINTF("tcpip_ipv6_output: Destination off-link but no route\n"); #endif /* !UIP_FALLBACK_INTERFACE */ uip_len = 0; return; } } else { nexthop = &locrt->nexthop; } } /* End of next hop determination */ #if UIP_CONF_IPV6_RPL if(rpl_update_header_final(nexthop)) { uip_len = 0; return; } #endif /* UIP_CONF_IPV6_RPL */ if((nbr = uip_ds6_nbr_lookup(nexthop)) == NULL) { if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) { uip_len = 0; return; } else { #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /* RFC4861, 7.2.2: * "If the source address of the packet prompting the solicitation is the * same as one of the addresses assigned to the outgoing interface, that * address SHOULD be placed in the IP Source Address of the outgoing * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used."*/ if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)){ uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr); } else { uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); } stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); nbr->nscount = 1; } } else { if(nbr->state == NBR_INCOMPLETE) { PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT /* Copy outgoing pkt in the queuing buffer for later transmit and set the destination nbr to nbr. */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } /* Send in parallel if we are running NUD (nbc state is either STALE, DELAY, or PROBE). See RFC 4861, section 7.7.3 on node behavior. */ if(nbr->state == NBR_STALE) { nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n"); } tcpip_output(&nbr->lladdr); #if UIP_CONF_IPV6_QUEUE_PKT /* * Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves * to STALE, and you must both send a NA and the queued packet. */ if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); tcpip_output(&nbr->lladdr); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } } /* Multicast IP destination address. */ tcpip_output(NULL); uip_len = 0; uip_ext_len = 0; }
/** * 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 event_handler( event_type_t event_type, unidata_t unidata ) { char str[32]; unsigned char ch; static int err; switch(event_type) { case KBRD_EVT: // ltoa((int32_t)unidata, str, 10); // OLED_puts(0, 41, 0xff, font6x9, str); if(kbrd_pressed) { kbrd_pressed = 0; //display_node(kbrd_getch()); ch = kbrd_getch(); /* itoa((int16_t)ch, str, 16); OLED_clr(0, 41, 3 * 6, 9); OLED_puts(0, 41, 0xff, font6x9, str); */ if(!(ch & 0x80)) { ch = active.menu->action(ch); active.menu->display(ch); update_statusbar(); } /* switch((ch = kbrd_getch())) { case 1: case 129: display(0, 0); break; case 16: case 144: display(1, 0); break; case 14: if((scroll_pos < (MSG_TABLE_SIZE - MSG_VIEW_SIZE)) && (scroll_pos < msg_count - 1)) { scroll_pos ++; event_emit(LOW_PRIORITY, DISPLAY_EVT, 2); } case 142: break; case 13: if(scroll_pos) { scroll_pos--; event_emit(LOW_PRIORITY, DISPLAY_EVT, 2); } case 141: break; case 11: OLED_cls(); err = initConfig(); //sprintf(str, "initConfig res: %d", err); //OLED_puts(0, 0, 0xff, font6x9, str); OLED_puts(0, 0, 0xff, font6x9, (err ? "initConfig failed" : "initConfig success")); break; case 134: { struct LogEntry entry; err = STRG_SUCCESS; entry.timestamp = 0; err += logAddEntry(&entry, "Msg 0"); entry.timestamp = 1000; err += logAddEntry(&entry, "Msg 1"); entry.timestamp = 2000; err += logAddEntry(&entry, "Msg 2"); sprintf(str, "Error code: %d", err); OLED_puts(0, 2*9, 0xff, font6x9, str); } break; default: display(2, ch); break; // display(0, 0); } */ /* OLED_puts(64 + 12, 41, 0xff, font6x9, "Key pressed "); itoa(kbrd_getch(), str, 10); OLED_puts(64 + 12 + sizeof("Key pressed ") * 6, 41, 0xff, font6x9, str); OLED_puts(64 + 12 + sizeof("Key pressed ") * 6 + strlen(str) * 6, 41, 0xff, font6x9, " "); */ } /* else OLED_puts(0, 41, 0xff, font6x9, "Key not pressed"); */ break; case INIT_EVT: //OLED_init(); //init_kbrd(); SPI_init(); event_emit(LOW_PRIORITY, INIT_MMC_EVT, 0); break; case INIT_MMC_EVT: initMMC(); err = initStorage(); event_emit(LOW_PRIORITY, INIT_OLED_EVT, 0); break; case INIT_OLED_EVT: OLED_init(); OLED_puts(0, 0 , 0xff, font6x9, "System initialization..."); OLED_puts(0, 1 * 9 , 0xff, font6x9, "SPI init'ed."); OLED_puts(0, 2 * 9 , 0xff, font6x9, "MMC init'ed."); OLED_puts(0, 3 * 9 , 0xff, font6x9, "OLED init'ed."); event_emit(LOW_PRIORITY, INIT_STORAGE_EVT, 0); break; case INIT_STORAGE_EVT: //err = initStorage(); //OLED_puts(0, 4 * 9 , 0xff, font6x9, err ? "Storage init failed!" : "Storage init'ed."); format_str(str, 32, "Storage err: %d", err); OLED_puts(0, 4 * 9 , 0xff, font6x9, err ? str : "Storage init'ed."); /* format_str(str, 32, "ZoneCfg pos: %u", syscfg.zone_cfg_addr); OLED_puts(0, 5 * 9 , 0xff, font6x9, str); err = 1; */ event_emit(LOW_PRIORITY, INIT_USER_IO_EVT, 0); break; case INIT_USER_IO_EVT: init_kbrd(); menu_init(err ? MNU_INIT | MNU_DO_NOT_SHOW : MNU_INIT); //set_sys_time((uint64_t)20000); stimer_set(1, 1000); break; } /* else if(event_type == INIT_SEND_MSGS_EVT) { msg_t msg; struct msginfo minfo; uint16_t addr_attr = 0x0000; uint8_t port_attr = PORT; //attr_write(0x02, &addr_attr); //attr_write(0x07, &port_attr); // This must be the code for us to say ZigZag (Node Dispatcher) // that we are interested in listening for messages and events msg = msg_new(0x00, 0x00, 0x01, 3, MFLAG_DEFAULT); if(msg < 0) OLED_puts(0, 0, 0xff, font6x9, "Error: msg_new"); if(msg_info(msg, &minfo) != ENOERR) OLED_puts(0, 9, 0xff, font6x9, "Error: msg_info"); ((unsigned char *)minfo.body_ptr)[0] = 0x02; ((unsigned char *)minfo.body_ptr)[1] = 0x00; ((unsigned char *)minfo.body_ptr)[2] = 0x00; if(msg_send(msg) != ENOERR) OLED_puts(0, 18, 0xff, font6x9, "Error: msg_send (1)"); msg = msg_new(0x00, 0x00, 0x01, 2, MFLAG_DEFAULT); if(msg < 0) OLED_puts(0, 0, 0xff, font6x9, "Error: msg_new"); if(msg_info(msg, &minfo) != ENOERR) OLED_puts(0, 9, 0xff, font6x9, "Error: msg_info"); ((unsigned char *)minfo.body_ptr)[0] = 0x07; ((unsigned char *)minfo.body_ptr)[1] = (uint8_t)PORT; // ((unsigned char *)minfo.body_ptr)[2] = (uint8_t)(PORT >> 8); if(msg_send(msg) != ENOERR) OLED_puts(0, 18, 0xff, font6x9, "Error: msg_send (2)"); } */ /* else { //sprintf(str, "Evt: %u", (uint16_t)event_type); //OLED_puts(0, 0, 0xff, font6x9, str); } */ }
/*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * uip_ds6_nbr_add(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr, u8_t isrouter, u8_t state) { int r; 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); // printf("r %d\n", r); 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; /* 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\n", state); NEIGHBOR_STATE_CHANGED(locnbr); locnbr->last_lookup = clock_time(); // printf("add %p\n", locnbr); 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) && (uip_ds6_is_nbr_garbage_collectible(n))) { /* We do not want to remove any non-garbage-collectible entry */ oldest = n; oldest_time = n->last_lookup; } } } if(oldest != NULL) { // printf("rm3\n"); uip_ds6_nbr_rm(oldest); locdefrt = uip_ds6_defrt_lookup(&oldest->ipaddr); uip_ds6_defrt_rm(locdefrt); uip_ds6_reg_cleanup_defrt(locdefrt); return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state); } } PRINTF("uip_ds6_nbr_add drop\n"); return NULL; }
/*---------------------------------------------------------------------------*/ void uip_ds6_neighbor_periodic(void) { /* 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)) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) { nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; } else { nbr->state = NBR_STALE; } } 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 == 0)) { nbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount); uip_nd6_ns_output(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 == 0)) { nbr->nscount++; PRINTF("PROBE: NS %u\n", nbr->nscount); uip_nd6_ns_output(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); } }
void tcpip_ipv6_output(void) { static uip_ds6_nbr_t *nbr = NULL; static uip_ipaddr_t* nexthop; if(uip_len == 0) { return; } if(uip_len > UIP_LINK_MTU) { UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_len = 0; return; } if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)) { UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_len = 0; return; } if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { /* Next hop determination */ nbr = NULL; if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)) { nexthop = &UIP_IP_BUF->destipaddr; } else { uip_ds6_route_t* locrt; locrt = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); if(locrt == NULL) { if((nexthop = uip_ds6_defrt_choose()) == NULL) { #ifdef UIP_FALLBACK_INTERFACE UIP_FALLBACK_INTERFACE.output(); #else PRINTF("tcpip_ipv6_output: Destination off-link but no route\n"); #endif uip_len = 0; return; } } else { nexthop = &locrt->nexthop; } } /* end of next hop determination */ if((nbr = uip_ds6_nbr_lookup(nexthop)) == NULL) { // printf("add1 %d\n", nexthop->u8[15]); if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) { // printf("add n\n"); uip_len = 0; return; } else { #if UIP_CONF_IPV6_QUEUE_PKT /* copy outgoing pkt in the queuing buffer for later transmmit */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } #endif /* RFC4861, 7.2.2: * "If the source address of the packet prompting the solicitation is the * same as one of the addresses assigned to the outgoing interface, that * address SHOULD be placed in the IP Source Address of the outgoing * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used."*/ if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) { uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr); } else { uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); } stimer_set(&(nbr->sendns), uip_ds6_if.retrans_timer / 1000); nbr->nscount = 1; } } else { if(nbr->state == NBR_INCOMPLETE) { PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT /* copy outgoing pkt in the queuing buffer for later transmmit and set the destination nbr to nbr */ if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) { memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len); uip_packetqueue_set_buflen(&nbr->packethandle, uip_len); } /* memcpy(nbr->queue_buf, UIP_IP_BUF, uip_len); nbr->queue_buf_len = uip_len;*/ uip_len = 0; #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ return; } /* if running NUD (nbc->state == STALE, DELAY, or PROBE ) keep sending in parallel see rfc 4861 Node behavior in section 7.7.3*/ if(nbr->state == NBR_STALE) { nbr->state = NBR_DELAY; stimer_set(&(nbr->reachable), UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n"); } stimer_set(&(nbr->sendns), uip_ds6_if.retrans_timer / 1000); tcpip_output(&(nbr->lladdr)); #if UIP_CONF_IPV6_QUEUE_PKT /* Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves *to STALE, and you must both send a NA and the queued packet */ /* if(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; tcpip_output(&(nbr->lladdr)); }*/ if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); tcpip_output(&(nbr->lladdr)); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } } /*multicast IP destination address */ tcpip_output(NULL); uip_len = 0; uip_ext_len = 0; }
//this will be LinkLayerAbsInit when linked toghter with 6LowPan int main(int argc, char **argv) { int flags; // Used to set non-blocking for stdin int retval; ule6lo_status_t status; // Used as result in many ule6lo lib calls ule6lo_IPEI_t ipei; ule6lo_macAddr_t mac; //Initialize test hooks ule6loTestIn_regRxHook(&test_rx); ule6loTestIn_regTxHook(&test_tx); // Setup stdin to operate non blocking flags = fcntl(0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(0, F_SETFL, flags); //Reset number of received bytes app_bytes_recv = 0; //Print instruction message printf("To send a message use this format and acknowledge with enter:\n<Destination ip> <Destination port> <message>\n"); printf("Use port 3001 for now\n"); // Debug print of contiki setup (defines etc) printContikiConfigurationInfo(); printf("Args: <LBR IP> <LN port> <LN IPEI(mac addr style,example:00:00:00:00:01)> <Mac addr>\n"); if(argc>=5) { status = ule6loGI_init(); printf("ule6loGI_init() returned %i\n", status); // Initialize link layer sscanf(argv[3],"%2hhX:%2hhX:%2hhX:%2hhX:%2hhX",&(ipei.id[0]),&(ipei.id[1]),&(ipei.id[2]),&(ipei.id[3]),&(ipei.id[4])); sscanf(argv[4],"%2hhX:%2hhX:%2hhX:%2hhX:%2hhX:%2hhX",&(mac.u8[0]),&(mac.u8[1]),&(mac.u8[2]),&(mac.u8[3]),&(mac.u8[4]),&(mac.u8[5])); ule6loGI_setMacAddress(&mac); lla_init(argv[1],atoi(argv[2]),&ipei); printf("Using IP %s and port %i and IPEI %s and MAC addr %s\n",argv[1],atoi(argv[2]), argv[3], argv[4]); } else { printf("Incorrect number of arguments"); return 1; } //Wait for connection while(ule6loGI_getStatus() != STATUS_SUCCESS) { sleep(1); } // Print our Link local address and our global address printLinkLocalAddress(); printGloballAddress(); //Create timer to print our IP addresses periodically stimer_set(&ipPrintTimer,10 ); // Print all our IP addresses printIPAddresses(); printIPV6Neighbourlist(); init_udp(); ule6lo_ip6addr_t loc_fipaddr2; memset(&loc_fipaddr2, 0x00, sizeof(loc_fipaddr2)); loc_fipaddr2.u8[0] = 0xff; loc_fipaddr2.u8[1] = 0x02; loc_fipaddr2.u8[10] = 0x00; loc_fipaddr2.u8[11] = 0x00; loc_fipaddr2.u8[12] = 0x00; loc_fipaddr2.u8[13] = 0x01; loc_fipaddr2.u8[15] = 0x05; ule6loGI_addMulticastAddr(&loc_fipaddr2); // Run forever while(1){ // Check the stdin for data readCommandLine(app_res, app_buffer, app_bytes_recv); // Let link layer receive data is any is present llaProcess(); debugPrint(); // Allow the stack to run ule6loOS_processRun(); } return 0; }
static void handle_dhcp(process_event_t message) { time_t seconds; switch( dhcpc_state.state ) { case DHCP_STATE_INITIAL: dhcpc_state.state = DHCP_STATE_DISCOVER; xid++; send_discover(); stimer_set(&dhcpc_state.stimer, (time_t)10 ); // normally set the timer for 60 seconds, // but because the ARP table is empty give DHCP server only 10 seconds. break; case DHCP_STATE_DISCOVER: if( !stimer_expired(&dhcpc_state.stimer) && message == DHCP_OFFER ) { parse_msg(); dhcpc_state.state = DHCP_STATE_REQUEST; xid++; send_request(); stimer_set(&dhcpc_state.stimer, (time_t)10 ); // set the timer for 10 seconds } else { dhcpc_state.state = DHCP_STATE_INITIAL; } break; case DHCP_STATE_REQUEST: if( !stimer_expired(&dhcpc_state.stimer) && message == DHCP_ACK ) { parse_msg(); dhcpc_state.state = DHCP_STATE_LEASED; PRINTF("Got IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.ipaddr)); PRINTF("Got netmask %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.netmask)); PRINTF("Got DNS server %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.dnsaddr)); PRINTF("Got default router %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.default_router)); PRINTF("Lease expires in %ld seconds\n", uip_ntohs(dhcpc_state.lease_time[0])*65536ul + uip_ntohs(dhcpc_state.lease_time[1])); dhcpc_configured(&dhcpc_state); #define MAX_TICKS (~((time_t)0) / 2) #define MAX_TICKS32 (~((time_t)0)) if((uip_ntohs(dhcpc_state.lease_time[0])*65536ul + uip_ntohs(dhcpc_state.lease_time[1]))/2 <= MAX_TICKS32) { seconds = ( uip_ntohs(dhcpc_state.lease_time[0])*65536ul + uip_ntohs(dhcpc_state.lease_time[1]) )/2; } else { seconds = MAX_TICKS32; } stimer_set(&dhcpc_state.stimer, seconds); // set the timer for half of lease_time seconds } else { dhcpc_state.state = DHCP_STATE_INITIAL; } break; case DHCP_STATE_LEASED: if( stimer_expired(&dhcpc_state.stimer) ) { dhcpc_state.state = DHCP_STATE_INITIAL; } break; case DHCP_STATE_REREQUEST: case DHCP_STATE_RELEASE: default: dhcpc_state.state = DHCP_STATE_INITIAL; break; } }
/*---------------------------------------------------------------------------*/ void uip_ds6_periodic(void) { #if CONF_6LOWPAN_ND_OPTI_START && UIP_CONF_6L_ROUTER /* Start RPL only when the device has global IPv6 */ if(!rpl_started && uip_ds6_get_global(ADDR_PREFERRED)) { rpl_init(); rpl_started = 1; } #endif /* CONF_6LOWPAN_ND_OPTI_START && UIP_CONF_6L_ROUTER */ /* 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); #if UIP_ND6_DEF_MAXDADNS > 0 } else if((locaddr->state == ADDR_TENTATIVE) && (locaddr->dadnscount <= uip_ds6_if.maxdadns) && (timer_expired(&locaddr->dadtimer)) && (uip_len == 0)) { uip_ds6_dad(locaddr); #endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } } } /* Periodic processing on default routers */ uip_ds6_defrt_periodic(); /* 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 CONF_6LOWPAN_ND /* Periodic processing on context prefixes */ for(loccontext = uip_ds6_context_pref_list; loccontext < uip_ds6_context_pref_list + UIP_DS6_CONTEXT_PREF_NB; loccontext++) { if(loccontext->state != CONTEXT_PREF_ST_FREE) { #if UIP_CONF_6LBR if(stimer_expired(&loccontext->lifetime) && loccontext->br->state != BR_ST_NEW_VERSION) { switch(loccontext->state) { case CONTEXT_PREF_ST_RM: /* Valid lifetime expired, so remove */ loccontext->state = CONTEXT_PREF_ST_FREE; break; case CONTEXT_PREF_ST_ADD: /* before c=0, now c=1 */ loccontext->state = CONTEXT_PREF_ST_COMPRESS; stimer_set(&loccontext->lifetime, loccontext->vlifetime * 60); break; } } #else /* UIP_CONF_6LBR */ if(stimer_expired(&loccontext->lifetime)) { switch(loccontext->state) { case CONTEXT_PREF_ST_UNCOMPRESSONLY: case CONTEXT_PREF_ST_RM: /* Valid lifetime expired, so remove */ loccontext->state = CONTEXT_PREF_ST_FREE; break; case CONTEXT_PREF_ST_SENDING: /* receive-only mode for a period of twice the default Router Lifetime */ loccontext->state = CONTEXT_PREF_ST_UNCOMPRESSONLY; stimer_set(&loccontext->lifetime, loccontext->router_lifetime * 2); break; case CONTEXT_PREF_ST_ADD: /* before c=0, now c=1 */ loccontext->state = CONTEXT_PREF_ST_COMPRESS; stimer_set(&loccontext->lifetime, loccontext->vlifetime * 60); break; } } else if(is_timeout_percent(&loccontext->lifetime, UIP_DS6_RS_PERCENT_LIFETIME_RETRAN, UIP_DS6_RS_MINLIFETIME_RETRAN) && loccontext->state == CONTEXT_PREF_ST_COMPRESS) { if(loccontext->br->state != BR_ST_SENDING_RS) { loccontext->br->state = BR_ST_MUST_SEND_RS; } loccontext->state = CONTEXT_PREF_ST_SENDING; } #endif /* UIP_CONF_6LBR */ } } #endif /* CONF_6LOWPAN_ND */ #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) { if(stimer_expired(&(locprefix->vlifetime))) { uip_ds6_prefix_rm(locprefix); #if UIP_CONF_6LR || UIP_CONF_6LN } else if(is_timeout_percent(&locprefix->vlifetime, UIP_DS6_RS_PERCENT_LIFETIME_RETRAN, UIP_DS6_RS_MINLIFETIME_RETRAN)) { if(locprefix->br->state != BR_ST_SENDING_RS) { locprefix->br->state = BR_ST_MUST_SEND_RS; } #endif /* UIP_CONF_6LR || UIP_CONF_6LN */ } } } #endif /* !UIP_CONF_ROUTER */ /* Periodic processing on border router */ #if CONF_6LOWPAN_ND uip_ds6_br_periodic(); #endif /* CONF_6LOWPAN_ND */ /* Periodic processing on Duplication Address*/ #if UIP_CONF_6LBR for(locdad = uip_ds6_dup_addr_list; locdad < uip_ds6_dup_addr_list + UIP_DS6_DUPADDR_NB; locdad++) { if(locdad->isused && stimer_expired(&locdad->lifetime)) { uip_ds6_dup_addr_rm(locdad); } } #endif /* UIP_CONF_6LBR */ uip_ds6_neighbor_periodic(); #if UIP_CONF_ROUTER & UIP_ND6_SEND_RA #if !CONF_6LOWPAN_ND || UIP_ND6_RA_PERIODIC /* Periodic RA sending */ if(stimer_expired(&uip_ds6_timer_ra) && (uip_len == 0)) { uip_ds6_send_ra_periodic(); } #endif /* !CONF_6LOWPAN_ND || UIP_ND6_RA_PERIODIC */ #endif /* UIP_CONF_ROUTER & UIP_ND6_SEND_RA */ etimer_reset(&uip_ds6_timer_periodic); return; }
/*---------------------------------------------------------------------------*/ void uip_ds6_init(void) { uip_ds6_neighbors_init(); uip_ds6_route_init(); PRINTF("Init of IPv6 data structures\n"); PRINTF("%u neighbors\n%u default routers\n%u prefixes\n%u routes\n%u unicast addresses\n%u multicast addresses\n%u anycast addresses\n", NBR_TABLE_MAX_NEIGHBORS, UIP_DS6_DEFRT_NB, UIP_DS6_PREFIX_NB, UIP_DS6_ROUTE_NB, UIP_DS6_ADDR_NB, UIP_DS6_MADDR_NB, UIP_DS6_AADDR_NB); memset(uip_ds6_prefix_list, 0, sizeof(uip_ds6_prefix_list)); memset(&uip_ds6_if, 0, sizeof(uip_ds6_if)); #if CONF_6LOWPAN_ND memset(uip_ds6_context_pref_list, 0, sizeof(uip_ds6_context_pref_list)); memset(uip_ds6_br_list, 0, sizeof(uip_ds6_br_list)); #if UIP_CONF_6LBR memset(uip_ds6_dup_addr_list, 0, sizeof(uip_ds6_dup_addr_list)); #endif /* UIP_CONF_6LBR */ #endif /* CONF_6LOWPAN_ND */ uip_ds6_addr_size = sizeof(struct uip_ds6_addr); uip_ds6_netif_addr_list_offset = offsetof(struct uip_ds6_netif, addr_list); /* Set interface parameters */ uip_ds6_if.link_mtu = UIP_LINK_MTU; uip_ds6_if.cur_hop_limit = UIP_TTL; uip_ds6_if.base_reachable_time = UIP_ND6_REACHABLE_TIME; uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time(); uip_ds6_if.retrans_timer = UIP_ND6_RETRANS_TIMER; uip_ds6_if.maxdadns = UIP_ND6_DEF_MAXDADNS; /* Create link local address, prefix, multicast addresses, anycast addresses */ uip_create_linklocal_prefix(&loc_fipaddr); #if UIP_CONF_ROUTER uip_ds6_prefix_add(&loc_fipaddr, UIP_DEFAULT_PREFIX_LEN, 0, 0, 0, 0); #else /* UIP_CONF_ROUTER */ uip_ds6_prefix_add(&loc_fipaddr, UIP_DEFAULT_PREFIX_LEN, 0); #endif /* UIP_CONF_ROUTER */ uip_ds6_set_addr_iid(&loc_fipaddr, &uip_lladdr); uip_ds6_addr_add(&loc_fipaddr, 0, ADDR_AUTOCONF); uip_create_linklocal_allnodes_mcast(&loc_fipaddr); uip_ds6_maddr_add(&loc_fipaddr); #if UIP_CONF_ROUTER uip_create_linklocal_allrouters_mcast(&loc_fipaddr); uip_ds6_maddr_add(&loc_fipaddr); #if UIP_ND6_SEND_RA #if !CONF_6LOWPAN_ND || UIP_ND6_RA_PERIODIC PRINTF("Will Sending periodic RA\n"); stimer_set(&uip_ds6_timer_ra, 2); /* wait to have a link local IP address */ #endif /* #if !CONF_6LOWPAN_ND || UIP_ND6_RA_PERIODIC */ #endif /* UIP_ND6_SEND_RA */ #if UIP_CONF_6LR etimer_set(&uip_ds6_timer_rs, random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY * CLOCK_SECOND)); #endif /* UIP_CONF_6LR */ #else /* UIP_CONF_ROUTER */ etimer_set(&uip_ds6_timer_rs, random_rand() % (UIP_ND6_MAX_RTR_SOLICITATION_DELAY * CLOCK_SECOND)); #endif /* UIP_CONF_ROUTER */ etimer_set(&uip_ds6_timer_periodic, UIP_DS6_PERIOD); #if CONF_6LOWPAN_ND_OPTI_START && UIP_CONF_6L_ROUTER rpl_started = 0; #endif /* CONF_6LOWPAN_ND_OPTI_START && UIP_CONF_6L_ROUTER */ return; }
void tcpip_ipv6_output(void) { struct uip_nd6_neighbor *nbc = NULL; struct uip_nd6_defrouter *dr = NULL; if(uip_len == 0) return; if(uip_len > UIP_LINK_MTU){ UIP_LOG("tcpip_ipv6_output: Packet to big"); uip_len = 0; return; } if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){ UIP_LOG("tcpip_ipv6_output: Destination address unspecified"); uip_len = 0; return; } if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { /*If destination is on link */ nbc = NULL; if(uip_nd6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){ nbc = uip_nd6_nbrcache_lookup(&UIP_IP_BUF->destipaddr); } else { #if UIP_CONF_ROUTER /*destination is not on link*/ uip_ipaddr_t ipaddr; uip_ipaddr_t *next_hop; /* Try to find the next hop address in the local routing table. */ next_hop = uip_router != NULL ? uip_router->lookup(&UIP_IP_BUF->destipaddr, &ipaddr) : NULL; if(next_hop != NULL) { /* Look for the next hop of the route in the neighbor cache. Add a cache entry if we can't find it. */ nbc = uip_nd6_nbrcache_lookup(next_hop); if(nbc == NULL) { nbc = uip_nd6_nbrcache_add(next_hop, NULL, 1, NO_STATE); } } else { #endif /* UIP_CONF_ROUTER */ /* No route found, check if a default router exists and use it then. */ dr = uip_nd6_choose_defrouter(); if(dr != NULL){ nbc = dr->nb; } else { /* shall we send a icmp error message destination unreachable ?*/ UIP_LOG("tcpip_ipv6_output: Destination off-link but no router"); uip_len = 0; return; } #if UIP_CONF_ROUTER } #endif /* UIP_CONF_ROUTER */ } /* there are two cases where the entry logically does not exist: * 1 it really does not exist. 2 it is in the NO_STATE state */ if (nbc == NULL || nbc->state == NO_STATE) { if (nbc == NULL) { /* create neighbor cache entry, original packet is replaced by NS*/ nbc = uip_nd6_nbrcache_add(&UIP_IP_BUF->destipaddr, NULL, 0, INCOMPLETE); } else { nbc->state = INCOMPLETE; } #if UIP_CONF_IPV6_QUEUE_PKT /* copy outgoing pkt in the queuing buffer for later transmmit */ memcpy(nbc->queue_buf, UIP_IP_BUF, uip_len); nbc->queue_buf_len = uip_len; #endif /* RFC4861, 7.2.2: * "If the source address of the packet prompting the solicitation is the * same as one of the addresses assigned to the outgoing interface, that * address SHOULD be placed in the IP Source Address of the outgoing * solicitation. Otherwise, any one of the addresses assigned to the * interface should be used."*/ if(uip_netif_is_addr_my_unicast(&UIP_IP_BUF->srcipaddr)){ uip_nd6_io_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbc->ipaddr); } else { uip_nd6_io_ns_output(NULL, NULL, &nbc->ipaddr); } stimer_set(&(nbc->last_send), uip_netif_physical_if.retrans_timer / 1000); nbc->count_send = 1; } else { if (nbc->state == INCOMPLETE){ PRINTF("tcpip_ipv6_output: neighbor cache entry incomplete\n"); #if UIP_CONF_IPV6_QUEUE_PKT /* copy outgoing pkt in the queuing buffer for later transmmit and set the destination neighbor to nbc */ memcpy(nbc->queue_buf, UIP_IP_BUF, uip_len); nbc->queue_buf_len = uip_len; uip_len = 0; #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ return; } /* if running NUD (nbc->state == STALE, DELAY, or PROBE ) keep sending in parallel see rfc 4861 Node behavior in section 7.7.3*/ if (nbc->state == STALE){ nbc->state = DELAY; stimer_set(&(nbc->reachable), UIP_ND6_DELAY_FIRST_PROBE_TIME); PRINTF("tcpip_ipv6_output: neighbor cache entry stale moving to delay\n"); } stimer_set(&(nbc->last_send), uip_netif_physical_if.retrans_timer / 1000); tcpip_output(&(nbc->lladdr)); #if UIP_CONF_IPV6_QUEUE_PKT /* Send the queued packets from here, may not be 100% perfect though. * This happens in a few cases, for example when instead of receiving a * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves *to STALE, and you must both send a NA and the queued packet */ if(nbc->queue_buf_len != 0) { uip_len = nbc->queue_buf_len; memcpy(UIP_IP_BUF, nbc->queue_buf, uip_len); nbc->queue_buf_len = 0; tcpip_output(&(nbc->lladdr)); } #endif /*UIP_CONF_IPV6_QUEUE_PKT*/ uip_len = 0; return; } } /*multicast IP destination address */ tcpip_output(NULL); uip_len = 0; uip_ext_len = 0; }
/*---------------------------------------------------------------------------*/ 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); #if UIP_ND6_DEF_MAXDADNS > 0 } else if((locaddr->state == ADDR_TENTATIVE) && (locaddr->dadnscount <= uip_ds6_if.maxdadns) && (timer_expired(&locaddr->dadtimer)) && (uip_len == 0)) { uip_ds6_dad(locaddr); #endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } } } /* Periodic processing on default routers */ uip_ds6_defrt_periodic(); /* 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_REACHABLE: if(stimer_expired(&locnbr->reachable)) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&locnbr->ipaddr); PRINTF(")\n"); locnbr->state = NBR_STALE; } break; #if UIP_ND6_SEND_NA case NBR_INCOMPLETE: if(locnbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&locnbr->sendns) && (uip_len == 0)) { locnbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, NULL, &locnbr->ipaddr); stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; case NBR_DELAY: if(stimer_expired(&locnbr->reachable)) { locnbr->state = NBR_PROBE; locnbr->nscount = 0; PRINTF("DELAY: moving to PROBE\n"); stimer_set(&locnbr->sendns, 0); } break; case NBR_PROBE: if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { PRINTF("PROBE END\n"); if((locdefrt = uip_ds6_defrt_lookup(&locnbr->ipaddr)) != NULL) { if (!locdefrt->isinfinite) { uip_ds6_defrt_rm(locdefrt); } } uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&locnbr->sendns) && (uip_len == 0)) { locnbr->nscount++; PRINTF("PROBE: NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr); stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; #endif /* UIP_ND6_SEND_NA */ default: break; } } } #if UIP_CONF_ROUTER & UIP_ND6_SEND_RA /* Periodic RA sending */ if(stimer_expired(&uip_ds6_timer_ra) && (uip_len == 0)) { uip_ds6_send_ra_periodic(); } #endif /* UIP_CONF_ROUTER & UIP_ND6_SEND_RA */ etimer_reset(&uip_ds6_timer_periodic); return; }
/*---------------------------------------------------------------------------*/ void uip_ds6_periodic(void) { /* This flag signals whether we allow or not to send a packet in the current * invocation. */ u8_t allow_output = 1; /* minimum lifetime */ min_lifetime = 0xFFFFFFFF; /* router with minimum lifetime */ min_defrt = NULL; /* Periodic processing on registrations */ for(locreg = uip_ds6_reg_list; locreg < uip_ds6_reg_list + UIP_DS6_REG_LIST_SIZE; locreg++) { if (locreg->isused) { if (stimer_expired(&locreg->reg_lifetime)) { uip_ds6_reg_rm(locreg); } else if (allow_output) { /* If no output is allowed, it is pointless to enter here in this invocation */ if (uip_ds6_if.registration_in_progress) { /* There is a registration in progress */ if ((locreg == uip_ds6_if.registration_in_progress) && (timer_expired(&locreg->registration_timer))) { /* We already sent a NS message for this address but there has been no response */ if(locreg->reg_count >= UIP_ND6_MAX_UNICAST_SOLICIT) { /* NUD failed. Signal the need for next-hop determination by deleting the * NCE (RFC 4861) */ uip_ds6_reg_rm(locreg); /* And then, delete neighbor and corresponding router (as hosts only keep * NCEs for routers in 6lowpan-nd) */ locnbr = uip_ds6_nbr_lookup(&locreg->defrt->ipaddr); uip_ds6_nbr_rm(locnbr); uip_ds6_defrt_rm(locreg->defrt); /* Since we are deleting a default router, we must delete also all * registrations with that router. * Be careful here, uip_ds6_reg_cleanup_defrt() modifies the value of locreg!*/ uip_ds6_reg_cleanup_defrt(locreg->defrt); /* We will also need to start sending RS, as specified in I-D.ietf-6lowpan-nd * for NUD failure case */ uip_ds6_send_rs(NULL); uip_ds6_if.registration_in_progress = NULL; } else { locreg->reg_count++; timer_restart(&locreg->registration_timer); uip_nd6_ns_output(&locreg->addr->ipaddr, &locreg->defrt->ipaddr, &locreg->defrt->ipaddr, 1, UIP_ND6_REGISTRATION_LIFETIME); } allow_output = 0; /* Prevent this invocation from sending anything else */ } } else { /* There are no registrations in progress, let's see this entry needs (re)registration * or deletion */ if ((locreg->state == REG_GARBAGE_COLLECTIBLE) || (locreg->state == REG_TO_BE_UNREGISTERED) || ((locreg->state == REG_REGISTERED) && (stimer_remaining(&locreg->reg_lifetime) < stimer_elapsed(&locreg->reg_lifetime)))) { /* Issue (re)registration */ uip_ds6_if.registration_in_progress = locreg; locreg->reg_count++; timer_set(&locreg->registration_timer, (uip_ds6_if.retrans_timer / 1000) * (CLOCK_SECOND /* FIXME @@@jwg!!!!*/+250)); if (locreg->state == REG_TO_BE_UNREGISTERED) { uip_nd6_ns_output(&locreg->addr->ipaddr, &locreg->defrt->ipaddr, &locreg->defrt->ipaddr, 1, 0); } else { uip_nd6_ns_output(&locreg->addr->ipaddr, &locreg->defrt->ipaddr, &locreg->defrt->ipaddr, 1, UIP_ND6_REGISTRATION_LIFETIME); } allow_output = 0; /* Prevent this invocation from sending anything else */ } } } } } /* 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 (allow_output) { if (stimer_remaining(&locaddr->vlifetime) < min_lifetime) { min_lifetime = stimer_remaining(&locaddr->vlifetime); min_defrt = locaddr->defrt; } } } } /* Periodic processing on default routers */ if (uip_ds6_defrt_choose() == NULL) { if (allow_output) { /* If default router list is empty, start sending RS */ uip_ds6_send_rs(NULL); allow_output = 0; /* Prevent this invocation from sending anything else */ } } else { for(locdefrt = uip_ds6_defrt_list; locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) { if((locdefrt->isused) && (!locdefrt->isinfinite)) { if (stimer_expired(&(locdefrt->lifetime))) { uip_ds6_defrt_rm(locdefrt); /* If default router list is empty, we will start sending RS in * the next invocation of ds6_periodic() */ } else { if (allow_output) { if (stimer_remaining(&locdefrt->lifetime) < min_lifetime) { min_lifetime = stimer_remaining(&locdefrt->lifetime); min_defrt = 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)) { if (stimer_expired(&locprefix->vlifetime)) { uip_ds6_prefix_rm(locprefix); } else if (allow_output) { if (stimer_remaining(&locprefix->vlifetime) < min_lifetime) { min_lifetime = stimer_remaining(&locprefix->vlifetime); min_defrt = locprefix->defrt; } } } } #endif /* !UIP_CONF_ROUTER */ #if CONF_6LOWPAN_ND_6CO /* Periodic processing on contexts */ for(loccontext = uip_ds6_addr_context_table; loccontext < uip_ds6_addr_context_table + SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; loccontext++) { if(loccontext->state != NOT_IN_USE) { if (stimer_expired(&loccontext->vlifetime)) { if (loccontext->state != EXPIRED) { loccontext->state = IN_USE_UNCOMPRESS_ONLY; stimer_set(&loccontext->vlifetime, 2 * loccontext->defrt_lifetime); } else { uip_ds6_context_rm(loccontext); } } else if (allow_output) { if (stimer_remaining(&loccontext->vlifetime) < min_lifetime) { min_lifetime = stimer_remaining(&loccontext->vlifetime); min_defrt = loccontext->defrt; } } } } #endif /* CONF_6LOWPAN_ND_6CO */ /* Start sending RS well before the minimum of the lifetimes (def. router, * context, or prefix) expires */ if ((allow_output) && (min_lifetime < UIP_DS6_LIFETIME_THRESHOLD)) { /* Start sending RSs to the router with minimum lifetime (if possible) */ uip_ds6_send_rs(min_defrt); allow_output = 0; } /* 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) { #if UIP_CONF_ROUTER /* There can not be INCOMPLETE NCEs in a host in 6lowpan-nd */ case NBR_INCOMPLETE: if (allow_output) { 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\n", locnbr->nscount); uip_nd6_ns_output(NULL, NULL, &locnbr->ipaddr); stimer_set(&(locnbr->sendns), uip_ds6_if.retrans_timer / 1000); allow_output = 0; } } break; #endif /* UIP_CONF_ROUTER */ case NBR_REACHABLE: if(stimer_expired(&(locnbr->reachable))) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&locnbr->ipaddr); PRINTF(")\n"); locnbr->state = NBR_STALE; NEIGHBOR_STATE_CHANGED(locnbr); } break; case NBR_DELAY: if (allow_output) { if(stimer_expired(&(locnbr->reachable))) { locnbr->state = NBR_PROBE; locnbr->nscount = 1; NEIGHBOR_STATE_CHANGED(locnbr); PRINTF("DELAY: moving to PROBE + NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr, 0, 0); stimer_set(&(locnbr->sendns), uip_ds6_if.retrans_timer / 1000); allow_output = 0; } } break; case NBR_PROBE: if (allow_output) { if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { PRINTF("PROBE END \n"); 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\n", locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr, 0, 0); stimer_set(&(locnbr->sendns), uip_ds6_if.retrans_timer / 1000); allow_output = 0; } } 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; }
/*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * uip_ds6_nbr_add(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state) { int r; 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\n", 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 && !uip_ds6_defrt_lookup(&n->ipaddr)) { 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\n"); return NULL; }
/** * \brief Performs periodic tasks for 6LP-GW variable management, such as * processing of neighbor lifetimes and DAD timers */ void pgw_periodic() { /* periodic processing of contexts */ for(loccontext = pgw_addr_context_table; loccontext < pgw_addr_context_table + SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; loccontext++) { if (loccontext->state != NOT_IN_USE) { if (stimer_expired(&loccontext->vlifetime)) { switch(loccontext->state) { case IN_USE_UNCOMPRESS_ONLY: loccontext->state = IN_USE_COMPRESS; stimer_set(&loccontext->vlifetime, PGW_CONTEXT_LIFETIME); context_chaged = 1; break; case IN_USE_COMPRESS: loccontext->state = EXPIRED; if (loccontext->vlifetime.interval > PGW_MIN_CONTEXT_CHANGE_DELAY) { stimer_reset(&loccontext->vlifetime); } else { /* This way we make sure that, if the context is eventually deleted, * No other context will use its id in a period of at least * MIN_CONTEXT_CHANGE_DELAY */ stimer_set(&loccontext->vlifetime, PGW_MIN_CONTEXT_CHANGE_DELAY); } context_chaged = 1; break; case EXPIRED: pgw_context_rm(loccontext); break; } } } } /* periodic processing of neighbors */ for(locnbr = pgw_6ln_cache; locnbr < pgw_6ln_cache + MAX_6LOWPAN_NEIGHBORS; locnbr++) { if(locnbr->isused) { /* * If the reachable timer is expired, we delete the NCE, * regardless of the NCE's state. */ if(stimer_expired(&(locnbr->reachable))) { /* I-D.ietf-6lowpan-nd: Should the Registration Lifetime in a NCE expire, * then the router MUST delete the cache entry. */ pgw_nbr_rm(locnbr); } else if ((locnbr->state == PGW_TENTATIVE) && (!uip_is_addr_link_local(&locnbr->ipaddr))) { if ((locnbr->dadnscount <= PGW_MAX_DAD_NS) && (timer_expired(&locnbr->dadtimer))) { pgw_dad(locnbr); /* If we found a neighbor requiring DAD, perform it. If there were * more neighbors requiring it, we'll do it in further invocations */ return; } } } } etimer_reset(&pgw_timer_periodic); return; }