Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
Archivo: tcpip.c Proyecto: 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();
}
Ejemplo n.º 3
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();
}
Ejemplo n.º 4
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;

}