Example #1
0
/*---------------------------------------------------------------------------*/
void
rpl_remove_routes(rpl_dag_t *dag)
{
  uip_ds6_route_t *r;
#if RPL_CONF_MULTICAST
  uip_mcast6_route_t *mcast_route;
#endif

  r = uip_ds6_route_head();

  while(r != NULL) {
    if(r->state.dag == dag) {
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
    } else {
      r = uip_ds6_route_next(r);
    }
  }

#if RPL_CONF_MULTICAST
  mcast_route = uip_mcast6_route_list_head();

  while(mcast_route != NULL) {
    if(mcast_route->dag == dag) {
      uip_mcast6_route_rm(mcast_route);
      mcast_route = uip_mcast6_route_list_head();
    } else {
      mcast_route = list_item_next(mcast_route);
    }
  }
#endif
}
Example #2
0
void
uip_ds6_route_info_callback(uip_nd6_opt_route_info * rio,
                            uip_ip6addr_t * next_hop)
{
    PRINTF("RIO received\n");
    //TODO Preferences ?
    uip_ds6_route_t *found;

    if((found = uip_ds6_route_lookup(&rio->prefix)) == NULL
            && rio->rlifetime != 0) {
        //New route
        PRINTF("New route received\n");
        PRINTF("type=%d, flags=%d, length=%d, lifetime=%"PRIu32", Preflen=%d, prefix=",
               rio->type, rio->flagsreserved, rio->len, uip_ntohl(rio->rlifetime), rio->preflen);
        uip_ds6_route_t *new_route;

        if((new_route =
                    uip_ds6_route_add(&rio->prefix, rio->preflen, next_hop)) == NULL) {
            PRINTF("error when adding route\n");
        } else {
            PRINTF("Route added\n");
            new_route->state.lifetime = uip_ntohl(rio->rlifetime);
        }
    } else {
        PRINTF("Route already exists\n");
        if(rio->rlifetime == 0) {
            uip_ds6_route_rm(found);
        } else {
            found->state.lifetime = uip_ntohl(rio->rlifetime);
        }
    }
}
Example #3
0
void
rpl_remove_routes(rpl_dag_t *dag)
{
  int i;

  for(i = 0; i < UIP_DS6_ROUTE_NB; i++) {
    if(uip_ds6_routing_table[i].state.dag == dag) {
      uip_ds6_route_rm(&uip_ds6_routing_table[i]);
    }
  }
}
Example #4
0
/*---------------------------------------------------------------------------*/
void
rpl_purge_routes(void)
{
  uip_ds6_route_t *r;
  uip_ipaddr_t prefix;
  rpl_dag_t *dag;
  rpl_instance_t *instance; //changed

  /* First pass, decrement lifetime */
  r = uip_ds6_route_head();

  while(r != NULL) {
    if(r->state.lifetime >= 1) {
      /*
       * If a route is at lifetime == 1, set it to 0, scheduling it for
       * immediate removal below. This achieves the same as the original code,
       * which would delete lifetime <= 1
       */
      r->state.lifetime--;
    }
    r = uip_ds6_route_next(r);
  }

  /* Second pass, remove dead routes */
  r = uip_ds6_route_head();

  while(r != NULL) {
    /*Pre-change handle second_instance*/
    if(r->state.lifetime < 1) {
      /* Routes with lifetime == 1 have only just been decremented from 2 to 1,
       * thus we want to keep them. Hence < and not <= */
      uip_ipaddr_copy(&prefix, &r->ipaddr);
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
      PRINTF("No more routes to ");
      PRINT6ADDR(&prefix);
      /*Changed*/
      instance = rpl_get_instance(r->state.instance_id);
      dag = instance->current_dag;
      //dag1 = second_instance->current_dag;
      /* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */
      if(dag->rank != ROOT_RANK(instance)) {
        PRINTF(" -> generate No-Path DAO\n");
        dao_output_target(dag->preferred_parent, &prefix, RPL_ZERO_LIFETIME);
        /* Don't schedule more than 1 No-Path DAO, let next iteration handle that */
        return;
      }
      PRINTF("\n");
    } else {
      r = uip_ds6_route_next(r);
    }
  }
}
Example #5
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_lookup(uip_ipaddr_t *destipaddr)
{
  uip_ds6_route_t *locrt = NULL;
  uint8_t longestmatch = 0;

  PRINTF("DS6: Looking up route for ");
  PRINT6ADDR(destipaddr);
  PRINTF("\n");

  for(locroute = uip_ds6_routing_table;
      locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB; locroute++) {
    if((locroute->isused) && (locroute->length >= longestmatch)
       &&
       (uip_ipaddr_prefixcmp
        (destipaddr, &locroute->ipaddr, locroute->length))) {
      longestmatch = locroute->length;
      locrt = locroute;
    }
  }

  if(locrt != NULL) {
#ifdef UIP_DS6_ROUTE_STATE_CLEAN
    switch (locrt->state.learned_from) {
      case RPL_ROUTE_FROM_UNICAST_DAO:
      case RPL_ROUTE_FROM_MULTICAST_DAO:
      case RPL_ROUTE_FROM_DIO:
        if(UIP_DS6_ROUTE_STATE_CLEAN(&locrt->state)) {
          uip_ds6_route_rm(locrt);
          //TODO : verify that the prefix len is 128
          mob_lost_node(locrt);
          PRINTF("DS6: Route timeout\n");
          return NULL;
        }
        break;
      default:
        break;
    }
#endif /* UIP_DS6_ROUTE_STATE_TYPE */
    PRINTF("DS6: Found route:");
    PRINT6ADDR(destipaddr);
    PRINTF(" via ");
    PRINT6ADDR(&locrt->nexthop);
    PRINTF("\n");
  } else {
    PRINTF("DS6: No route found\n");
  }

  return locrt;
}
Example #6
0
void
rpl_purge_routes(void)
{
  int i;

  for(i = 0; i < UIP_DS6_ROUTE_NB; i++) {
    if(uip_ds6_routing_table[i].isused) {
      if(uip_ds6_routing_table[i].state.lifetime <= 1) {
        uip_ds6_route_rm(&uip_ds6_routing_table[i]);
      } else {
        uip_ds6_routing_table[i].state.lifetime--;
      }
    }
  }
}
Example #7
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop,
                  uint8_t metric)
{
  loc_loop_state = uip_ds6_list_loop
     ((uip_ds6_element_t *)uip_ds6_routing_table, UIP_DS6_ROUTE_NB,
      sizeof(uip_ds6_route_t), ipaddr, length,
      (uip_ds6_element_t **)&locroute);

#ifdef UIP_DS6_ROUTE_STATE_CLEAN
  if (loc_loop_state == NOSPACE) {
    for(locroute = uip_ds6_routing_table;
        locroute < uip_ds6_routing_table + UIP_DS6_ROUTE_NB;
        ++locroute) {
      if(locroute->isused
          && (UIP_DS6_ROUTE_STATE_CLEAN(&locroute->state))) {
        uip_ds6_route_rm(locroute);
        loc_loop_state = FREESPACE;
        break;
      }
    }
  }
  if (loc_loop_state == NOSPACE) {
    locroute = NULL;
  }
#endif /* UIP_DS6_ROUTE_STATE_TYPE */

  if (loc_loop_state == FREESPACE) {
    locroute->isused = 1;
    uip_ipaddr_copy(&(locroute->ipaddr), ipaddr);
    locroute->length = length;
    uip_ipaddr_copy(&(locroute->nexthop), nexthop);
    locroute->metric = metric;

#ifdef UIP_DS6_ROUTE_STATE_TYPE
    memset (&(locroute->state),0,sizeof(UIP_DS6_ROUTE_STATE_TYPE));
#endif

    PRINTF("DS6: adding route: ");
    PRINT6ADDR(ipaddr);
    PRINTF(" via ");
    PRINT6ADDR(nexthop);
    PRINTF("\n");
    ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
  }

  return locroute;
}
Example #8
0
/*---------------------------------------------------------------------------*/
void
rpl_remove_routes(rpl_dag_t *dag)
{
  uip_ds6_route_t *r;

  r = uip_ds6_route_head();

  while(r != NULL) {
    if(r->state.dag == dag) {
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
    } else {
      r = uip_ds6_route_next(r);
    }
  }
}
Example #9
0
static httpd_cgi_call_t *
webserver_network_route_rm(struct httpd_state *s)
{
  uip_ds6_route_t *route;
  uip_ipaddr_t ipaddr;
  webserver_result_title = "Network";
  webserver_result_text = "Delete route: Route not found";
  if(s->query && uiplib_ipaddrconv(s->query, &ipaddr) != 0) {
    route = uip_ds6_route_lookup(&ipaddr);
    if(route) {
      uip_ds6_route_rm(route);
      webserver_result_text = "Route deleted";
    }
  }
  return &webserver_result_page;
}
Example #10
0
/*---------------------------------------------------------------------------*/
void
rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag)
{
  uip_ds6_route_t *r;

  r = uip_ds6_route_head();

  while(r != NULL) {
    if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) &&
       r->state.dag == dag) {
      uip_ds6_route_rm(r);
      r = uip_ds6_route_head();
    } else {
      r = uip_ds6_route_next(r);
    }
  }
  ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
}
Example #11
0
/*---------------------------------------------------------------------------*/
static void
rm_routelist(struct uip_ds6_route_neighbor_routes *routes)
{
#if DEBUG != DEBUG_NONE
  assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
  PRINTF("uip_ds6_route_rm_routelist\n");
  if(routes != NULL && routes->route_list != NULL) {
    struct uip_ds6_route_neighbor_route *r;
    r = list_head(routes->route_list);
    while(r != NULL) {
      uip_ds6_route_rm(r->route);
      r = list_head(routes->route_list);
    }
    nbr_table_remove(nbr_routes, routes);
  }
#if DEBUG != DEBUG_NONE
  assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
}
Example #12
0
void
tcpip_ipv6_output(void)
{
  uip_ds6_nbr_t *nbr = NULL;
  uip_ipaddr_t *nexthop;

  if(uip_len == 0) {
    return;
  }

  if(uip_len > UIP_LINK_MTU) {
    UIP_LOG("tcpip_ipv6_output: Packet to big");
    uip_clear_buf();
    return;
  }

  if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){
    UIP_LOG("tcpip_ipv6_output: Destination address unspecified");
    uip_clear_buf();
    return;
  }

  if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
    /* Next hop determination */
    nbr = NULL;

    /* We first check if the destination address is on our immediate
       link. If so, we simply use the destination address as our
       nexthop address. */
    if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
      nexthop = &UIP_IP_BUF->destipaddr;
    } else {
      uip_ds6_route_t *route;
      /* Check if we have a route to the destination address. */
      route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);

      /* No route was found - we send to the default route instead. */
      if(route == NULL) {
        PRINTF("tcpip_ipv6_output: no route found, using default route\n");
        nexthop = uip_ds6_defrt_choose();
        if(nexthop == NULL) {
#ifdef UIP_FALLBACK_INTERFACE
	  PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", 
		 uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40));
	  if(uip_ext_len > 0) {
	    extern void remove_ext_hdr(void);
	    uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40);
	    remove_ext_hdr();
	    /* This should be copied from the ext header... */
	    UIP_IP_BUF->proto = proto;
	  }
	  /* Inform the other end that the destination is not reachable. If it's
	   * not informed routes might get lost unexpectedly until there's a need
	   * to send a new packet to the peer */
	  if(UIP_FALLBACK_INTERFACE.output() < 0) {
	    PRINTF("FALLBACK: output error. Reporting DST UNREACH\n");
	    uip_icmp6_error_output(ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0);
	    uip_flags = 0;
	    tcpip_ipv6_output();
	    return;
	  }
