Ejemplo n.º 1
0
void udp_send(struct net_driver_s *dev, struct udp_conn_s *conn)
{
  FAR struct udp_iphdr_s *pudpbuf = UDPBUF;

  if (dev->d_sndlen > 0)
    {
      /* The total length to send is the size of the application data plus
       * the IP and UDP headers (and, eventually, the Ethernet header)
       */

      dev->d_len = dev->d_sndlen + IPUDP_HDRLEN;

      /* Initialize the IP header.  Note that for IPv6, the IP length field
       * does not include the IPv6 IP header length.
       */

#ifdef CONFIG_NET_IPv6

      pudpbuf->vtc         = 0x60;
      pudpbuf->tcf         = 0x00;
      pudpbuf->flow        = 0x00;
      pudpbuf->len[0]      = (dev->d_sndlen >> 8);
      pudpbuf->len[1]      = (dev->d_sndlen & 0xff);
      pudpbuf->nexthdr     = IP_PROTO_UDP;
      pudpbuf->hoplimit    = conn->ttl;

      net_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr);
      net_ipaddr_copy(pudpbuf->destipaddr, &conn->ripaddr);

#else /* CONFIG_NET_IPv6 */

      pudpbuf->vhl         = 0x45;
      pudpbuf->tos         = 0;
      pudpbuf->len[0]      = (dev->d_len >> 8);
      pudpbuf->len[1]      = (dev->d_len & 0xff);
      ++g_ipid;
      pudpbuf->ipid[0]     = g_ipid >> 8;
      pudpbuf->ipid[1]     = g_ipid & 0xff;
      pudpbuf->ipoffset[0] = 0;
      pudpbuf->ipoffset[1] = 0;
      pudpbuf->ttl         = conn->ttl;
      pudpbuf->proto       = IP_PROTO_UDP;

      net_ipaddr_hdrcopy(pudpbuf->srcipaddr, &dev->d_ipaddr);
      net_ipaddr_hdrcopy(pudpbuf->destipaddr, &conn->ripaddr);

      /* Calculate IP checksum. */

      pudpbuf->ipchksum    = 0;
      pudpbuf->ipchksum    = ~(ip_chksum(dev));

#endif /* CONFIG_NET_IPv6 */

      /* Initialize the UDP header */

      pudpbuf->srcport     = conn->lport;
      pudpbuf->destport    = conn->rport;
      pudpbuf->udplen      = HTONS(dev->d_sndlen + UDP_HDRLEN);

#ifdef CONFIG_NET_UDP_CHECKSUMS
      /* Calculate UDP checksum. */

      pudpbuf->udpchksum   = 0;
      pudpbuf->udpchksum   = ~(udp_chksum(dev));
      if (pudpbuf->udpchksum == 0)
        {
          pudpbuf->udpchksum = 0xffff;
        }
#else
      pudpbuf->udpchksum   = 0;
#endif

      nllvdbg("Outgoing UDP packet length: %d (%d)\n",
              dev->d_len, (pudpbuf->len[0] << 8) | pudpbuf->len[1]);

#ifdef CONFIG_NET_STATISTICS
      g_netstats.udp.sent++;
      g_netstats.ip.sent++;
#endif
    }
Ejemplo n.º 2
0
void icmp_input(FAR struct net_driver_s *dev)
{
  FAR struct icmp_iphdr_s *picmp = ICMPBUF;

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

#ifndef CONFIG_NET_IPv6
  /* ICMPv4 processing code follows. */

  /* ICMP echo (i.e., ping) processing. This is simple, we only change the
   * ICMP type from ECHO to ECHO_REPLY and adjust the ICMP checksum before
   * we return the packet.
   */

  if (picmp->type == ICMP_ECHO_REQUEST)
    {
      /* If we are configured to use ping IP address assignment, we use
       * the destination IP address of this ping packet and assign it to
       * ourself.
       */

#ifdef CONFIG_NET_PINGADDRCONF
      if (dev->d_ipaddr == 0)
        {
          dev->d_ipaddr = picmp->destipaddr;
        }
#endif

      /* Change the ICMP type */

      picmp->type = ICMP_ECHO_REPLY;

      /* Swap IP addresses. */

      net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr);
      net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr);

      /* Recalculate the ICMP checksum */

#if 0
      /* The slow way... sum over the ICMP message */

      picmp->icmpchksum = 0;
      picmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)picmp->len[0] << 8) | (uint16_t)picmp->len[1]) - IP_HDRLEN);
      if (picmp->icmpchksum == 0)
        {
          picmp->icmpchksum = 0xffff;
        }
#else
      /* The quick way -- Since only the type has changed, just adjust the
       * checksum for the change of type
       */

      if (picmp->icmpchksum >= HTONS(0xffff - (ICMP_ECHO_REQUEST << 8)))
        {
          picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8) + 1;
        }
      else
        {
          picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8);
        }
