Esempio n. 1
0
static inline FAR struct tcp_conn_s *
  tcp_ipv6_active(FAR struct net_driver_s *dev, FAR struct tcp_hdr_s *tcp)
{
  FAR struct ipv6_hdr_s *ip = IPv6BUF;
  FAR struct tcp_conn_s *conn;
  net_ipv6addr_t *srcipaddr;
#ifdef CONFIG_NETDEV_MULTINIC
  net_ipv6addr_t *destipaddr;
#endif

  conn       = (FAR struct tcp_conn_s *)g_active_tcp_connections.head;
  srcipaddr  = (net_ipv6addr_t *)ip->srcipaddr;
#ifdef CONFIG_NETDEV_MULTINIC
  destipaddr = (net_ipv6addr_t *)ip->destipaddr;
#endif

  while (conn)
    {
      /* Find an open connection matching the TCP input. The following
       * checks are performed:
       *
       * - The local port number is checked against the destination port
       *   number in the received packet.
       * - The remote port number is checked if the connection is bound
       *   to a remote port.
       * - If multiple network interfaces are supported, then the local
       *   IP address is available and we will insist that the
       *   destination IP matches the bound address. If a socket is
       *   bound to INADDRY_ANY, then it should receive all packets
       *   directed to the port.
       * - Finally, if the connection is bound to a remote IP address,
       *   the source IP address of the packet is checked.
       *
       * If all of the above are true then the newly received TCP packet
       * is destined for this TCP connection.
       */

      if (conn->tcpstateflags != TCP_CLOSED &&
          tcp->destport == conn->lport &&
          tcp->srcport  == conn->rport &&
#ifdef CONFIG_NETDEV_MULTINIC
          (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_allzeroaddr) ||
           net_ipv6addr_cmp(*destipaddr, conn->u.ipv6.laddr)) &&
#endif
          net_ipv6addr_cmp(*srcipaddr, conn->u.ipv6.raddr))
        {
          /* Matching connection found.. break out of the loop and return a
           * reference to it.
           */

          break;
        }

      /* Look at the next active connection */

      conn = (FAR struct tcp_conn_s *)conn->node.flink;
    }

  return conn;
}
Esempio n. 2
0
static bool lib_lo_ipv6match(FAR const void *addr, socklen_t len, int type)
{
  FAR struct in_addr6 *ipv6addr;

  if (type == AF_INE6T && len >= sizeof(struct in_addr6))
    {
      ipv6addr = (FAR struct in_addr6 *)addr;
      return net_ipv6addr_cmp(ipv6addr->sin6_addr.s6_addr16, g_lo_ipv6addr);
    }

  return false;
}
Esempio n. 3
0
void neighbor_add(FAR net_ipv6addr_t ipaddr, FAR struct neighbor_addr_s *addr)
{
  uint8_t oldest_time;
  int     oldest_ndx;
  int     i;

  ninfo("Add neighbor: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
        ntohs(ipaddr[0]), ntohs(ipaddr[1]), ntohs(ipaddr[2]),
        ntohs(ipaddr[3]), ntohs(ipaddr[4]), ntohs(ipaddr[5]),
        ntohs(ipaddr[6]), ntohs(ipaddr[7]));
  ninfo("  at: %02x:%02x:%02x:%02x:%02x:%02x\n",
        addr->na_addr.ether_addr_octet[0],
        addr->na_addr.ether_addr_octet[1],
        addr->na_addr.ether_addr_octet[2],
        addr->na_addr.ether_addr_octet[3],
        addr->na_addr.ether_addr_octet[4],
        addr->na_addr.ether_addr_octet[5]);

  /* Find the first unused entry or the oldest used entry. */

  oldest_time = 0;
  oldest_ndx  = 0;

  for (i = 0; i < CONFIG_NET_IPv6_NCONF_ENTRIES; ++i)
    {
      if (g_neighbors[i].ne_time == NEIGHBOR_MAXTIME)
        {
          oldest_ndx = i;
          break;
        }

      if (net_ipv6addr_cmp(g_neighbors[i].ne_ipaddr, ipaddr))
        {
          oldest_ndx = i;
          break;
        }

      if (g_neighbors[i].ne_time > oldest_time)
        {
          oldest_ndx = i;
          oldest_time = g_neighbors[i].ne_time;
        }
    }

  /* Use the oldest or first free entry (either pointed to by the
   * "oldest_ndx" variable).
   */

  g_neighbors[oldest_ndx].ne_time = 0;
  net_ipv6addr_copy(g_neighbors[oldest_ndx].ne_ipaddr, ipaddr);
  memcpy(&g_neighbors[oldest_ndx].ne_addr, addr, sizeof(struct neighbor_addr_s));
}
Esempio n. 4
0
static inline FAR struct tcp_conn_s *
tcp_ipv6_listener(const net_ipv6addr_t ipaddr, uint16_t portno)
{
  FAR struct tcp_conn_s *conn;
  int i;

  /* Check if this port number is in use by any active UIP TCP connection */

  for (i = 0; i < CONFIG_NET_TCP_CONNS; i++)
    {
      conn = &g_tcp_connections[i];

      /* Check if this connection is open and the local port assignment
       * matches the requested port number.
       */

      if (conn->tcpstateflags != TCP_CLOSED && conn->lport == portno)
        {
          /* If there are multiple interface devices, then the local IP
           * address of the connection must also match.  INADDR_ANY is a
           * special case:  There can only be instance of a port number
           * with INADDR_ANY.
           */

          if (net_ipv6addr_cmp(conn->u.ipv6.laddr, ipaddr) ||
              net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_allzeroaddr))
            {
              /* The port number is in use, return the connection */

              return conn;
            }
        }
    }

  return NULL;
}
Esempio n. 5
0
static int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn,
                                const net_ipv6addr_t addr)
{
#ifdef CONFIG_NETDEV_MULTINIC
  /* Do nothing if a device is already bound to the connection */

  if (conn->dev != NULL)
    {
      return OK;
    }

  /* Return success without using device notification if the locally bound
   * address is IN6ADDR_ANY.  In this case, there may be multiple devices
   * that can provide data so the exceptional events from any particular
   * device are not important.
   */

  if (net_ipv6addr_cmp(addr, g_ipv6_allzeroaddr))
    {
      return OK;
    }

  /* There are multiple network devices.  We need to select the device that
   * is going to route the TCP packet based on the provided IP address.
   */

  conn->dev = netdev_findby_ipv6addr(addr, addr);

  /* Return success if we found the device */

  return conn->dev != NULL ? OK : -ENETUNREACH;
#else
  /* There is only a single network device... the one at the head of the
   * g_netdevices list.
   */

  return (g_netdevices != NULL) ? OK : -ENETUNREACH;
#endif

}
Esempio n. 6
0
void icmpv6_notify(net_ipv6addr_t ipaddr)
{
  FAR struct icmpv6_notify_s *curr;

  /* Find an entry with the matching IP address in the list of waiters */

  for (curr = g_icmpv6_waiters; curr; curr = curr->nt_flink)
    {
      /* Does this entry match?  If the result is okay, then we have
       * already notified this waiter and it has not yet taken the
       * entry from the list.
       */

      if (curr->nt_result != OK && net_ipv6addr_cmp(curr->nt_ipaddr, ipaddr))
        {
          /* Yes.. Signal the waiting, returning success */

          curr->nt_result = OK;
          nxsem_post(&curr->nt_sem);
          break;
        }
    }
}
Esempio n. 7
0
static int net_match_ipv6(FAR struct net_route_ipv6_s *route, FAR void *arg)
{
  FAR struct route_match_ipv6_s *match = (FAR struct route_match_ipv6_s *)arg;

  /* To match, the masked target address must be the same, and the masks
   * must be the same.
   */

  if (net_ipv6addr_maskcmp(route->target, match->target, match->netmask) &&
      net_ipv6addr_cmp(route->netmask, match->netmask))
    {
      /* They match.. Remove the entry from the routing table */

      if (match->prev)
        {
          (void)sq_remafter((FAR sq_entry_t *)match->prev,
                            (FAR sq_queue_t *)&g_routes_ipv6);
        }
      else
        {
          (void)sq_remfirst((FAR sq_queue_t *)&g_routes_ipv6);
        }

      /* And free the routing table entry by adding it to the free list */

      net_freeroute_ipv6(route);

      /* Return a non-zero value to terminate the traversal */

      return 1;
    }

  /* Next time we are here, this will be the previous entry */

  match->prev = route;
  return 0;
}
Esempio n. 8
0
static int net_match_ipv6(FAR struct net_route_ipv6_s *route, FAR void *arg)
{
  FAR struct route_match_ipv6_s *match = (FAR struct route_match_ipv6_s *)arg;

  /* To match, the masked target address must be the same, and the masks
   * must be the same.
   */

  net_ipv6_dumproute("Comparing", route);
  ninfo("With:\n");
  ninfo("  target:  %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
        htons(match->target[0]),  htons(match->target[1]),
        htons(match->target[2]),  htons(match->target[3]),
        htons(match->target[4]),  htons(match->target[5]),
        htons(match->target[6]),  htons(match->target[7]));
  ninfo("  netmask: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
        htons(match->netmask[0]), htons(match->netmask[1]),
        htons(match->netmask[2]), htons(match->netmask[3]),
        htons(match->netmask[4]), htons(match->netmask[5]),
        htons(match->netmask[6]), htons(match->netmask[7]));

  if (net_ipv6addr_maskcmp(route->target, match->target, match->netmask) &&
      net_ipv6addr_cmp(route->netmask, match->netmask))
    {
      /* They match.. a non-zero value to terminate the traversal.  The last
       * value of index is the index to the matching entry.
       */

      return 1;
    }

  /* Next time we are here, this will be the routing table index */

  match->index++;
  return 0;
}
Esempio n. 9
0
int icmpv6_neighbor(const net_ipv6addr_t ipaddr)
{
  FAR struct net_driver_s *dev;
  struct icmpv6_notify_s notify;
  struct timespec delay;
  struct icmpv6_neighbor_s state;
  FAR const uint16_t *lookup;
  net_lock_t save;
  int ret;

  /* First check if destination is a local broadcast or a multicast address.
   *
   * - IPv6 multicast addresses are have the high-order octet of the
   *   addresses=0xff (ff00::/8.)
   */

  if (net_ipv6addr_cmp(ipaddr, g_ipv6_allzeroaddr) ||
      (ipaddr[0] & NTOHS(0xff00)) == NTOHS(0xff00))
    {
      /* We don't need to send the Neighbor Solicitation */

      return OK;
    }

  /* Get the device that can route this request */

#ifdef CONFIG_NETDEV_MULTINIC
  dev = netdev_findby_ipv6addr(g_ipv6_allzeroaddr, ipaddr);
#else
  dev = netdev_findby_ipv6addr(ipaddr);
#endif
  if (!dev)
    {
      ndbg("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr);
      ret = -EHOSTUNREACH;
      goto errout;
    }

#ifdef CONFIG_NET_MULTILINK
  /* If we are supporting multiple network devices and using different
   * link level protocols then we can get here for other link protocols
   * as well.  Continue and send the Neighbor Solicitation request only
   * if this device uses the Ethernet data link protocol.
   *
   * REVISIT:  Other link layer protocols may require Neighbor Discovery
   * as well (but not SLIP which is the only other option at the moment).
   */

  if (dev->d_lltype != NET_LL_ETHERNET)
    {
      return OK;
    }
#endif

  /* Check if the destination address is on the local network. */

  if (net_ipv6addr_maskcmp(ipaddr, dev->d_ipv6addr, dev->d_ipv6netmask))
    {
      /* Yes.. use the input address for the lookup */

      lookup = ipaddr;
    }
  else
    {
      net_ipv6addr_t dripaddr;

      /* Destination address is not on the local network */

#ifdef CONFIG_NET_ROUTE

      /* We have a routing table.. find the correct router to use in
       * this case (or, as a fall-back, use the device's default router
       * address).  We will use the router IP address instead of the
       * destination address when determining the MAC address.
       */

      netdev_ipv6_router(dev, ipaddr, dripaddr);
#else
      /* Use the device's default router IP address instead of the
       * destination address when determining the MAC address.
       */

      net_ipv6addr_copy(dripaddr, dev->d_ipv6draddr);
#endif

      /* Use the router address for the lookup */

      lookup = dripaddr;
    }

  /* Allocate resources to receive a callback.  This and the following
   * initialization is performed with the network lock because we don't
   * want anything to happen until we are ready.
   */

  save = net_lock();
  state.snd_cb = icmpv6_callback_alloc();
  if (!state.snd_cb)
    {
      ndbg("ERROR: Failed to allocate a cllback\n");
      ret = -ENOMEM;
      goto errout_with_lock;
    }

  /* Initialize the state structure. This is done with interrupts
   * disabled
   */

  (void)sem_init(&state.snd_sem, 0, 0);        /* Doesn't really fail */
  state.snd_retries = 0;                       /* No retries yet */
  net_ipv6addr_copy(state.snd_ipaddr, lookup); /* IP address to query */

#ifdef CONFIG_NETDEV_MULTINIC
  /* Remember the routing device name */

  strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname,
          IFNAMSIZ);
#endif

  /* Now loop, testing if the address mapping is in the Neighbor Table and
   * re-sending the Neighbor Solicitation if it is not.
   */

  ret = -ETIMEDOUT; /* Assume a timeout failure */

  while (state.snd_retries < CONFIG_ICMPv6_NEIGHBOR_MAXTRIES)
    {
      /* Check if the address mapping is present in the Neighbor Table.  This
       * is only really meaningful on the first time through the loop.
       *
       * NOTE: If the Neighbor Table is large than this could be a performance
       * issue.
       */

      if (neighbor_findentry(lookup) != NULL)
        {
          /* We have it!  Break out with success */

          ret = OK;
          break;
        }

      /* Set up the Neighbor Advertisement wait BEFORE we send the Neighbor
       * Solicitation.
       */

      icmpv6_wait_setup(lookup, &notify);

      /* Arm/re-arm the callback */

      state.snd_sent      = false;
      state.snd_cb->flags = ICMPv6_POLL;
      state.snd_cb->priv  = (FAR void *)&state;
      state.snd_cb->event = icmpv6_neighbor_interrupt;

      /* Notify the device driver that new TX data is available. */

      dev->d_txavail(dev);

      /* Wait for the send to complete or an error to occur: NOTES: (1)
       * net_lockedwait will also terminate if a signal is received, (2)
       * interrupts may be disabled! They will be re-enabled while the
       * task sleeps and automatically re-enabled when the task restarts.
       */

      do
        {
          (void)net_lockedwait(&state.snd_sem);
        }
      while (!state.snd_sent);

      /* Now wait for response to the Neighbor Advertisement to be received.
       * The optimal delay would be the work case round trip time.
       * NOTE: The network is locked.
       */

      delay.tv_sec  = CONFIG_ICMPv6_NEIGHBOR_DELAYSEC;
      delay.tv_nsec = CONFIG_ICMPv6_NEIGHBOR_DELAYNSEC;

      ret = icmpv6_wait(&notify, &delay);

      /* icmpv6_wait will return OK if and only if the matching Neighbor
       * Advertisement is received.  Otherwise, it will return -ETIMEDOUT.
       */

      if (ret == OK)
        {
          break;
        }

      /* Increment the retry count */

      state.snd_retries++;
    }

  sem_destroy(&state.snd_sem);
  icmpv6_callback_free(state.snd_cb);
errout_with_lock:
  net_unlock(save);
errout:
  return ret;
}