Exemplo n.º 1
0
static int net_match_ipv4(FAR struct net_route_ipv4_s *route, FAR void *arg)
{
  FAR struct route_match_ipv4_s *match = (FAR struct route_match_ipv4_s *)arg;

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

  net_ipv4_dumproute("Comparing", route);
  ninfo("With:\n");
  ninfo("  target=%08lx netmask=%08lx\n",
        htonl(match->target), htonl(match->netmask));

  if (net_ipv4addr_maskcmp(route->target, match->target, match->netmask) &&
      net_ipv4addr_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;
}
Exemplo n.º 2
0
void arp_ipin(FAR struct net_driver_s *dev)
{
  in_addr_t srcipaddr;

  /* Only insert/update an entry if the source IP address of the incoming IP
   * packet comes from a host on the local network.
   */

  srcipaddr = net_ip4addr_conv32(IPBUF->eh_srcipaddr);
  if (net_ipv4addr_maskcmp(srcipaddr, dev->d_ipaddr, dev->d_netmask))
    {
      arp_hdr_update(IPBUF->eh_srcipaddr, ETHBUF->src);
    }
}
Exemplo n.º 3
0
static bool lib_lo_ipv4match(FAR const void *addr, socklen_t len, int type)
{
  FAR struct in_addr *ipv4addr;

  if (type == AF_INET && len >= sizeof(struct in_addr))
    {
      ipv4addr = (FAR struct in_addr *)addr;
      return net_ipv4addr_maskcmp(ipv4addr->sin_addr.s_addr,
                                  g_lo_ipv4addr->s_addr,
                                  g_lo_ipv4addr->s_addr);
    }

  return false;
}
Exemplo n.º 4
0
static int net_match(FAR struct net_route_s *route, FAR void *arg)
{
  FAR struct route_match_s *match = ( FAR struct route_match_s *)arg;

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

  if (net_ipv4addr_maskcmp(route->target, match->target, match->netmask) &&
      net_ipv4addr_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);
        }
      else
        {
          (void)sq_remfirst((FAR sq_queue_t *)&g_routes);
        }

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

      net_freeroute(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;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
static uint16_t ping_interrupt(FAR struct net_driver_s *dev, FAR void *conn,
                               FAR void *pvpriv, uint16_t flags)
{
  FAR struct icmp_ping_s *pstate = (struct icmp_ping_s *)pvpriv;
  FAR uint8_t *ptr;
  int i;

  nllvdbg("flags: %04x\n", flags);
  if (pstate)
    {
      /* Check if this is a ICMP ECHO reply.  If so, return the sequence
       * number to the caller.  NOTE: We may not even have sent the
       * requested ECHO request; this could have been the delayed ECHO
       * response from a previous ping.
       */

      if ((flags & ICMP_ECHOREPLY) != 0 && conn != NULL)
        {
          FAR struct icmp_iphdr_s *icmp = (FAR struct icmp_iphdr_s *)conn;

          nllvdbg("ECHO reply: id=%d seqno=%d\n",
                  ntohs(icmp->id), ntohs(icmp->seqno));

          if (ntohs(icmp->id) == pstate->png_id)
            {
              /* Consume the ECHOREPLY */

              flags     &= ~ICMP_ECHOREPLY;
              dev->d_len = 0;

              /* Return the result to the caller */

              pstate->png_result = OK;
              pstate->png_seqno  = ntohs(icmp->seqno);
              goto end_wait;
            }
        }

      /* Check:
       *   If the outgoing packet is available (it may have been claimed
       *   by a sendto interrupt serving a different thread)
       * -OR-
       *   If the output buffer currently contains unprocessed incoming
       *   data.
       * -OR-
       *   If we have already sent the ECHO request
       *
       * In the first two cases, we will just have to wait for the next
       * polling cycle.
       */

      if (dev->d_sndlen <= 0 &&           /* Packet available */
          (flags & ICMP_NEWDATA) == 0 &&  /* No incoming data */
          !pstate->png_sent)              /* Request not sent */
        {
          FAR struct icmp_iphdr_s *picmp = ICMPBUF;

          /* We can send the ECHO request now.
           *
           * Format the ICMP ECHO request packet
           */

          picmp->type  = ICMP_ECHO_REQUEST;
          picmp->icode = 0;
          picmp->id    = htons(pstate->png_id);
          picmp->seqno = htons(pstate->png_seqno);

          /* Add some easily verifiable data */

          for (i = 0, ptr = ICMPDAT; i < pstate->png_datlen; i++)
            {
              *ptr++ = i;
            }

          /* Send the ICMP echo request.  Note that d_sndlen is set to
           * the size of the ICMP payload and does not include the size
           * of the ICMP header.
           */

          nllvdbg("Send ECHO request: seqno=%d\n", pstate->png_seqno);

          dev->d_sndlen = pstate->png_datlen + 4;
          icmp_send(dev, &pstate->png_addr);

          pstate->png_sent = true;
          return flags;
        }

      /* Check if the selected timeout has elapsed */

      if (ping_timeout(pstate))
        {
          int failcode;

          /* Check if this device is on the same network as the destination
           * device.
           */

          if (!net_ipv4addr_maskcmp(pstate->png_addr, dev->d_ipaddr, dev->d_netmask))
            {
              /* Destination address was not on the local network served by this
               * device.  If a timeout occurs, then the most likely reason is
               * that the destination address is not reachable.
               */

              nlldbg("Not reachable\n");
              failcode = -ENETUNREACH;
            }
          else
            {
              nlldbg("Ping timeout\n");
              failcode = -ETIMEDOUT;
            }

          /* Report the failure */

          pstate->png_result = failcode;
          goto end_wait;
        }

      /* Continue waiting */
    }

  return flags;

end_wait:
  nllvdbg("Resuming\n");

  /* Do not allow any further callbacks */

  pstate->png_cb->flags   = 0;
  pstate->png_cb->priv    = NULL;
  pstate->png_cb->event   = NULL;

  /* Wake up the waiting thread */

  sem_post(&pstate->png_sem);
  return flags;
}
Exemplo n.º 7
0
void arp_out(FAR struct net_driver_s *dev)
{
  struct ether_addr ethaddr;
  FAR struct eth_hdr_s *peth = ETHBUF;
  FAR struct arp_iphdr_s *pip = IPBUF;
  in_addr_t ipaddr;
  in_addr_t destipaddr;
  int ret;

#if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_ARP_SEND)
  /* Skip sending ARP requests when the frame to be transmitted was
   * written into a packet socket.
   */

  if (IFF_IS_NOARP(dev->d_flags))
    {
      /* Clear the indication and let the packet continue on its way. */

      IFF_CLR_NOARP(dev->d_flags);
      return;
    }
#endif

  /* Find the destination IP address in the ARP table and construct
   * the Ethernet header. If the destination IP address isn't on the
   * local network, we use the default router's IP address instead.
   *
   * If not ARP table entry is found, we overwrite the original IP
   * packet with an ARP request for the IP address.
   */

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

  if (net_ipv4addr_hdrcmp(pip->eh_destipaddr, g_broadcast_ipaddr))
    {
      memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
      goto finish_header;
    }

#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 (NTOHS(pip->eh_destipaddr[0]) >= 0xe000 &&
      NTOHS(pip->eh_destipaddr[0]) <= 0xefff)
    {
      /* Build the well-known IPv4 IGMP Ethernet address.  The first
       * three bytes are fixed; the final three variable come from the
       * last three bytes of the IPv4 address (network order).
       *
       * Address range : 01:00:5e:00:00:00 to 01:00:5e:7f:ff:ff
       */

      FAR const uint8_t *ip = (FAR uint8_t *)pip->eh_destipaddr;

      peth->dest[0] = g_multicast_ethaddr[0];
      peth->dest[1] = g_multicast_ethaddr[1];
      peth->dest[2] = g_multicast_ethaddr[2];
      peth->dest[3] = ip[1] & 0x7f;
      peth->dest[4] = ip[2];
      peth->dest[5] = ip[3];

      goto finish_header;
    }
#endif

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

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

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

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

  else if (net_ipv4addr_broadcast(destipaddr, dev->d_netmask))
    {
      /* Yes.. then we won't need to know the destination MAC address */

      memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
      goto finish_header;
    }
  else
    {
      /* Else, we use the destination IP address. */

      net_ipv4addr_copy(ipaddr, destipaddr);
    }

  /* Check if we already have this destination address in the ARP table */

  ret = arp_find(ipaddr, &ethaddr);
  if (ret < 0)
    {
      ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr);

      /* The destination address was not in our ARP table, so we overwrite
       * the IP packet with an ARP request.
       */

      arp_format(dev, ipaddr);
      arp_dump(ARPBUF);
      return;
    }

  /* Build an Ethernet header. */

  memcpy(peth->dest, ethaddr.ether_addr_octet, ETHER_ADDR_LEN);

  /* Finish populating the Ethernet header */

finish_header:
  memcpy(peth->src, dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN);
  peth->type  = HTONS(ETHTYPE_IP);
  dev->d_len += ETH_HDRLEN;
}