#endif

      nllvdbg("Outgoing ICMP packet length: %d (%d)\n",
              dev->d_len, (picmp->len[0] << 8) | picmp->len[1]);

#ifdef CONFIG_NET_STATISTICS
      g_netstats.icmp.sent++;
      g_netstats.ip.sent++;
#endif
    }

  /* If an ICMP echo reply is received then there should also be
   * a thread waiting to received the echo response.
   */

#ifdef CONFIG_NET_ICMP_PING
  else if (picmp->type == ICMP_ECHO_REPLY && g_echocallback)
    {
      (void)devif_callback_execute(dev, picmp, ICMP_ECHOREPLY, g_echocallback);
    }
#endif

  /* Otherwise the ICMP input was not processed */

  else
    {
      nlldbg("Unknown ICMP cmd: %d\n", picmp->type);
      goto typeerr;
    }

  return;

typeerr:
#ifdef CONFIG_NET_STATISTICS
  g_netstats.icmp.typeerr++;
  g_netstats.icmp.drop++;
#endif
  dev->d_len = 0;

#else /* !CONFIG_NET_IPv6 */

  /* If we get a neighbor solicitation for our address we should send
   * a neighbor advertisement message back.
   */

  if (picmp->type == ICMP6_NEIGHBOR_SOLICITATION)
    {
      if (net_ipaddr_cmp(picmp->icmp6data, dev->d_ipaddr))
        {
          if (picmp->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS)
            {
              /* Save the sender's address in our neighbor list. */

              net_neighbor_add(picmp->srcipaddr, &(picmp->options[2]));
            }

          /* We should now send a neighbor advertisement back to where the
           * neighbor solicitation came from.
           */

          picmp->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
          picmp->flags = ICMP6_FLAG_S; /* Solicited flag. */

          picmp->reserved1 = picmp->reserved2 = picmp->reserved3 = 0;

          net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr);
          net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr);
          picmp->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
          picmp->options[1] = 1;  /* Options length, 1 = 8 bytes. */
          memcpy(&(picmp->options[2]), &dev->d_mac, IFHWADDRLEN);
          picmp->icmpchksum = 0;
          picmp->icmpchksum = ~icmp_6chksum(dev);
        }
      else
        {
          goto drop;
        }
    }
  else if (picmp->type == ICMP6_ECHO_REQUEST)
    {
      /* ICMP echo (i.e., ping) processing. This is simple, we only
       * change the ICMP type from ECHO to ECHO_REPLY and update the
       * ICMP checksum before we return the packet.
       */

      picmp->type = ICMP6_ECHO_REPLY;

      net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr);
      net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr);
      picmp->icmpchksum = 0;
      picmp->icmpchksum = ~icmp_6chksum(dev);
    }

  /* If an ICMP echo reply is received then there should also be
   * a thread waiting to received the echo response.
   */

#ifdef CONFIG_NET_ICMP_PING
  else if (picmp->type == ICMP6_ECHO_REPLY && g_echocallback)
    {
      uint16_t flags = ICMP_ECHOREPLY;

      if (g_echocallback)
        {
          /* Dispatch the ECHO reply to the waiting thread */

          flags = devif_callback_execute(dev, picmp, flags, g_echocallback);
        }

      /* If the ECHO reply was not handled, then drop the packet */

      if (flags == ICMP_ECHOREPLY)
        {
          /* The ECHO reply was not handled */

          goto drop;
        }
    }
#endif

  else
    {
      nlldbg("Unknown ICMP6 cmd: %d\n", picmp->type);
      goto typeerr;
    }

  nllvdbg("Outgoing ICMP6 packet length: %d (%d)\n",
          dev->d_len, (picmp->len[0] << 8) | picmp->len[1]);

#ifdef CONFIG_NET_STATISTICS
  g_netstats.icmp.sent++;
  g_netstats.ip.sent++;
#endif
  return;

typeerr:
#ifdef CONFIG_NET_STATISTICS
  g_netstats.icmp.typeerr++;
#endif

drop:
#ifdef CONFIG_NET_STATISTICS
  g_netstats.icmp.drop++;
#endif
  dev->d_len = 0;

