Exemplo n.º 1
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);
        }
    }
}
Exemplo n.º 2
0
uip_ds6_route_t *
rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
              uip_ipaddr_t *next_hop)
{
  uip_ds6_route_t *rep;

  rep = uip_ds6_route_lookup(prefix);
  if(rep == NULL) {
    if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop, 0)) == NULL) {
      PRINTF("RPL: No space for more route entries\n");
      return NULL;
    }
  } else {
    PRINTF("RPL: Updated the next hop for prefix ");
    PRINT6ADDR(prefix);
    PRINTF(" to ");
    PRINT6ADDR(next_hop);
    PRINTF("\n");
    uip_ipaddr_copy(&rep->nexthop, next_hop);
  }
  rep->state.dag = dag;
  rep->state.lifetime = RPL_LIFETIME(dag, dag->default_lifetime);
  rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL;

  PRINTF("RPL: Added a route to ");
  PRINT6ADDR(prefix);
  PRINTF("/%d via ", prefix_len);
  PRINT6ADDR(next_hop);
  PRINTF("\n");

  return rep;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
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_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;
            }
#if TCPIP_CONF_ANNOTATE_TRANSMISSIONS
            if(nexthop != NULL) {
                printf("#L %u 1; red\n", nexthop->u8[sizeof(uip_ipaddr_t) - 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 */
        if((nbr = uip_ds6_nbr_lookup(nexthop)) == 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.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");
            }
#endif /* UIP_ND6_SEND_NA */

            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;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
/*---------------------------------------------------------------------------*/
void
rpl_update_header_empty(void)
{
  rpl_instance_t *instance;
  int uip_ext_opt_offset;
  int last_uip_ext_len;

  last_uip_ext_len = uip_ext_len;
  uip_ext_len = 0;
  uip_ext_opt_offset = 2;

  PRINTF("RPL: Verifying the presence of the RPL header option\n");

  switch(UIP_IP_BUF->proto) {
  case UIP_PROTO_HBHO:
    if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
      PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
      uip_ext_len = last_uip_ext_len;
      return;
    }
    instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
    if(instance == NULL || !instance->used || !instance->current_dag->joined) {
      PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n");
      return;
    }
    break;
  default:
    PRINTF("RPL: No hop-by-hop option found, creating it\n");
    if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
      PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
      uip_ext_len = last_uip_ext_len;
      return;
    }
    set_rpl_opt(uip_ext_opt_offset);
    uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
    return;
  }

  switch(UIP_EXT_HDR_OPT_BUF->type) {
  case UIP_EXT_HDR_OPT_RPL:
    PRINTF("RPL: Updating RPL option\n");
    UIP_EXT_HDR_OPT_RPL_BUF->senderrank = instance->current_dag->rank;

    /* Check the direction of the down flag, as per Section 11.2.2.3,
       which states that if a packet is going down it should in
       general not go back up again. If this happens, a
       RPL_HDR_OPT_FWD_ERR should be flagged. */
    if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
      if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
        UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
        PRINTF("RPL forwarding error\n");
      }
    } else {
      /* Set the down extension flag correctly as described in Section
         11.2 of RFC6550. If the packet progresses along a DAO route,
         the down flag should be set. */
      if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
        /* No route was found, so this packet will go towards the RPL
           root. If so, we should not set the down flag. */
        UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
        PRINTF("RPL option going up\n");
      } else {
        /* A DAO route was found so we set the down flag. */
        UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
        PRINTF("RPL option going down\n");
      }
    }

    uip_ext_len = last_uip_ext_len;
    return;
  default:
    PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
    uip_ext_len = last_uip_ext_len;
    return;
  }
}
Exemplo n.º 7
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_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) {
	if(0){
	/* 
	 * I-D.ietf.6lowpan-nd 5.7: As all prefixes but the link-local prefix are
	 * always assumed to be off-link, multicast-based address resolution between
	 * neighbors is not needed.
	 * In addition, there are neither INCOMPLETE, STALE, DELAY, nor PROBE NCEs 
	 * in 6LoWPAN-ND.
	 */	
		return;
    } else {
    	tcpip_output(&(nbr->lladdr));
      uip_len = 0;
      return;
    }
  }
   
  /*multicast IP destination address */
  tcpip_output(NULL);
  uip_len = 0;
  uip_ext_len = 0;
   
}
Exemplo n.º 8
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;