#else
          PRINTF("tcpip_ipv6_output: Destination off-link but no route\n");
#endif /* !UIP_FALLBACK_INTERFACE */
          uip_clear_buf();
          return;
        }

      } else {
        /* A route was found, so we look up the nexthop neighbor for
           the route. */
        nexthop = uip_ds6_route_nexthop(route);

        /* If the nexthop is dead, for example because the neighbor
           never responded to link-layer acks, we drop its route. */
        if(nexthop == NULL) {
#if UIP_CONF_IPV6_RPL
          /* If we are running RPL, and if we are the root of the
             network, we'll trigger a global repair berfore we remove
             the route. */
          rpl_dag_t *dag;
          rpl_instance_t *instance;

          dag = (rpl_dag_t *)route->state.dag;
          if(dag != NULL) {
            instance = dag->instance;

            rpl_repair_root(instance->instance_id);
          }
#endif /* UIP_CONF_IPV6_RPL */
          uip_ds6_route_rm(route);

          /* We don't have a nexthop to send the packet to, so we drop
             it. */
          return;
        }
      }
#if TCPIP_CONF_ANNOTATE_TRANSMISSIONS
      if(nexthop != NULL) {
        static uint8_t annotate_last;
        static uint8_t annotate_has_last = 0;

        if(annotate_has_last) {
          printf("#L %u 0; red\n", annotate_last);
        }
        printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
        annotate_last = nexthop->u8[sizeof(uip_ipaddr_t) - 1];
        annotate_has_last = 1;
      }
#endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */
    }

    /* End of next hop determination */

#if UIP_CONF_IPV6_RPL
    if(rpl_update_header_final(nexthop)) {
      uip_clear_buf();
      return;
    }
#endif /* UIP_CONF_IPV6_RPL */
    nbr = uip_ds6_nbr_lookup(nexthop);
    if(nbr == NULL) {
#if UIP_ND6_SEND_NA
      if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) {
        uip_clear_buf();
        return;
      } else {
#if UIP_CONF_IPV6_QUEUE_PKT
        /* Copy outgoing pkt in the queuing buffer for later transmit. */
        if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) {
          memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len);
          uip_packetqueue_set_buflen(&nbr->packethandle, uip_len);
        }
#endif
      /* RFC4861, 7.2.2:
       * "If the source address of the packet prompting the solicitation is the
       * same as one of the addresses assigned to the outgoing interface, that
       * address SHOULD be placed in the IP Source Address of the outgoing
       * solicitation.  Otherwise, any one of the addresses assigned to the
       * interface should be used."*/
       if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)){
          uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr);
        } else {
          uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
        }

        stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
        nbr->nscount = 1;
        /* Send the first NS try from here (multicast destination IP address). */
      }
#else /* UIP_ND6_SEND_NA */
      uip_len = 0;
      return;  
#endif /* UIP_ND6_SEND_NA */
    } else {
#if UIP_ND6_SEND_NA
      if(nbr->state == NBR_INCOMPLETE) {
        PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n");
#if UIP_CONF_IPV6_QUEUE_PKT
        /* Copy outgoing pkt in the queuing buffer for later transmit and set
           the destination nbr to nbr. */
        if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) {
          memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len);
          uip_packetqueue_set_buflen(&nbr->packethandle, uip_len);
        }
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/
        uip_clear_buf();
        return;
      }
      /* Send in parallel if we are running NUD (nbc state is either STALE,
         DELAY, or PROBE). See RFC 4861, section 7.3.3 on node behavior. */
      if(nbr->state == NBR_STALE) {
        nbr->state = NBR_DELAY;
        stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
        nbr->nscount = 0;
        PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
      }
#endif /* UIP_ND6_SEND_NA */

      tcpip_output(uip_ds6_nbr_get_ll(nbr));

