Beispiel #1
0
/**
 * \brief Get Neighbor_AO by IP Address and send an ICMPv6 Echo Request
 * 
 * \param destination ip address
 */
void uip_icmp6_echo_request_output(uip_ipaddr_t * dst)
{
	Neighbor_AO * neighbor;
	neighbor = uip_nd6_nbrcache_lookup(dst);
	if (NULL != neighbor)
		uip_icmp6_echo_request_output_to_neighbor(neighbor);
}
Beispiel #2
0
/**
 * \brief handle incoming echo request
 *
 * \param the incoming NewDataEvent
 */
void uip_icmp6_echo_request_input(NewDataEvent * e)
{
	struct uip_icmp_hdr * icmp_hdr;
	struct uip_tcpip_hdr * tcpip_hdr;
	Neighbor_AO * neighbor;
	static QEvent const pr_sig = { PACKET_RECEIVED_SIG};
	static QEvent const ps_sig = { PACKET_SENT_SIG};
	tcpip_hdr = ( struct uip_tcpip_hdr *) &e->buf[UIP_LLH_LEN];
	icmp_hdr = (struct uip_icmp_hdr *)&e->buf[uip_l2_l3_hdr_len];
	
	neighbor = uip_nd6_nbrcache_lookup(&tcpip_hdr->srcipaddr);
	if (NULL != neighbor)
		QActive_postFIFO((QActive *)neighbor, &pr_sig);
	
	switch_eth_addr(e);
	
	memcpy(&tcpip_hdr->destipaddr, &tcpip_hdr->srcipaddr, sizeof(uip_ipaddr_t));
	memcpy(&tcpip_hdr->srcipaddr, &uip_hostaddr, sizeof(uip_ipaddr_t));
	icmp_hdr->type = ICMP6_ECHO_REPLY;
  icmp_hdr->icode = 0;
  icmp_hdr->icmpchksum = 0;
  icmp_hdr->icmpchksum = ~upper_layer_chksum6((unsigned char *) &e->buf);
	e->super.sig = SEND_DATA_SIG;
	QF_publish((QEvent *) e);
	QActive_postFIFO((QActive *)neighbor, &ps_sig);
}
Beispiel #3
0
/**
 * \brief Reply incoming ICMPv6 Echo Request with an Echo Reply
 * 
 * \param incoming NewDataEvent
 */
void uip_icmp6_echo_reply_input(NewDataEvent * e)
{
	Neighbor_AO * neighbor;
	struct uip_icmpip_hdr * icmpip_hdr;
	static QEvent const icmpr_sig = { ICMPV6_ECHO_REPLY_SIG};
	icmpip_hdr = ( struct uip_icmpip_hdr *) &e->buf[UIP_LLH_LEN];
	
	neighbor = uip_nd6_nbrcache_lookup(&icmpip_hdr->srcipaddr);
	if (NULL != neighbor)
		QActive_postFIFO((QActive *)neighbor, &icmpr_sig);
}
Beispiel #4
0
/*------------------------------------------------------------------*/
void 
uip_nd6_io_ns_input(void)
{
  PRINTF("Received NS from");
  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
  PRINTF("to");
  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
  PRINTF("with target address");
  PRINT6ADDR((uip_ipaddr_t *)(&UIP_ND6_NS_BUF->tgtipaddr));
  PRINTF("\n");
  UIP_STAT(++uip_stat.nd6.recv);
 
  u8_t flags;
 
#if UIP_CONF_IPV6_CHECKS
  if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
     (uip_is_addr_mcast(&UIP_ND6_NS_BUF->tgtipaddr)) ||
     (UIP_ICMP_BUF->icode != 0))
  {
    goto badpkt;
  }
#endif /* UIP_CONF_IPV6_CHECKS */ 
  
  /* Options reading: we handle only SLLAO for now */
  nd6_opt_llao = NULL;
  nd6_opt_offset = UIP_ND6_NS_LEN;
  while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
#if UIP_CONF_IPV6_CHECKS
    if(UIP_ND6_OPT_HDR_BUF->len == 0) {
      goto badpkt;
    }
#endif /* UIP_CONF_IPV6_CHECKS */ 
    switch(UIP_ND6_OPT_HDR_BUF->type) {
      case UIP_ND6_OPT_SLLAO:
        nd6_opt_llao = (struct uip_nd6_opt_llao *)UIP_ND6_OPT_HDR_BUF;
        break;
      default:
        UIP_LOG("ND option not supported in NS");
        break;
    }
    nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3);
  }

  /* Options processing: only SLLAO */
  if(nd6_opt_llao != NULL) {
#if UIP_CONF_IPV6_CHECKS
    /* There must be NO option in a DAD NS */
    if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
      goto badpkt;
    } else {
#endif /*UIP_CONF_IPV6_CHECKS*/
      neighbor = uip_nd6_nbrcache_lookup(&UIP_IP_BUF->srcipaddr);
      if(neighbor == NULL) {
        /* we need to add the neighbor*/
        uip_nd6_nbrcache_add(&UIP_IP_BUF->srcipaddr,
                             &nd6_opt_llao->addr, 0, STALE);
      } else {
        /* If LL address changed, set neighbor state to stale */
        if(memcmp(&nd6_opt_llao->addr, &neighbor->lladdr, UIP_LLADDR_LEN) != 0) {
          memcpy(&neighbor->lladdr, &nd6_opt_llao->addr, UIP_LLADDR_LEN);
          neighbor->state = STALE;
        } else {
          /* If neighbor state is INCOMPLETE, set to STALE */
          if(neighbor->state == INCOMPLETE) {
            neighbor->state = STALE;
          }
        }
      }
#if UIP_CONF_IPV6_CHECKS
    }   