#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 ");
    PRINT6ADDR(ipaddr);
    PRINTF("\n");
    return NULL;
  }

  /* First make sure that we don't add a route twice. If we find an
     existing route for our destination, we'll just update the old
     one. */
  r = uip_ds6_route_lookup(ipaddr);
  if(r != NULL) {
    PRINTF("uip_ds6_route_add: old route already found, updating this one instead: ");
    PRINT6ADDR(ipaddr);
    PRINTF("\n");
  } else {
    struct uip_ds6_route_neighbor_routes *routes;
    /* If there is no routing entry, create one */

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

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

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

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

    if(r == NULL) {
      PRINTF("uip_ds6_route_add: could not allocate memory for new route to ");
      PRINT6ADDR(ipaddr);
      PRINTF(", dropping it\n");
      return NULL;
    }


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

    PRINTF("uip_ds6_route_add num %d\n", num_routes);
    r->routes = routes;
  }

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

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

  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;
}
Exemplo n.º 9
0
/*---------------------------------------------------------------------------*/
int
rpl_update_header_empty(void)
{
  rpl_instance_t *instance;
  int uip_ext_opt_offset;
  int last_uip_ext_len;
  rpl_parent_t *parent;

  last_uip_ext_len = uip_ext_len;
  uip_ext_len = 0;
  uip_ext_opt_offset = 2;

  PRINTF("RPL: Verifying the presence of the RPL header option\n");

  switch(UIP_IP_BUF->proto) {
  case UIP_PROTO_HBHO:
    if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
      PRINTF("RPL: Hop-by-hop extension header has wrong size\n");
      uip_ext_len = last_uip_ext_len;
      return 0;
    }
    if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
      PRINTF("RPL: Non RPL Hop-by-hop option support not implemented\n");
      uip_ext_len = last_uip_ext_len;
      return 0;
    }
    if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
      PRINTF("RPL: RPL Hop-by-hop option has wrong length\n");
      uip_ext_len = last_uip_ext_len;
      return 0;
    }
    instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
    if(instance == NULL || !instance->used || !instance->current_dag->joined) {
      PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n");
      return 0;
    }
    break;
  default:
#if RPL_INSERT_HBH_OPTION
    PRINTF("RPL: No hop-by-hop option found, creating it\n");
    if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE - UIP_LLH_LEN) {
      PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
      uip_ext_len = last_uip_ext_len;
      return 0;
    }
    set_rpl_opt(uip_ext_opt_offset);
    uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
#endif
    return 0;
  }

  switch(UIP_EXT_HDR_OPT_BUF->type) {
  case UIP_EXT_HDR_OPT_RPL:
    PRINTF("RPL: Updating RPL option\n");
    UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);

    /* Check the direction of the down flag, as per Section 11.2.2.3,
       which states that if a packet is going down it should in
       general not go back up again. If this happens, a
       RPL_HDR_OPT_FWD_ERR should be flagged. */
    if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
      if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
        UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
        PRINTF("RPL forwarding error\n");
        /* We should send back the packet to the originating parent,
           but it is not feasible yet, so we send a No-Path DAO instead */
        PRINTF("RPL generate No-Path DAO\n");
        parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
        if(parent != NULL) {
          dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
        }
        /* Drop packet */
        return 1;
      }
    } else {
      /* Set the down extension flag correctly as described in Section
         11.2 of RFC6550. If the packet progresses along a DAO route,
         the down flag should be set. */
      if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
        /* No route was found, so this packet will go towards the RPL
           root. If so, we should not set the down flag. */
        UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
        PRINTF("RPL option going up\n");
      } else {
        /* A DAO route was found so we set the down flag. */
        UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
        PRINTF("RPL option going down\n");
      }
    }

    uip_ext_len = last_uip_ext_len;
    return 0;
  default:
    PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
    uip_ext_len = last_uip_ext_len;
    return 0;
  }
}
Exemplo n.º 10
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();
}
Exemplo n.º 11
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;
}
Exemplo n.º 12
0
static void
ns_input(void)
{
    uint8_t flags;
#if CETIC_6LBR_SMARTBRIDGE
    uip_ds6_route_t * route;
#endif
    uip_ipaddr_t tgtipaddr;

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

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

    /* Options processing */
    nd6_opt_llao = NULL;
    nd6_opt_offset = UIP_ND6_NS_LEN;
    while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
#if UIP_CONF_IPV6_CHECKS
        if(UIP_ND6_OPT_HDR_BUF->len == 0) {
            PRINTF("NS received is bad\n");
            goto discard;
        }
#endif /* UIP_CONF_IPV6_CHECKS */
        switch (UIP_ND6_OPT_HDR_BUF->type) {
        case UIP_ND6_OPT_SLLAO:
            nd6_opt_llao = &uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset];
#if UIP_CONF_IPV6_CHECKS
            /* There must be NO option in a DAD NS */
            if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
                PRINTF("NS received is bad\n");
                goto discard;
            } else {
#endif /*UIP_CONF_IPV6_CHECKS */
                nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
                if(nbr == NULL) {
                    /* Copy link address to a uip_lladdr_t first
                     * to ensure the second argument to uip_ds6_nbr_add is word-aligned */
                    uip_lladdr_t lladdr;
                    memcpy(&lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN);
                    uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr, 0, NBR_STALE);
                } else {
                    uip_lladdr_t *lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
                    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;
                    } else {
                        if(nbr->state == NBR_INCOMPLETE) {
                            nbr->state = NBR_STALE;
                        }
                    }
                }