#if UIP_CONF_IPV6_QUEUE_PKT
      /*
       * Send the queued packets from here, may not be 100% perfect though.
       * This happens in a few cases, for example when instead of receiving a
       * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves
       * to STALE, and you must both send a NA and the queued packet.
       */
      if(uip_packetqueue_buflen(&nbr->packethandle) != 0) {
        uip_len = uip_packetqueue_buflen(&nbr->packethandle);
        memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len);
        uip_packetqueue_free(&nbr->packethandle);
        tcpip_output(uip_ds6_nbr_get_ll(nbr));
      }
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/

      uip_clear_buf();
      return;
    }
  }
  /* Multicast IP destination address. */
  tcpip_output(NULL);
  uip_clear_buf();
}
Example #13
0
/*---------------------------------------------------------------------------*/
httpd_simple_script_t
httpd_simple_get_script(const char *name)
{
  static uip_ds6_route_t *r;
  static char filename[HTTPD_PATHLEN];
  static int i;

  strcpy(filename, slip_config_www_root);
  strcat(filename, "/");
  strcat(filename, name);

  redirect = 0;

  if(strcmp(name, "index.html") == 0 || strcmp(name, "") == 0) {
    return generate_index;
#if CONTIKI_TARGET_NATIVE
  } else if (access(filename, R_OK) == 0) {
      return send_file;
#endif
#if CETIC_NODE_INFO
  } else if(strcmp(name, "sensors.html") == 0) {
    return generate_sensors;
#endif
  } else if(strcmp(name, "rpl.html") == 0) {
    return generate_rpl;
  } else if(strcmp(name, "network.html") == 0) {
    return generate_network;
  } else if(strcmp(name, "config.html") == 0) {
    return generate_config;
  } else if(strcmp(name, "statistics.html") == 0) {
    return generate_statistics;
  } else if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
    if(strcmp(name, "rpl-gr") == 0) {
#if UIP_CONF_IPV6_RPL
      rpl_repair_root(RPL_DEFAULT_INSTANCE);
#endif
      return generate_rpl;
    } else if(memcmp(name, "route_rm?", 9) == 0) {
      redirect = 1;
      i = atoi(name + 9);
      for(r = uip_ds6_route_list_head(); r != NULL; r = list_item_next(r), --i) {
        if(i == 0) {
          uip_ds6_route_rm(r);
          break;
        }
      }
      return generate_network;
    } else if(memcmp(name, "nbr_rm?", 7) == 0) {
      redirect = 1;
      uip_ds6_nbr_rm(&uip_ds6_nbr_cache[atoi(name + 7)]);
      return generate_network;
    } else if(memcmp(name, "config?", 7) == 0) {
      if(update_config(name + 7)) {
        return generate_config;
      } else {
        return generate_reboot;
      }
    } else {
      return generate_404;
    }
  } else {
    return generate_404;
  }
}
Example #14
0
/*---------------------------------------------------------------------------*/
uip_ds6_route_t *
uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
		  uip_ipaddr_t *nexthop)
{
  uip_ds6_route_t *r;
  struct uip_ds6_route_neighbor_route *nbrr;

#if DEBUG != DEBUG_NONE
  assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */

  /* Get link-layer address of next hop, make sure it is in neighbor table */
  const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop);
  if(nexthop_lladdr == NULL) {
    PRINTF("uip_ds6_route_add: neighbor link-local address unknown for ");
    PRINT6ADDR(nexthop);
    PRINTF("\n");
    return NULL;
  }

  /* First make sure that we don't add a route twice. If we find an
     existing route for our destination, we'll delete the old
     one first. */
  r = uip_ds6_route_lookup(ipaddr);
  if(r != NULL) {
    PRINTF("uip_ds6_route_add: old route for ");
    PRINT6ADDR(ipaddr);
    PRINTF(" found, deleting it\n");
    uip_ds6_route_rm(r);
  }
  {
    struct uip_ds6_route_neighbor_routes *routes;
    /* If there is no routing entry, create one. We first need to
       check if we have room for this route. If not, we remove the
       least recently used one we have. */

    if(uip_ds6_route_num_routes() == UIP_DS6_ROUTE_NB) {
      /* Removing the oldest route entry from the route table. The
         least recently used route is the first route on the list. */
      uip_ds6_route_t *oldest;

      oldest = list_tail(routelist); /* uip_ds6_route_head(); */
      PRINTF("uip_ds6_route_add: dropping route to ");
      PRINT6ADDR(&oldest->ipaddr);
      PRINTF("\n");
      uip_ds6_route_rm(oldest);
    }


    /* Every neighbor on our neighbor table holds a struct
       uip_ds6_route_neighbor_routes which holds a list of routes that
       go through the neighbor. We add our route entry to this list.

       We first check to see if we already have this neighbor in our
       nbr_route table. If so, the neighbor already has a route entry
       list.
    */
    routes = nbr_table_get_from_lladdr(nbr_routes,
                                       (linkaddr_t *)nexthop_lladdr);

    if(routes == NULL) {
      /* If the neighbor did not have an entry in our neighbor table,
         we create one. The nbr_table_add_lladdr() function returns a
         pointer to a pointer that we may use for our own purposes. We
         initialize this pointer with the list of routing entries that
         are attached to this neighbor. */
      routes = nbr_table_add_lladdr(nbr_routes,
                                    (linkaddr_t *)nexthop_lladdr);
      if(routes == NULL) {
        /* This should not happen, as we explicitly deallocated one
           route table entry above. */
        PRINTF("uip_ds6_route_add: could not allocate neighbor table entry\n");
        return NULL;
      }
      LIST_STRUCT_INIT(routes, route_list);
    }

    /* Allocate a routing entry and populate it. */
    r = memb_alloc(&routememb);

    if(r == NULL) {
      /* This should not happen, as we explicitly deallocated one
         route table entry above. */
      PRINTF("uip_ds6_route_add: could not allocate route\n");
      return NULL;
    }

    /* add new routes first - assuming that there is a reason to add this
       and that there is a packet coming soon. */
    list_push(routelist, r);

    nbrr = memb_alloc(&neighborroutememb);
    if(nbrr == NULL) {
      /* This should not happen, as we explicitly deallocated one
         route table entry above. */
      PRINTF("uip_ds6_route_add: could not allocate neighbor route list entry\n");
      memb_free(&routememb, r);
      return NULL;
    }

    nbrr->route = r;
    /* Add the route to this neighbor */
    list_add(routes->route_list, nbrr);
    r->neighbor_routes = routes;
    num_routes++;

    PRINTF("uip_ds6_route_add num %d\n", num_routes);
  }

  uip_ipaddr_copy(&(r->ipaddr), ipaddr);
  r->length = length;

#ifdef UIP_DS6_ROUTE_STATE_TYPE
  memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE));
#endif

  PRINTF("uip_ds6_route_add: adding route: ");
  PRINT6ADDR(ipaddr);
  PRINTF(" via ");
  PRINT6ADDR(nexthop);
  PRINTF("\n");
  ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);

#if UIP_DS6_NOTIFICATIONS
  call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop);