#endif /*UIP_CONF_IPV6_CHECKS*/
  }

  /* 
   * Rest of NS processing: Depends on the purpose of the NS: NUD or DAD or
   * Address Resolution 
   */
  /** \note we use ifaddr to remember the target address */
  ifaddr = uip_netif_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr, 128, 0);
  if(ifaddr != NULL) {
    if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)){
      /* DAD CASE */
#if UIP_CONF_IPV6_CHECKS 
      /* Dst address must be solicited node mcast address */
      if(!uip_netif_is_addr_my_solicited(&UIP_IP_BUF->destipaddr)){
        goto badpkt;
      }
#endif /* UIP_CONF_IPV6_CHECKS */ 
      /*
       * If my address is not tentative, then send a NA to all nodes with
       * TLLAO flags are: override = yes.
       */
        if(ifaddr->state!=TENTATIVE) {  
        /* 
         * we need to send a NA, we set the src, dest, flags. tgt remains the
         * same and the rest is done at "create_na" 
         */
        uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr);
        uip_netif_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
        flags = UIP_ND6_NA_FLAG_OVERRIDE;
        goto create_na;
      } else {
        /** \todo if I sent a NS before him, I win */
        uip_netif_dad_failed(&UIP_ND6_NS_BUF->tgtipaddr);
        goto discard;
      }
    }
  

#if UIP_CONF_IPV6_CHECKS
    /* Duplicate check */
    if(uip_netif_is_addr_my_unicast(&UIP_IP_BUF->srcipaddr)) {
      /**
       * \NOTE do we do something here? we both are using the same address.
       * If we are doing dad, we could cancel it, though we should receive a
       * NA in response of DAD NS we sent, hence DAD will fail anyway. If we
       * were not doing DAD, it means there is a duplicate in the network!
       */
      goto badpkt;
    }
#endif /*UIP_CONF_IPV6_CHECKS*/

    /* Address resolution case */  
    if(uip_netif_is_addr_my_solicited(&UIP_IP_BUF->destipaddr)){
      /*   
       * we need to send a NA, we set the src, dest, flags. The rest is
       * set at the "create_na" label.
       */
      uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
      uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr);
      flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
      goto create_na;
    } 

    /* 
     * NUD CASE. at this point the packet must be for us! we check this, 
     * and at the same time if target == dest
     */
    if(uip_netif_addr_lookup(&UIP_IP_BUF->destipaddr, 128, 0) == ifaddr){
      /*   
       * we need to send a NA, we set the src, dest, flags. The rest is set
       * at the "create_na" label.
       */
      uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
      uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr);
      flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE;
      goto create_na;
    } else {
#if UIP_CONF_IPV6_CHECKS
      goto badpkt;
#endif /* UIP_CONF_IPV6_CHECKS */ 
    }    
  } else {
    goto discard;
  }
  

 create_na:
  /* 
   * Fill the part of the NA which is common to all NAs. If the NS contained
   * extension headers, we must set the target address properly
   */
  uip_ext_len = 0; 
  
  /* IP header */
  UIP_IP_BUF->vtc = 0x60;
  UIP_IP_BUF->tcflow = 0;
  UIP_IP_BUF->flow = 0;
  UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */
  UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN;
  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
  UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;

  /* ICMP header */
  UIP_ICMP_BUF->type = ICMP6_NA;
  UIP_ICMP_BUF->icode = 0;

  /* NA static part */
  UIP_ND6_NA_BUF->flagsreserved = flags;
  memcpy(&UIP_ND6_NA_BUF->tgtipaddr, &ifaddr->ipaddr, sizeof(uip_ipaddr_t));

  /* NA option: TLLAO. note that length field is in unit of 8 bytes */
  uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN;
  nd6_opt_llao = (struct uip_nd6_opt_llao *)&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN];
  nd6_opt_llao->type = UIP_ND6_OPT_TLLAO;
  nd6_opt_llao->len = UIP_ND6_OPT_LLAO_LEN >> 3;
  memcpy(&(nd6_opt_llao->addr), &uip_lladdr, UIP_LLADDR_LEN);
  /* padding if needed */
  memset((void *)(&nd6_opt_llao->addr) + UIP_LLADDR_LEN, 0, UIP_ND6_OPT_LLAO_LEN - 2 - UIP_LLADDR_LEN);

  /*ICMP checksum*/
  UIP_ICMP_BUF->icmpchksum = 0;
  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); 


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

#if UIP_CONF_IPV6_CHECKS
 badpkt:
  UIP_STAT(++uip_stat.nd6.drop);
  UIP_LOG("NS received is bad"); 