#if UIP_CONF_IPV6_CHECKS
            }
#endif /*UIP_CONF_IPV6_CHECKS */
            break;
        default:
            PRINTF("ND option not supported in NS");
            break;
        }
        nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
    }

    memcpy(&tgtipaddr, &UIP_ND6_NS_BUF->tgtipaddr, sizeof(tgtipaddr));
    addr = uip_ds6_addr_lookup(&tgtipaddr);
#if CETIC_6LBR_SMARTBRIDGE
    //ND Proxy implementation
    if ( addr == NULL ) {
        if ( (route = uip_ds6_route_lookup(&tgtipaddr)) != NULL ) {
            if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
                /* DAD CASE */
                uip_create_linklocal_allnodes_mcast(&tgtipaddr);
                uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tgtipaddr);
                flags = UIP_ND6_NA_FLAG_OVERRIDE;
                goto create_na;
            } else {
                uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
                uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tgtipaddr);
                flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
                goto create_na;
            }
        }
    }
#endif
    if(addr != NULL) {
#if UIP_ND6_DEF_MAXDADNS > 0
        if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
            /* DAD CASE */
#if UIP_CONF_IPV6_CHECKS
            if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
                PRINTF("NS received is bad\n");
                goto discard;
            }
#endif /* UIP_CONF_IPV6_CHECKS */
            if(addr->state != ADDR_TENTATIVE) {
                uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr);
                uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
                flags = UIP_ND6_NA_FLAG_OVERRIDE;
                goto create_na;
            } else {
                /** \todo if I sent a NS before him, I win */
                uip_ds6_dad_failed(addr);
                goto discard;
            }
#else /* UIP_ND6_DEF_MAXDADNS > 0 */
        if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
            /* DAD CASE */
            goto discard;
#endif /* UIP_ND6_DEF_MAXDADNS > 0 */
        }
#if UIP_CONF_IPV6_CHECKS
        if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) {
            /**
             * \NOTE do we do something here? we both are using the same address.
             * If we are doing dad, we could cancel it, though we should receive a
             * NA in response of DAD NS we sent, hence DAD will fail anyway. If we
             * were not doing DAD, it means there is a duplicate in the network!
             */
            PRINTF("NS received is bad\n");
            goto discard;
        }
#endif /*UIP_CONF_IPV6_CHECKS */

        /* Address resolution case */
        if(uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
            uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
            uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tgtipaddr);
            flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
            goto create_na;
        }

        /* NUD CASE */
        if(uip_ds6_addr_lookup(&UIP_IP_BUF->destipaddr) == addr) {
            uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
            uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tgtipaddr);
            flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
            goto create_na;
        } else {
#if UIP_CONF_IPV6_CHECKS
            PRINTF("NS received is bad\n");
            goto discard;
#endif /* UIP_CONF_IPV6_CHECKS */
        }
    } else {
        goto discard;
    }


create_na:
    /* If the node is a router it should set R flag in NAs */
#if UIP_CONF_ROUTER
    flags = flags | UIP_ND6_NA_FLAG_ROUTER;
#endif
    uip_ext_len = 0;
    UIP_IP_BUF->vtc = 0x60;
    UIP_IP_BUF->tcflow = 0;
    UIP_IP_BUF->flow = 0;
    UIP_IP_BUF->len[0] = 0;       /* length will not be more than 255 */
    UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN;
    UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
    UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;

    UIP_ICMP_BUF->type = ICMP6_NA;
    UIP_ICMP_BUF->icode = 0;

    UIP_ND6_NA_BUF->flagsreserved = flags;
    memcpy(&UIP_ND6_NA_BUF->tgtipaddr, &tgtipaddr, sizeof(uip_ipaddr_t));

    create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN],
                UIP_ND6_OPT_TLLAO);

    UIP_ICMP_BUF->icmpchksum = 0;
    UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();

    uip_len =
        UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN;

    UIP_STAT(++uip_stat.nd6.sent);
    PRINTF("Sending NA to ");
    PRINT6ADDR(&UIP_IP_BUF->destipaddr);
    PRINTF(" from ");
    PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
    PRINTF(" with target address ");
    PRINT6ADDR(&UIP_ND6_NA_BUF->tgtipaddr);
    PRINTF("\n");
    return;