#endif

#if DEBUG != DEBUG_NONE
  assert_nbr_routes_list_sane();
#endif /* DEBUG != DEBUG_NONE */
  return r;
}
Example #15
0
/* Switch the ports and addresses and set route and neighbor cache.
 * Returns 1 if packet was sent properly, in this case it is the caller
 * that needs to release the net_buf. If 0 is returned, then uIP stack
 * has released the net_buf already because there was an some net related
 * error when sending the buffer.
 */
static inline int udp_prepare_and_send(struct net_context *context,
				       struct net_buf *buf)
{
#ifdef CONFIG_NETWORKING_WITH_IPV6
	uip_ds6_route_t *route_old, *route_new = NULL;
	uip_ds6_nbr_t *nbr;
#endif
	uip_ipaddr_t tmp;
	uint16_t port;
	uint8_t ret;

	if (uip_len(buf) == 0) {
		/* This is expected as uIP will typically set the
		 * packet length to 0 after receiving it. So we need
		 * to fix the length here. The protocol specific
		 * part is added also here.
		 */
		uip_len(buf) = uip_slen(buf) = uip_appdatalen(buf);
		buf->data = buf->buf + UIP_IPUDPH_LEN;
	}

	port = UIP_UDP_BUF(buf)->srcport;
	UIP_UDP_BUF(buf)->srcport = UIP_UDP_BUF(buf)->destport;
	UIP_UDP_BUF(buf)->destport = port;

	uip_ipaddr_copy(&tmp, &UIP_IP_BUF(buf)->srcipaddr);
	uip_ipaddr_copy(&UIP_IP_BUF(buf)->srcipaddr,
			&UIP_IP_BUF(buf)->destipaddr);
	uip_ipaddr_copy(&UIP_IP_BUF(buf)->destipaddr, &tmp);

#ifdef CONFIG_NETWORKING_WITH_IPV6
	/* The peer needs to be in neighbor cache before route can be added.
	 */
	nbr = uip_ds6_nbr_lookup((uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr);
	if (!nbr) {
		const uip_lladdr_t *lladdr = (const uip_lladdr_t *)&buf->src;
		nbr = uip_ds6_nbr_add(
			(uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr,
			lladdr, 0, NBR_REACHABLE);
		if (!nbr) {
			NET_DBG("Cannot add peer ");
			PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr);
			PRINT(" to neighbor cache\n");
		}
	}

	/* Temporarily add route to peer, delete the route after
	 * sending the packet. Check if there was already a
	 * route and do not remove it if there was existing
	 * route to this peer.
	 */
	route_old = uip_ds6_route_lookup(&UIP_IP_BUF(buf)->destipaddr);
	if (!route_old) {
		route_new = uip_ds6_route_add(&UIP_IP_BUF(buf)->destipaddr,
					      128,
					      &UIP_IP_BUF(buf)->destipaddr);
		if (!route_new) {
			NET_DBG("Cannot add route to peer ");
			PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr);
			PRINT("\n");
		}
	}
#endif

	ret = simple_udp_sendto_port(buf,
				     net_context_get_udp_connection(context),
				     buf->data, buf->len,
				     &UIP_IP_BUF(buf)->destipaddr,
				     uip_ntohs(UIP_UDP_BUF(buf)->destport));
	if (!ret) {
		NET_DBG("Packet could not be sent properly.\n");
	}

#ifdef CONFIG_NETWORKING_WITH_IPV6
	if (!route_old && route_new) {
		/* This will also remove the neighbor cache entry */
		uip_ds6_route_rm(route_new);
	}
#endif

	return ret;
}
Example #16
0
int
rpl_verify_header(int uip_ext_opt_offset)
{
  rpl_instance_t *instance;
  int down;
  uint8_t sender_closer;
  uip_ds6_route_t *route;

  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
    PRINTF("RPL: Bad header option! (wrong length)\n");
    return 1;
  }

  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
  if(instance == NULL) {
    PRINTF("RPL: Unknown instance: %u\n",
           UIP_EXT_HDR_OPT_RPL_BUF->instance);
    return 1;
  }

  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
    PRINTF("RPL: Forward error!\n");
    /* We should try to repair it by removing the neighbor that caused
       the packet to be forwareded in the first place. We drop any
       routes that go through the neighbor that sent the packet to
       us. */
    route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
    if(route != NULL) {
      uip_ds6_route_rm(route);

      /* If we are the root and just needed to remove a DAO route,
         chances are that the network needs to be repaired. The
         rpl_repair_root() function will cause a global repair if we
         happen to be the root node of the dag. */
      PRINTF("RPL: initiate global repair\n");
      rpl_repair_root(instance->instance_id);
    }

    /* Remove the forwarding error flag and return 0 to let the packet
       be forwarded again. */
    UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_FWD_ERR;
    return 0;
  }

  if(!instance->current_dag->joined) {
    PRINTF("RPL: No DAG in the instance\n");
    return 1;
  }

  down = 0;
  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) {
    down = 1;
  }

  sender_closer = UIP_EXT_HDR_OPT_RPL_BUF->senderrank < instance->current_dag->rank;

  PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up",
	 sender_closer,
	 UIP_EXT_HDR_OPT_RPL_BUF->senderrank,
	 instance->current_dag->rank
	 );

  if((down && !sender_closer) || (!down && sender_closer)) {
    PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
	   UIP_EXT_HDR_OPT_RPL_BUF->senderrank, instance->current_dag->rank,
	   sender_closer);
    if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) {
      PRINTF("RPL: Rank error signalled in RPL option!\n");
      /* We should try to repair it, not implemented for the moment */
      rpl_reset_dio_timer(instance);
      /* Forward the packet anyway. */
      return 0;
    }
    PRINTF("RPL: Single error tolerated\n");
    UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
    return 0;
  }

  PRINTF("RPL: Rank OK\n");

  return 0;
}
Example #17
0
File: tcpip.c Project: adutze/6lbr
void
tcpip_ipv6_output(void)
{
  uip_ds6_nbr_t *nbr = NULL;
  uip_ipaddr_t *nexthop;
  uip_ds6_route_t *route = NULL;

  if(uip_len == 0) {
    return;
  }

  PRINTF("IPv6 packet send from ");
  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
  PRINTF(" to ");
  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
  PRINTF("\n");

  if(uip_len > UIP_LINK_MTU) {
    UIP_LOG("tcpip_ipv6_output: Packet to big");
    uip_clear_buf();
    return;
  }

  if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){
    UIP_LOG("tcpip_ipv6_output: Destination address unspecified");
    uip_clear_buf();
    return;
  }

  if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
    /* Next hop determination */
    nbr = NULL;

    /* We first check if the destination address is on our immediate
       link. If so, we simply use the destination address as our
       nexthop address. */
    if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
      nexthop = &UIP_IP_BUF->destipaddr;
    } else {
      /* Check if we have a route to the destination address. */
      route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);

      /* No route was found - we send to the default route instead. */
      if(route == NULL) {
#if CETIC_6LBR_SMARTBRIDGE
        if (uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64)) {
          /* In smart-bridge mode, there is no route towards hosts on the Ethernet side
          Therefore we have to check the destination and assume the host is on-link */
          nexthop = &UIP_IP_BUF->destipaddr;
        } else
