Beispiel #1
0
void netdev_ipv4_txnotify(in_addr_t ripaddr)
#  endif
{
  FAR struct net_driver_s *dev;

  /* Find the device driver that serves the subnet of the remote address */

#ifdef CONFIG_NETDEV_MULTINIC
  dev = netdev_findby_ipv4addr(lipaddr, ripaddr);
#else
  dev = netdev_findby_ipv4addr(ripaddr);
#endif

  if (dev && dev->d_txavail)
    {
      /* Notify the device driver that new TX data is available. */

      (void)dev->d_txavail(dev);
    }
}
Beispiel #2
0
static int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn, in_addr_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 INADDR_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_ipv4addr_cmp(addr, INADDR_ANY))
    {
      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_ipv4addr(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
}
int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr,
                     FAR socklen_t *addrlen)
{
  FAR struct net_driver_s *dev;
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
  FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr;
#endif
#ifdef CONFIG_NETDEV_MULTINIC
  in_addr_t lipaddr;
  in_addr_t ripaddr;
#endif

  /* Check if enough space has been provided for the full address */

  if (*addrlen < sizeof(struct sockaddr_in))
    {
      /* This function is supposed to return the partial address if
       * a smaller buffer has been provided.  This support has not
       * been implemented.
       */

      return -ENOSYS;
    }

  /* Set the port number */

  switch (psock->s_type)
    {
#ifdef CONFIG_NET_TCP
      case SOCK_STREAM:
        {
          FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn;
          outaddr->sin_port = tcp_conn->lport; /* Already in network byte order */
#ifdef CONFIG_NETDEV_MULTINIC
          lipaddr = tcp_conn->u.ipv4.laddr;
          ripaddr = tcp_conn->u.ipv4.raddr;
#endif
        }
        break;
#endif

#ifdef CONFIG_NET_UDP
      case SOCK_DGRAM:
        {
          FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn;
          outaddr->sin_port = udp_conn->lport; /* Already in network byte order */
#ifdef CONFIG_NETDEV_MULTINIC
          lipaddr = udp_conn->u.ipv4.laddr;
          ripaddr = udp_conn->u.ipv4.raddr;
#endif
        }
        break;
#endif

      default:
        return -EOPNOTSUPP;
    }

  /* The socket/connection does not know its IP address unless
   * CONFIG_NETDEV_MULTINIC is selected.  Otherwise the design supports only
   * a single network device and only the network device knows the IP address.
   */

  netdev_semtake();

#ifdef CONFIG_NETDEV_MULTINIC
  /* Find the device matching the IPv4 address in the connection structure */

  dev = netdev_findby_ipv4addr(lipaddr, ripaddr);
#else
  /* There is only one, the first network device in the list. */

  dev = g_netdevices;
#endif

  if (!dev)
    {
      netdev_semgive();
      return -EINVAL;
    }

  /* Set the address family and the IP address */

#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
  outaddr->sin_family = AF_INET;
  outaddr->sin_addr.s_addr = dev->d_ipaddr;
  *addrlen = sizeof(struct sockaddr_in);
#endif
  netdev_semgive();

  /* Return success */

  return OK;
}
Beispiel #4
0
int arp_send(in_addr_t ipaddr)
{
  FAR struct net_driver_s *dev;
  struct arp_notify_s notify;
  struct timespec delay;
  struct arp_send_s state;
  int ret;

  /* First check if destination is a local broadcast. */

  if (ipaddr == INADDR_BROADCAST)
    {
      /* We don't need to send the ARP request */

      return OK;
    }

#ifdef CONFIG_NET_IGMP
  /* Check if the destination address is a multicast address
   *
   * - IPv4: multicast addresses lie in the class D group -- The address range
   *   224.0.0.0 to 239.255.255.255 (224.0.0.0/4)
   *
   * - IPv6 multicast addresses are have the high-order octet of the
   *   addresses=0xff (ff00::/8.)
   */

  if (NTOHL(ipaddr) >= 0xe0000000 && NTOHL(ipaddr) <= 0xefffffff)
    {
      /* We don't need to send the ARP request */

      return OK;
    }
#endif

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

  dev = netdev_findby_ipv4addr(INADDR_ANY, ipaddr);
  if (!dev)
    {
      nerr("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr);
      ret = -EHOSTUNREACH;
      goto errout;
    }

  /* ARP support is only built if the Ethernet data link is supported.
   * Continue and send the ARP request only if this device uses the
   * Ethernet data link protocol.
   */

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

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

  if (!net_ipv4addr_maskcmp(ipaddr, dev->d_ipaddr, dev->d_netmask))
    {
      in_addr_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_ipv4_router(dev, ipaddr, &dripaddr);
#else
      /* Use the device's default router IP address instead of the
       * destination address when determining the MAC address.
       */

      net_ipv4addr_copy(dripaddr, dev->d_draddr);
#endif
      ipaddr = dripaddr;
    }

  /* The destination address is on the local network.  Check if it is
   * the sub-net broadcast address.
   */

  else if (net_ipv4addr_broadcast(ipaddr, dev->d_netmask))
    {
      /* Yes.. We don't need to send the ARP request */

      return OK;
    }

  /* 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.
   */

  net_lock();
  state.snd_cb = arp_callback_alloc(dev);
  if (!state.snd_cb)
    {
      nerr("ERROR: Failed to allocate a callback\n");
      ret = -ENOMEM;
      goto errout_with_lock;
    }

  /* This semaphore is used for signaling and, hence, should not have
   * priority inheritance enabled.
   */

  (void)nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
  nxsem_setprotocol(&state.snd_sem, SEM_PRIO_NONE);

  state.snd_retries   = 0;              /* No retries yet */
  state.snd_ipaddr    = ipaddr;         /* IP address to query */

  /* Remember the routing device name */

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

  /* Now loop, testing if the address mapping is in the ARP table and re-
   * sending the ARP request if it is not.
   */

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

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

      if (arp_find(ipaddr, NULL) >= 0)
        {
          /* We have it!  Break out with success */

          ret = OK;
          break;
        }

      /* Set up the ARP response wait BEFORE we send the ARP request */

      arp_wait_setup(ipaddr, &notify);

      /* Arm/re-arm the callback */

      state.snd_sent      = false;
      state.snd_result    = -EBUSY;
      state.snd_cb->flags = (ARP_POLL | NETDEV_DOWN);
      state.snd_cb->priv  = (FAR void *)&state;
      state.snd_cb->event = arp_send_eventhandler;

      /* Notify the device driver that new TX data is available.
       * NOTES: This is in essence what netdev_ipv4_txnotify() does, which
       * is not possible to call since it expects a in_addr_t as
       * its single argument to lookup the network interface.
       */

      if (dev->d_txavail)
        {
          dev->d_txavail(dev);
        }

      /* Wait for the send to complete or an error to occur.
       * net_lockedwait will also terminate if a signal is received.
       */

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

      /* Check the result of the send operation */

      ret = state.snd_result;
      if (ret < 0)
        {
          /* Break out on a send failure */

          nerr("ERROR: Send failed: %d\n", ret);
          break;
        }

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

      delay.tv_sec  = CONFIG_ARP_SEND_DELAYSEC;
      delay.tv_nsec = CONFIG_ARP_SEND_DELAYNSEC;

      ret = arp_wait(&notify, &delay);

      /* arp_wait will return OK if and only if the matching ARP response
       * is received.  Otherwise, it will return -ETIMEDOUT.
       */

      if (ret >= OK)
        {
          /* Break out if arp_wait() fails */

          break;
        }

      /* Increment the retry count */

      state.snd_retries++;
      nerr("ERROR: arp_wait failed: %d\n", ret);
    }

  nxsem_destroy(&state.snd_sem);
  arp_callback_free(dev, state.snd_cb);
errout_with_lock:
  net_unlock();
errout:
  return ret;
}
Beispiel #5
0
int icmp_ping(in_addr_t addr, uint16_t id, uint16_t seqno, uint16_t datalen,
              int dsecs)
{
  FAR struct net_driver_s *dev;
  struct icmp_ping_s state;
  net_lock_t save;
#ifdef CONFIG_NET_ARP_SEND
  int ret;
#endif

  /* Get the device that will be used to route this ICMP ECHO request */

#ifdef CONFIG_NETDEV_MULTINIC
  dev = netdev_findby_ipv4addr(INADDR_ANY, addr);
#else
  dev = netdev_findby_ipv4addr(addr);
#endif
  if (dev == 0)
    {
      ndbg("ERROR: Not reachable\n");
      return -ENETUNREACH;
    }

#ifdef CONFIG_NET_ARP_SEND
  /* Make sure that the IP address mapping is in the ARP table */

  ret = arp_send(addr);
  if (ret < 0)
    {
      ndbg("ERROR: Not reachable\n");
      return -ENETUNREACH;
    }
#endif

  /* Initialize the state structure */

  sem_init(&state.png_sem, 0, 0);
  state.png_ticks  = DSEC2TICK(dsecs); /* System ticks to wait */
  state.png_result = -ENOMEM;          /* Assume allocation failure */
  state.png_addr   = addr;             /* Address of the peer to be ping'ed */
  state.png_id     = id;               /* The ID to use in the ECHO request */
  state.png_seqno  = seqno;            /* The seqno to use in the ECHO request */
  state.png_datlen = datalen;          /* The length of data to send in the ECHO request */
  state.png_sent   = false;            /* ECHO request not yet sent */

  save             = net_lock();
  state.png_time   = clock_systimer();

  /* Set up the callback */

  state.png_cb = icmp_callback_alloc(dev);
  if (state.png_cb)
    {
      state.png_cb->flags   = (ICMP_POLL | ICMP_ECHOREPLY | NETDEV_DOWN);
      state.png_cb->priv    = (FAR void *)&state;
      state.png_cb->event   = ping_interrupt;
      state.png_result      = -EINTR; /* Assume sem-wait interrupted by signal */

      /* Notify the device driver of the availability of TX data */

      netdev_txnotify_dev(dev);

      /* Wait for either the full round trip transfer to complete or
       * for timeout to occur. (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.
       */

      nllvdbg("Start time: 0x%08x seqno: %d\n", state.png_time, seqno);
      net_lockedwait(&state.png_sem);

      icmp_callback_free(dev, state.png_cb);
    }

  net_unlock(save);

  /* Return the negated error number in the event of a failure, or the
   * sequence number of the ECHO reply on success.
   */

  if (!state.png_result)
    {
      nllvdbg("Return seqno=%d\n", state.png_seqno);
      return (int)state.png_seqno;
    }
  else
    {
      nlldbg("Return error=%d\n", -state.png_result);
      return state.png_result;
    }
}