discard:
    uip_clear_buf();
    return;
}
#endif /* UIP_ND6_SEND_NA */


/*------------------------------------------------------------------*/
void
uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
{
    uip_ext_len = 0;
    UIP_IP_BUF->vtc = 0x60;
    UIP_IP_BUF->tcflow = 0;
    UIP_IP_BUF->flow = 0;
    UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
    UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;

    if(dest == NULL) {
        uip_create_solicited_node(tgt, &UIP_IP_BUF->destipaddr);
    } else {
        uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest);
    }
    UIP_ICMP_BUF->type = ICMP6_NS;
    UIP_ICMP_BUF->icode = 0;
    UIP_ND6_NS_BUF->reserved = 0;
    uip_ipaddr_copy((uip_ipaddr_t *) &UIP_ND6_NS_BUF->tgtipaddr, tgt);
    UIP_IP_BUF->len[0] = 0;       /* length will not be more than 255 */
    /*
     * check if we add a SLLAO option: for DAD, MUST NOT, for NUD, MAY
     * (here yes), for Address resolution , MUST
     */
    if(!(uip_ds6_is_my_addr(tgt))) {
        if(src != NULL) {
            uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, src);
        } else {
            uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
        }
        if (uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
            PRINTF("Dropping NS due to no suitable source address\n");
            uip_clear_buf();
            return;
        }
        UIP_IP_BUF->len[1] =
            UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN;

        create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NS_LEN],
                    UIP_ND6_OPT_SLLAO);

        uip_len =
            UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN;
    } else {
        uip_create_unspecified(&UIP_IP_BUF->srcipaddr);
        UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NS_LEN;
        uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN;
    }

    UIP_ICMP_BUF->icmpchksum = 0;
    UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();

    UIP_STAT(++uip_stat.nd6.sent);
    PRINTF("Sending NS to");
    PRINT6ADDR(&UIP_IP_BUF->destipaddr);
    PRINTF("from");
    PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
    PRINTF("with target address");
    PRINT6ADDR(tgt);
    PRINTF("\n");
    return;
}
Exemplo n.º 13
0
static void
receiver(struct simple_udp_connection *c,
         const uip_ipaddr_t *sender_addr,
         uint16_t sender_port,
         const uip_ipaddr_t *receiver_addr,
         uint16_t receiver_port,
         const uint8_t *data,
         uint16_t datalen)
{
  int i,num_neigh;
  uint8_t *ptr;
  struct ip_list_struct *s;
  uip_ipaddr_t *addr;
  uip_ds6_addr_t * nh;

  // Check if this is the first time I get a message from this node
  if( !list_exist(sender_addr) ){
     // First message from this neighbour
     s = memb_alloc(&ip_mem);
     uip_ipaddr_copy(&s->ip, sender_addr);
     list_add(ip_list, s);
     printf("Neighbour added \n"); 
  }

  printf("Neighbour information received from ");
  uip_debug_ipaddr_print(sender_addr);
  printf("\n");
 
  num_neigh = datalen/sizeof(uip_ipaddr_t);
  ptr=data;
  printf("2nd hop neighbour list is: \n");
  for(i=0; i < num_neigh; i++){
     ptr += i*sizeof(uip_ipaddr_t);
     addr = ptr;
     uip_debug_ipaddr_print(addr);

     // Add the 2nd neighbors in the routing table

     if(uip_ds6_is_my_addr(addr))
        continue; // Hey this is myself

     if( list_exist(addr) )
	continue; // Hey you're a 1st hop neighbour

     // I can add the entry in the routing table
     uip_ds6_route_add(addr, 128, sender_addr);
     printf("\nAdded route\n");

     // Verify!
     nh = uip_ds6_route_lookup(addr);
     if( nh != NULL ){
        printf("TO=");
        uip_debug_ipaddr_print(addr);
        printf(" NEXTHOP=");
        uip_debug_ipaddr_print(nh); 	
     }
  }
  printf("\n");



}
Exemplo n.º 14
0
Arquivo: tcpip.c Projeto: 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();
}
Exemplo n.º 15
0
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;

}
Exemplo n.º 16
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;
}
Exemplo n.º 17
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;
}
Exemplo n.º 18
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;
}