#endif
#if CETIC_6LBR_ROUTER && UIP_CONF_IPV6_RPL
        if (is_dodag_root() && uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64)) {
          //In router mode, we drop packets towards unknown mote
          PRINTF("Dropping wsn packet with no route\n");
          uip_len = 0;
          return;
        } else
#endif
#if CETIC_6LBR_IP64
        if(ip64_addr_is_ip64(&UIP_IP_BUF->destipaddr)) {
#if UIP_CONF_IPV6_RPL
          rpl_remove_header();
#endif
          IP64_CONF_UIP_FALLBACK_INTERFACE.output();
          uip_len = 0;
          uip_ext_len = 0;
          return;
        }
        else
#endif
        {
          PRINTF("tcpip_ipv6_output: no route found, using default route\n");
          nexthop = uip_ds6_defrt_choose();
        }
        if(nexthop == NULL) {
#ifdef UIP_FALLBACK_INTERFACE
	  PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n", 
		 uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40));
	  if(uip_ext_len > 0) {
	    extern void remove_ext_hdr(void);
	    uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40);
	    remove_ext_hdr();
	    /* This should be copied from the ext header... */
	    UIP_IP_BUF->proto = proto;
	  }
	  UIP_FALLBACK_INTERFACE.output();
#else
          PRINTF("tcpip_ipv6_output: Destination off-link but no route\n");
#endif /* !UIP_FALLBACK_INTERFACE */
          uip_clear_buf();
          return;
        }

      } else {
        /* A route was found, so we look up the nexthop neighbor for
           the route. */
        nexthop = uip_ds6_route_nexthop(route);

        /* If the nexthop is dead, for example because the neighbor
           never responded to link-layer acks, we drop its route. */
        if(nexthop == NULL) {
#if UIP_CONF_IPV6_RPL
          /* If we are running RPL, and if we are the root of the
             network, we'll trigger a DIO before we remove
             the route. */
          rpl_dag_t *dag;

          dag = (rpl_dag_t *)route->state.dag;
          if(dag != NULL) {
            rpl_reset_dio_timer(dag->instance);
          }
#endif /* UIP_CONF_IPV6_RPL */
          uip_ds6_route_rm(route);

          /* We don't have a nexthop to send the packet to, so we drop
             it. */
          return;
        }
      }
#if TCPIP_CONF_ANNOTATE_TRANSMISSIONS
      if(nexthop != NULL) {
        static uint8_t annotate_last;
        static uint8_t annotate_has_last = 0;

        if(annotate_has_last) {
          printf("#L %u 0; red\n", annotate_last);
        }
        printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
        annotate_last = nexthop->u8[sizeof(uip_ipaddr_t) - 1];
        annotate_has_last = 1;
      }
#endif /* TCPIP_CONF_ANNOTATE_TRANSMISSIONS */
    }

    /* End of next hop determination */

#if UIP_CONF_IPV6_RPL
    if(rpl_update_header_final(nexthop)) {
      uip_clear_buf();
      return;
    }
#endif /* UIP_CONF_IPV6_RPL */
    nbr = uip_ds6_nbr_lookup(nexthop);
    if(nbr == NULL) {
#if UIP_ND6_SEND_NA
#if CETIC_6LBR && UIP_CONF_IPV6_RPL
      /* Don't perform NUD if it has been disabled for WSN */
      if((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_WSN_NUD) != 0 &&
         uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64) &&
         route != NULL) {
        uip_clear_buf();
        return;
      }
#endif
      if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE)) == NULL) {
        uip_clear_buf();
        return;
      } else {
#if UIP_CONF_IPV6_QUEUE_PKT
        /* Copy outgoing pkt in the queuing buffer for later transmit. */
        if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) {
          memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len);
          uip_packetqueue_set_buflen(&nbr->packethandle, uip_len);
        }
#endif
      /* RFC4861, 7.2.2:
       * "If the source address of the packet prompting the solicitation is the
       * same as one of the addresses assigned to the outgoing interface, that
       * address SHOULD be placed in the IP Source Address of the outgoing
       * solicitation.  Otherwise, any one of the addresses assigned to the
       * interface should be used."*/
       if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)){
          uip_nd6_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbr->ipaddr);
        } else {
          uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr);
        }

        stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
        nbr->nscount = 1;
        /* Send the first NS try from here (multicast destination IP address). */
      }