#endif /* UIP_CONF_IPV6_CHECKS */
  
 discard:
  uip_len = 0;
  return;
}
Beispiel #5
0
void
tcpip_ipv6_output(void)
{
  struct uip_nd6_neighbor *nbc = NULL;
  struct uip_nd6_defrouter *dr = NULL;
  
  if(uip_len == 0)
    return;

  if(uip_len > UIP_LINK_MTU){
    UIP_LOG("tcpip_ipv6_output: Packet to big");
    uip_len = 0;
    return;
  }
  if(uip_is_addr_unspecified(&UIP_IP_BUF->destipaddr)){
    UIP_LOG("tcpip_ipv6_output: Destination address unspecified");
    uip_len = 0;
    return;
  }
  if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
    /*If destination is on link */
    nbc = NULL;
    if(uip_nd6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
      nbc = uip_nd6_nbrcache_lookup(&UIP_IP_BUF->destipaddr);
    } else {
#if UIP_CONF_ROUTER
      /*destination is not on link*/
      uip_ipaddr_t ipaddr;
      uip_ipaddr_t *next_hop;

      /* Try to find the next hop address in the local routing table. */
      next_hop = uip_router != NULL ?
        uip_router->lookup(&UIP_IP_BUF->destipaddr, &ipaddr) : NULL;
      if(next_hop != NULL) {
        /* Look for the next hop of the route in the neighbor cache.
           Add a cache entry if we can't find it. */
        nbc = uip_nd6_nbrcache_lookup(next_hop);
        if(nbc == NULL) {
          nbc = uip_nd6_nbrcache_add(next_hop, NULL, 1, NO_STATE);
        }
      } else {
#endif /* UIP_CONF_ROUTER */
        /* No route found, check if a default router exists and use it then. */
        dr = uip_nd6_choose_defrouter();
        if(dr != NULL){
          nbc = dr->nb;
        } else {
          /* shall we send a icmp error message destination unreachable ?*/
          UIP_LOG("tcpip_ipv6_output: Destination off-link but no router");
          uip_len = 0;
          return;
        }
#if UIP_CONF_ROUTER
      }
#endif /* UIP_CONF_ROUTER */
    }
    /* there are two cases where the entry logically does not exist:
     * 1 it really does not exist. 2 it is in the NO_STATE state */
    if (nbc == NULL || nbc->state == NO_STATE) {
      if (nbc == NULL) {
        /* create neighbor cache entry, original packet is replaced by NS*/
        nbc = uip_nd6_nbrcache_add(&UIP_IP_BUF->destipaddr, NULL, 0, INCOMPLETE);
      } else {
        nbc->state = INCOMPLETE;
      }
#if UIP_CONF_IPV6_QUEUE_PKT
      /* copy outgoing pkt in the queuing buffer for later transmmit */
      memcpy(nbc->queue_buf, UIP_IP_BUF, uip_len);
      nbc->queue_buf_len = uip_len;
#endif
      /* RFC4861, 7.2.2:
       * "If the source address of the packet prompting the solicitation is the
       * same as one of the addresses assigned to the outgoing interface, that
       * address SHOULD be placed in the IP Source Address of the outgoing
       * solicitation.  Otherwise, any one of the addresses assigned to the
       * interface should be used."*/
      if(uip_netif_is_addr_my_unicast(&UIP_IP_BUF->srcipaddr)){
        uip_nd6_io_ns_output(&UIP_IP_BUF->srcipaddr, NULL, &nbc->ipaddr);
      } else {
        uip_nd6_io_ns_output(NULL, NULL, &nbc->ipaddr);
      }

      stimer_set(&(nbc->last_send),
                uip_netif_physical_if.retrans_timer / 1000);
      nbc->count_send = 1;
    } else {
      if (nbc->state == INCOMPLETE){
        PRINTF("tcpip_ipv6_output: neighbor cache entry incomplete\n");
#if UIP_CONF_IPV6_QUEUE_PKT
        /* copy outgoing pkt in the queuing buffer for later transmmit and set
           the destination neighbor to nbc */
        memcpy(nbc->queue_buf, UIP_IP_BUF, uip_len);
        nbc->queue_buf_len = uip_len;
        uip_len = 0;
#endif /*UIP_CONF_IPV6_QUEUE_PKT*/
        return;
      }
      /* if running NUD (nbc->state == STALE, DELAY, or PROBE ) keep
         sending in parallel see rfc 4861 Node behavior in section 7.7.3*/
	 
      if (nbc->state == STALE){
        nbc->state = DELAY;
        stimer_set(&(nbc->reachable),
                  UIP_ND6_DELAY_FIRST_PROBE_TIME);
        PRINTF("tcpip_ipv6_output: neighbor cache entry stale moving to delay\n");
      }
      
      stimer_set(&(nbc->last_send),
                uip_netif_physical_if.retrans_timer / 1000);
      
      tcpip_output(&(nbc->lladdr));


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

      uip_len = 0;
      return;
    }
  }
   
  /*multicast IP destination address */
  tcpip_output(NULL);
  uip_len = 0;
  uip_ext_len = 0;
   
}