#endif /* !CONFIG_NET_IPv6 */
}
Ejemplo n.º 3
0
void icmp_send(FAR struct net_driver_s *dev, FAR net_ipaddr_t *destaddr)
{
  FAR struct icmp_iphdr_s *picmp = ICMPBUF;

  if (dev->d_sndlen > 0)
    {
      /* The total length to send is the size of the application data plus
       * the IP and ICMP headers (and, eventually, the Ethernet header)
       */

      dev->d_len = dev->d_sndlen + IPICMP_HDRLEN;

      /* The total size of the data (for ICMP checksum calculation) includes
       * the size of the ICMP header
       */

      dev->d_sndlen += ICMP_HDRLEN;

      /* Initialize the IP header.  Note that for IPv6, the IP length field
       * does not include the IPv6 IP header length.
       */

#ifdef CONFIG_NET_IPv6

      picmp->vtc         = 0x60;
      picmp->tcf         = 0x00;
      picmp->flow        = 0x00;
      picmp->len[0]      = (dev->d_sndlen >> 8);
      picmp->len[1]      = (dev->d_sndlen & 0xff);
      picmp->nexthdr     = IP_PROTO_ICMP;
      picmp->hoplimit    = IP_TTL;

      net_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr);
      net_ipaddr_copy(picmp->destipaddr, destaddr);

#else /* CONFIG_NET_IPv6 */

      picmp->vhl         = 0x45;
      picmp->tos         = 0;
      picmp->len[0]      = (dev->d_len >> 8);
      picmp->len[1]      = (dev->d_len & 0xff);
      ++g_ipid;
      picmp->ipid[0]     = g_ipid >> 8;
      picmp->ipid[1]     = g_ipid & 0xff;
      picmp->ipoffset[0] = TCPFLAG_DONTFRAG >> 8;
      picmp->ipoffset[1] = TCPFLAG_DONTFRAG & 0xff;
      picmp->ttl         = IP_TTL;
      picmp->proto       = IP_PROTO_ICMP;

      net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr);
      net_ipaddr_hdrcopy(picmp->destipaddr, destaddr);

      /* Calculate IP checksum. */

      picmp->ipchksum    = 0;
      picmp->ipchksum    = ~(ip_chksum(dev));

#endif /* CONFIG_NET_IPv6 */

      /* Calculate the ICMP checksum. */

      picmp->icmpchksum  = 0;
      picmp->icmpchksum  = ~(icmp_chksum(dev, dev->d_sndlen));
      if (picmp->icmpchksum == 0)
        {
          picmp->icmpchksum = 0xffff;
        }

      nllvdbg("Outgoing ICMP packet length: %d (%d)\n",
              dev->d_len, (picmp->len[0] << 8) | picmp->len[1]);

#ifdef CONFIG_NET_STATISTICS
      g_netstats.icmp.sent++;
      g_netstats.ip.sent++;
#endif
    }
Ejemplo n.º 4
0
void arp_arpin(FAR struct net_driver_s *dev)
{
  FAR struct arp_hdr_s *parp = ARPBUF;
  in_addr_t ipaddr;

  if (dev->d_len < (sizeof(struct arp_hdr_s) + NET_LL_HDRLEN))
    {
      nlldbg("Too small\n");
      dev->d_len = 0;
      return;
    }

  dev->d_len = 0;

  ipaddr = net_ip4addr_conv32(parp->ah_dipaddr);
  switch(parp->ah_opcode)
    {
      case HTONS(ARP_REQUEST):
        nllvdbg("ARP request for IP %04lx\n", (long)ipaddr);

        /* ARP request. If it asked for our address, we send out a reply. */

        if (net_ipaddr_cmp(ipaddr, dev->d_ipaddr))
          {
            struct eth_hdr_s *peth = ETHBUF;

            /* First, we register the one who made the request in our ARP
             * table, since it is likely that we will do more communication
             * with this host in the future.
             */

            arp_update(parp->ah_sipaddr, parp->ah_shwaddr);

            parp->ah_opcode = HTONS(ARP_REPLY);
            memcpy(parp->ah_dhwaddr, parp->ah_shwaddr, ETHER_ADDR_LEN);
            memcpy(parp->ah_shwaddr, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN);
            memcpy(peth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN);
            memcpy(peth->dest, parp->ah_dhwaddr, ETHER_ADDR_LEN);

            parp->ah_dipaddr[0] = parp->ah_sipaddr[0];
            parp->ah_dipaddr[1] = parp->ah_sipaddr[1];
            net_ipaddr_hdrcopy(parp->ah_sipaddr, &dev->d_ipaddr);
            arp_dump(parp);

            peth->type          = HTONS(ETHTYPE_ARP);
            dev->d_len          = sizeof(struct arp_hdr_s) + NET_LL_HDRLEN;
          }
        break;

      case HTONS(ARP_REPLY):
        nllvdbg("ARP reply for IP %04lx\n", (long)ipaddr);

        /* ARP reply. We insert or update the ARP table if it was meant
         * for us.
         */

        if (net_ipaddr_cmp(ipaddr, dev->d_ipaddr))
          {
            /* Yes... Insert the address mapping in the ARP table */

            arp_update(parp->ah_sipaddr, parp->ah_shwaddr);

            /* Then notify any logic waiting for the ARP result */

            arp_notify(net_ip4addr_conv32(parp->ah_sipaddr));
          }
        break;
    }
}