#else /* UIP_ND6_SEND_NA */
      uip_len = 0;
      return;  
#endif /* UIP_ND6_SEND_NA */
    } else {
#if UIP_ND6_SEND_NA
      if(nbr->state == NBR_INCOMPLETE) {
        PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n");
#if UIP_CONF_IPV6_QUEUE_PKT
        /* Copy outgoing pkt in the queuing buffer for later transmit and set
           the destination nbr to nbr. */
        if(uip_packetqueue_alloc(&nbr->packethandle, UIP_DS6_NBR_PACKET_LIFETIME) != NULL) {
          memcpy(uip_packetqueue_buf(&nbr->packethandle), UIP_IP_BUF, uip_len);
          uip_packetqueue_set_buflen(&nbr->packethandle, uip_len);
        }
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/
        uip_clear_buf();
        return;
      }
      /* Send in parallel if we are running NUD (nbc state is either STALE,
         DELAY, or PROBE). See RFC 4861, section 7.3.3 on node behavior. */
#if CETIC_6LBR && UIP_CONF_IPV6_RPL
      /* Don't update nbr state if we don't want to perform NUD for WSN */
      if((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_WSN_NUD) == 0 ||
         !uip_ipaddr_prefixcmp(&wsn_net_prefix, &UIP_IP_BUF->destipaddr, 64) ||
         route == NULL)
#endif
      if(nbr->state == NBR_STALE) {
        nbr->state = NBR_DELAY;
        stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME);
        nbr->nscount = 0;
        PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
      }
#endif /* UIP_ND6_SEND_NA */

      tcpip_output(uip_ds6_nbr_get_ll(nbr));

#if UIP_CONF_IPV6_QUEUE_PKT
      /*
       * Send the queued packets from here, may not be 100% perfect though.
       * This happens in a few cases, for example when instead of receiving a
       * NA after sendiong a NS, you receive a NS with SLLAO: the entry moves
       * to STALE, and you must both send a NA and the queued packet.
       */
      if(uip_packetqueue_buflen(&nbr->packethandle) != 0) {
        uip_len = uip_packetqueue_buflen(&nbr->packethandle);
        memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len);
        uip_packetqueue_free(&nbr->packethandle);
        tcpip_output(uip_ds6_nbr_get_ll(nbr));
      }
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/

      uip_clear_buf();
      return;
    }
  }
  /* Multicast IP destination address. */
  tcpip_output(NULL);
  uip_clear_buf();
}
Example #18
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)
{
#if CETIC_6LBR_SMARTBRIDGE
    uip_ds6_route_t * route;
#endif
    uint8_t is_llchange;
    uint8_t is_router;
    uint8_t is_solicited;
    uint8_t is_override;

    PRINTF("Received NA from");
    PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
    PRINTF("to");
    PRINT6ADDR(&UIP_IP_BUF->destipaddr);
    PRINTF("with target address");
    PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NA_BUF->tgtipaddr));
    PRINTF("\n");
    UIP_STAT(++uip_stat.nd6.recv);

    /*
     * booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40, 0x20
     * but it works. Be careful though, do not use tests such as is_router == 1
     */
    is_llchange = 0;
    is_router = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_ROUTER));
    is_solicited =
        ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED));
    is_override =
        ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE));

#if UIP_CONF_IPV6_CHECKS
    if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
            (UIP_ICMP_BUF->icode != 0) ||
            (uip_is_addr_mcast(&UIP_ND6_NA_BUF->tgtipaddr)) ||
            (is_solicited && uip_is_addr_mcast(&UIP_IP_BUF->destipaddr))) {
        PRINTF("NA received is bad\n");
        goto discard;
    }
#endif /*UIP_CONF_IPV6_CHECKS */

    /* Options processing: we handle TLLAO, and must ignore others */
    nd6_opt_offset = UIP_ND6_NA_LEN;
    nd6_opt_llao = NULL;
    while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
#if UIP_CONF_IPV6_CHECKS
        if(UIP_ND6_OPT_HDR_BUF->len == 0) {
            PRINTF("NA received is bad\n");
            goto discard;
        }
#endif /*UIP_CONF_IPV6_CHECKS */
        switch (UIP_ND6_OPT_HDR_BUF->type) {
        case UIP_ND6_OPT_TLLAO:
            nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF;
            break;
        default:
            PRINTF("ND option not supported in NA\n");
            break;
        }
        nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
    }
#if CETIC_6LBR_SMARTBRIDGE
    /* Address Advertisement */
    if ( (nvm_data.mode & CETIC_MODE_SMART_MULTI_BR) != 0 ) {
        if (uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) && uip_is_mcast_group_id_all_nodes(&UIP_IP_BUF->destipaddr)) {
            LOG6LBR_6ADDR(INFO, &UIP_ND6_NA_BUF->tgtipaddr, "Received purge NA for ");
#if CETIC_NODE_INFO
            node_info_rm_by_addr(&UIP_ND6_NA_BUF->tgtipaddr);
#endif
            route = uip_ds6_route_lookup(&UIP_ND6_NA_BUF->tgtipaddr);
            if (route != NULL ) {
                uip_ds6_route_rm(route);
            }
            goto discard;
        }
    }
