Exemplo n.º 1
0
static inline FAR struct tcp_conn_s *
  tcp_ipv4_active(FAR struct net_driver_s *dev, FAR struct tcp_hdr_s *tcp)
{
  FAR struct ipv4_hdr_s *ip = IPv4BUF;
  FAR struct tcp_conn_s *conn;
  in_addr_t srcipaddr;
#ifdef CONFIG_NETDEV_MULTINIC
  in_addr_t destipaddr;
#endif

  conn       = (FAR struct tcp_conn_s *)g_active_tcp_connections.head;
  srcipaddr  = net_ip4addr_conv32(ip->srcipaddr);
#ifdef CONFIG_NETDEV_MULTINIC
  destipaddr = net_ip4addr_conv32(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_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY) ||
           net_ipv4addr_cmp(destipaddr, conn->u.ipv4.laddr)) &&
#endif
          net_ipv4addr_cmp(srcipaddr, conn->u.ipv4.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;
}
Exemplo n.º 2
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.º 3
0
FAR struct igmp_group_s *igmp_grpfind(FAR struct net_driver_s *dev,
                                      FAR const in_addr_t *addr)
{
  FAR struct igmp_group_s *group;
  net_lock_t flags;

  grplldbg("Searching for addr %08x\n", (int)*addr);

  /* We must disable interrupts because we don't which context we were
   * called from.
   */

  flags = net_lock();
  for (group = (FAR struct igmp_group_s *)dev->grplist.head;
       group;
       group = group->next)
    {
      grplldbg("Compare: %08x vs. %08x\n", group->grpaddr, *addr);
      if (net_ipv4addr_cmp(group->grpaddr, *addr))
        {
          grplldbg("Match!\n");
          break;
        }
    }

  net_unlock(flags);
  return group;
}
Exemplo n.º 4
0
static inline FAR struct tcp_conn_s *tcp_ipv4_listener(in_addr_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_ipv4addr_cmp(conn->u.ipv4.laddr, ipaddr) ||
              net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY))
            {
              /* The port number is in use, return the connection */

              return conn;
            }
        }
    }

  return NULL;
}
Exemplo n.º 5
0
FAR struct arp_entry *arp_find(in_addr_t ipaddr)
{
  FAR struct arp_entry *tabptr;
  int i;

  for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i)
    {
      tabptr = &g_arptable[i];
      if (net_ipv4addr_cmp(ipaddr, tabptr->at_ipaddr))
        {
          return tabptr;
        }
    }

  return NULL;
}
Exemplo n.º 6
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
}
Exemplo n.º 7
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.º 8
0
int arp_update(in_addr_t ipaddr, FAR uint8_t *ethaddr)
{
  struct arp_entry *tabptr = NULL;
  int               i;

  /* Walk through the ARP mapping table and try to find an entry to
   * update. If none is found, the IP -> MAC address mapping is
   * inserted in the ARP table.
   */

  for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i)
    {
      tabptr = &g_arptable[i];

      /* Only check those entries that are actually in use. */

      if (tabptr->at_ipaddr != 0)
        {
          /* Check if the source IP address of the incoming packet matches
           * the IP address in this ARP table entry.
           */

          if (net_ipv4addr_cmp(ipaddr, tabptr->at_ipaddr))
            {
              /* An old entry found, update this and return. */

              memcpy(tabptr->at_ethaddr.ether_addr_octet, ethaddr, ETHER_ADDR_LEN);
              tabptr->at_time = g_arptime;
              return OK;
            }
        }
    }

  /* If we get here, no existing ARP table entry was found, so we create one. */
  /* First, we try to find an unused entry in the ARP table. */

  for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i)
    {
      tabptr = &g_arptable[i];
      if (tabptr->at_ipaddr == 0)
        {
          break;
        }
    }

  /* If no unused entry is found, we try to find the oldest entry and
   * throw it away.
   */

  if (i == CONFIG_NET_ARPTAB_SIZE)
    {
      uint8_t tmpage = 0;
      int j = 0;

      for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i)
        {
          tabptr = &g_arptable[i];
          if (g_arptime - tabptr->at_time > tmpage)
            {
              tmpage = g_arptime - tabptr->at_time;
              j = i;
            }
        }

      i = j;
      tabptr = &g_arptable[i];
    }

  /* Now, i is the ARP table entry which we will fill with the new
   * information.
   */

  tabptr->at_ipaddr = ipaddr;
  memcpy(tabptr->at_ethaddr.ether_addr_octet, ethaddr, ETHER_ADDR_LEN);
  tabptr->at_time = g_arptime;
  return OK;
}
Exemplo n.º 9
0
int ipv4_input(FAR struct net_driver_s *dev)
{
  FAR struct ipv4_hdr_s *pbuf = BUF;
  uint16_t iplen;

  /* This is where the input processing starts. */

#ifdef CONFIG_NET_STATISTICS
  g_netstats.ipv4.recv++;
#endif

  /* Start of IP input header processing code. */
  /* Check validity of the IP header. */

  if (pbuf->vhl != 0x45)
    {
      /* IP version and header length. */

#ifdef CONFIG_NET_STATISTICS
      g_netstats.ipv4.drop++;
      g_netstats.ipv4.vhlerr++;
#endif
      nlldbg("Invalid IP version or header length: %02x\n", pbuf->vhl);
      goto drop;
    }

  /* Check the size of the packet. If the size reported to us in d_len is
   * smaller the size reported in the IP header, we assume that the packet
   * has been corrupted in transit. If the size of d_len is larger than the
   * size reported in the IP packet header, the packet has been padded and
   * we set d_len to the correct value.
   */

  iplen = (pbuf->len[0] << 8) + pbuf->len[1];
  if (iplen <= dev->d_len)
    {
      dev->d_len = iplen;
    }
  else
    {
      nlldbg("IP packet shorter than length in IP header\n");
      goto drop;
    }

  /* Check the fragment flag. */

  if ((pbuf->ipoffset[0] & 0x3f) != 0 || pbuf->ipoffset[1] != 0)
    {
#if defined(CONFIG_NET_TCP_REASSEMBLY)
      dev->d_len = devif_reassembly();
      if (dev->d_len == 0)
        {
          goto drop;
        }
#else /* CONFIG_NET_TCP_REASSEMBLY */
#ifdef CONFIG_NET_STATISTICS
      g_netstats.ipv4.drop++;
      g_netstats.ipv4.fragerr++;
#endif
      nlldbg("IP fragment dropped\n");
      goto drop;
#endif /* CONFIG_NET_TCP_REASSEMBLY */
    }

   /* If IP broadcast support is configured, we check for a broadcast
    * UDP packet, which may be destined to us (even if there is no IP
    * address yet assigned to the device as is the case when we are
    * negotiating over DHCP for an address).
    */

#if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP_STACK)
  if (pbuf->proto == IP_PROTO_UDP &&
      net_ipv4addr_cmp(net_ip4addr_conv32(pbuf->destipaddr),
                       g_ipv4_alloneaddr))
    {
      return udp_ipv4_input(dev);
    }

  /* In most other cases, the device must be assigned a non-zero IP
   * address.  Another exception is when CONFIG_NET_PINGADDRCONF is
   * enabled...
   */

  else
#endif
#ifdef CONFIG_NET_ICMP
  if (net_ipv4addr_cmp(dev->d_ipaddr, g_ipv4_allzeroaddr))
    {
      /* If we are configured to use ping IP address configuration and
       * hasn't been assigned an IP address yet, we accept all ICMP
       * packets.
       */

#ifdef CONFIG_NET_PINGADDRCONF
      if (pbuf->proto == IP_PROTO_ICMP)
        {
          nlldbg("Possible ping config packet received\n");
          icmp_input(dev);
          goto drop;
        }
      else
#endif
        {
          nlldbg("No IP address assigned\n");
          goto drop;
        }
    }

  /* Check if the packet is destined for out IP address */
  else
#endif
    {
      /* Check if the packet is destined for our IP address. */

      if (!net_ipv4addr_cmp(net_ip4addr_conv32(pbuf->destipaddr), dev->d_ipaddr))
        {
#ifdef CONFIG_NET_IGMP
          in_addr_t destip = net_ip4addr_conv32(pbuf->destipaddr);
          if (igmp_grpfind(dev, &destip) == NULL)
#endif
            {
#ifdef CONFIG_NET_STATISTICS
              g_netstats.ipv4.drop++;
#endif
              goto drop;
            }
        }
    }

  if (ipv4_chksum(dev) != 0xffff)
    {
      /* Compute and check the IP header checksum. */

#ifdef CONFIG_NET_STATISTICS
      g_netstats.ipv4.drop++;
      g_netstats.ipv4.chkerr++;
#endif
      nlldbg("Bad IP checksum\n");
      goto drop;
    }

  /* Make sure that all packet processing logic knows that there is an IPv4
   * packet in the device buffer.
   */

  IFF_SET_IPv4(dev->d_flags);

  /* Now process the incoming packet according to the protocol. */

  switch (pbuf->proto)
    {
#ifdef CONFIG_NET_TCP_STACK
      case IP_PROTO_TCP:   /* TCP input */
        tcp_ipv4_input(dev);
        break;
#endif

#ifdef CONFIG_NET_UDP_STACK
      case IP_PROTO_UDP:   /* UDP input */
        udp_ipv4_input(dev);
        break;
#endif

  /* Check for ICMP input */

#ifdef CONFIG_NET_ICMP
      case IP_PROTO_ICMP:  /* ICMP input */
        icmp_input(dev);
        break;
#endif

  /* Check for IGMP input */

#ifdef CONFIG_NET_IGMP
      case IP_PROTO_IGMP:  /* IGMP input */
        igmp_input(dev);
        break;
#endif

      default:              /* Unrecognized/unsupported protocol */
#ifdef CONFIG_NET_STATISTICS
        g_netstats.ipv4.drop++;
        g_netstats.ipv4.protoerr++;
#endif

        nlldbg("Unrecognized IP protocol\n");
        goto drop;
    }

  /* Return and let the caller do any pending transmission. */

  return OK;

  /* Drop the packet.  NOTE that OK is returned meaning that the
   * packet has been processed (although processed unsuccessfully).
   */

drop:
  dev->d_len = 0;
  return OK;
}