#endif
    addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr);
    /* Message processing, including TLLAO if any */
    if(addr != NULL) {
#if UIP_ND6_DEF_MAXDADNS > 0
        if(addr->state == ADDR_TENTATIVE) {
            uip_ds6_dad_failed(addr);
        }
#endif /*UIP_ND6_DEF_MAXDADNS > 0 */
        PRINTF("NA received is bad\n");
        goto discard;
    } else {
        uip_lladdr_t *lladdr;
        nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr);
        lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
        if(nbr == NULL) {
            goto discard;
        }
        if(nd6_opt_llao != 0) {
            is_llchange =
                memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], (void *)lladdr,
                       UIP_LLADDR_LEN);
        }
        if(nbr->state == NBR_INCOMPLETE) {
            if(nd6_opt_llao == NULL) {
                goto discard;
            }
            memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
                   UIP_LLADDR_LEN);
            if(is_solicited) {
                nbr->state = NBR_REACHABLE;
                nbr->nscount = 0;

                /* reachable time is stored in ms */
                stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);

            } else {
                nbr->state = NBR_STALE;
            }
            nbr->isrouter = is_router;
        } else {
            if(!is_override && is_llchange) {
                if(nbr->state == NBR_REACHABLE) {
                    nbr->state = NBR_STALE;
                }
                goto discard;
            } else {
                if(is_override || (!is_override && nd6_opt_llao != 0 && !is_llchange)
                        || nd6_opt_llao == 0) {
                    if(nd6_opt_llao != 0) {
                        memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
                               UIP_LLADDR_LEN);
                    }
                    if(is_solicited) {
                        nbr->state = NBR_REACHABLE;
                        /* reachable time is stored in ms */
                        stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
                    } else {
                        if(nd6_opt_llao != 0 && is_llchange) {
                            nbr->state = NBR_STALE;
                        }
                    }
                }
            }
            if(nbr->isrouter && !is_router) {
                defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr);
                if(defrt != NULL) {
                    uip_ds6_defrt_rm(defrt);
                }
            }
            nbr->isrouter = is_router;
        }
    }
#if UIP_CONF_IPV6_QUEUE_PKT
    /* The nbr is now reachable, check if we had buffered a pkt for it */
    /*if(nbr->queue_buf_len != 0) {
      uip_len = nbr->queue_buf_len;
      memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len);
      nbr->queue_buf_len = 0;
      return;
      }*/
    if(uip_packetqueue_buflen(&nbr->packethandle) != 0) {
        uip_len = uip_packetqueue_buflen(&nbr->packethandle);
        memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len);
        uip_packetqueue_free(&nbr->packethandle);
        return;
    }

#endif /*UIP_CONF_IPV6_QUEUE_PKT */

discard:
    uip_clear_buf();
    return;
}
Example #19
0
/*---------------------------------------------------------------------------*/
int
rpl_verify_header(int uip_ext_opt_offset)
{
  rpl_instance_t *instance;
  int down;
  uint16_t sender_rank;
  uint8_t sender_closer;
  uip_ds6_route_t *route;
  rpl_parent_t *sender = NULL;

  if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
    PRINTF("RPL: Hop-by-hop extension header has wrong size\n");
    return 1;
  }

  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
    PRINTF("RPL: Non RPL Hop-by-hop option\n");
    return 1;
  }

  if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
    PRINTF("RPL: Bad header option! (wrong length)\n");
    return 1;
  }

  instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
  if(instance == NULL) {
    PRINTF("RPL: Unknown instance: %u\n",
           UIP_EXT_HDR_OPT_RPL_BUF->instance);
    return 1;
  }

  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
    PRINTF("RPL: Forward error!\n");
    /* We should try to repair it by removing the neighbor that caused
       the packet to be forwareded in the first place. We drop any
       routes that go through the neighbor that sent the packet to
       us. */
    route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
    if(route != NULL) {
      uip_ds6_route_rm(route);
    }
    RPL_STAT(rpl_stats.forward_errors++);
    /* Trigger DAO retransmission */
    rpl_reset_dio_timer(instance);
    /* drop the packet as it is not routable */
    return 1;
  }

  if(!instance->current_dag->joined) {
    PRINTF("RPL: No DAG in the instance\n");
    return 1;
  }

  down = 0;
  if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN) {
    down = 1;
  }

  sender_rank = UIP_HTONS(UIP_EXT_HDR_OPT_RPL_BUF->senderrank);
  sender_closer = sender_rank < instance->current_dag->rank;

  PRINTF("RPL: Packet going %s, sender closer %d (%d < %d)\n", down == 1 ? "down" : "up",
	 sender_closer,
	 sender_rank,
	 instance->current_dag->rank
	 );

  sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER));

  if(sender != NULL && (UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR)) {
    /* A rank error was signalled, attempt to repair it by updating
     * the sender's rank from ext header */
    sender->rank = sender_rank;
    rpl_select_dag(instance, sender);
  }

  if((down && !sender_closer) || (!down && sender_closer)) {
    PRINTF("RPL: Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
	   sender_rank, instance->current_dag->rank,
	   sender_closer);
    /* Attempt to repair the loop by sending a unicast DIO back to the sender
     * so that it gets a fresh update of our rank. */
    if(sender != NULL) {
      instance->unicast_dio_target = sender;
      rpl_schedule_unicast_dio_immediately(instance);
    }
    if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_RANK_ERR) {
      RPL_STAT(rpl_stats.loop_errors++);
      PRINTF("RPL: Rank error signalled in RPL option!\n");
      /* Packet must be dropped and dio trickle timer reset, see RFC6550 - 11.2.2.2 */
      rpl_reset_dio_timer(instance);
      return 1;
    }
    PRINTF("RPL: Single error tolerated\n");
    RPL_STAT(rpl_stats.loop_warnings++);
    UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_RANK_ERR;
    return 0;
  }

  PRINTF("RPL: Rank OK\n");

  return 0;
}