示例#1
0
void uip_igmpsend(FAR struct uip_driver_s *dev, FAR struct igmp_group_s *group,
                  FAR uip_ipaddr_t *destipaddr)
{
  nllvdbg("msgid: %02x destipaddr: %08x\n", group->msgid, (int)*destipaddr);

  /* The total length to send is the size of the IP and IGMP headers and 4
   * bytes for the ROUTER ALERT (and, eventually, the ethernet header)
   */

  dev->d_len           = UIP_IPIGMPH_LEN;

  /* The total size of the data is the size of the IGMP header */

  dev->d_sndlen        = UIP_IGMPH_LEN;

  /* Add the router alert option */

  IGMPBUF->ra[0]       = HTONS(IPOPT_RA >> 16);
  IGMPBUF->ra[1]       = HTONS(IPOPT_RA & 0xffff);

  /* Initialize the IPv4 header */

  IGMPBUF->vhl         = 0x46;  /* 4->IP; 6->24 bytes */
  IGMPBUF->tos         = 0;
  IGMPBUF->len[0]      = (dev->d_len >> 8);
  IGMPBUF->len[1]      = (dev->d_len & 0xff);
  ++g_ipid;
  IGMPBUF->ipid[0]     = g_ipid >> 8;
  IGMPBUF->ipid[1]     = g_ipid & 0xff;
  IGMPBUF->ipoffset[0] = UIP_TCPFLAG_DONTFRAG >> 8;
  IGMPBUF->ipoffset[1] = UIP_TCPFLAG_DONTFRAG & 0xff;
  IGMPBUF->ttl         = IGMP_TTL;
  IGMPBUF->proto       = UIP_PROTO_IGMP;

  uiphdr_ipaddr_copy(IGMPBUF->srcipaddr, &dev->d_ipaddr);
  uiphdr_ipaddr_copy(IGMPBUF->destipaddr, destipaddr);

  /* Calculate IP checksum. */

  IGMPBUF->ipchksum    = 0;
  IGMPBUF->ipchksum    = ~uip_igmpchksum((FAR uint8_t *)IGMPBUF, UIP_IPH_LEN + RASIZE);

  /* Set up the IGMP message */

  IGMPBUF->type        = group->msgid;
  IGMPBUF->maxresp     = 0;
  uiphdr_ipaddr_copy(IGMPBUF->grpaddr, &group->grpaddr);

  /* Calculate the IGMP checksum. */

  IGMPBUF->chksum      = 0;
  IGMPBUF->chksum      = ~uip_igmpchksum(&IGMPBUF->type, UIP_IPIGMPH_LEN);

  IGMP_STATINCR(uip_stat.igmp.poll_send);
  IGMP_STATINCR(uip_stat.ip.sent);

  nllvdbg("Outgoing IGMP packet length: %d (%d)\n",
          dev->d_len, (IGMPBUF->len[0] << 8) | IGMPBUF->len[1]);
  igmp_dumppkt(RA, UIP_IPIGMPH_LEN + RASIZE);
}
示例#2
0
static void uip_tcpsendcommon(struct uip_driver_s *dev, struct uip_conn *conn)
{
  struct uip_tcpip_hdr *pbuf = BUF;

  memcpy(pbuf->ackno, conn->rcvseq, 4);
  memcpy(pbuf->seqno, conn->sndseq, 4);

  pbuf->proto    = UIP_PROTO_TCP;
  pbuf->srcport  = conn->lport;
  pbuf->destport = conn->rport;

  uiphdr_ipaddr_copy(pbuf->srcipaddr, &dev->d_ipaddr);
  uiphdr_ipaddr_copy(pbuf->destipaddr, &conn->ripaddr);

  if (conn->tcpstateflags & UIP_STOPPED)
    {
      /* If the connection has issued uip_stop(), we advertise a zero
       * window so that the remote host will stop sending data.
       */

      pbuf->wnd[0] = 0;
      pbuf->wnd[1] = 0;
    }
  else
    {
      pbuf->wnd[0] = ((CONFIG_NET_RECEIVE_WINDOW) >> 8);
      pbuf->wnd[1] = ((CONFIG_NET_RECEIVE_WINDOW) & 0xff);
    }

  /* Finish the IP portion of the message, calculate checksums and send
   * the message.
   */

  uip_tcpsendcomplete(dev);

}
示例#3
0
void uip_icmpsend(struct uip_driver_s *dev, uip_ipaddr_t *destaddr)
{
  struct uip_icmpip_hdr *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 + UIP_IPICMPH_LEN;

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

      dev->d_sndlen += UIP_ICMPH_LEN;

      /* 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     = UIP_PROTO_ICMP;
      picmp->hoplimit    = UIP_TTL;

      uip_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr);
      uip_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] = UIP_TCPFLAG_DONTFRAG >> 8;
      picmp->ipoffset[1] = UIP_TCPFLAG_DONTFRAG & 0xff;
      picmp->ttl         = UIP_TTL;
      picmp->proto       = UIP_PROTO_ICMP;

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

      /* Calculate IP checksum. */

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

#endif /* CONFIG_NET_IPv6 */

      /* Calculate the ICMP checksum. */

      picmp->icmpchksum  = 0;
      picmp->icmpchksum  = ~(uip_icmpchksum(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
      uip_stat.icmp.sent++;
      uip_stat.ip.sent++;
#endif
    }
示例#4
0
void uip_icmpinput(struct uip_driver_s *dev)
{
  struct uip_icmpip_hdr *picmp = ICMPBUF;

#ifdef CONFIG_NET_STATISTICS
  uip_stat.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. */

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

      /* Recalculate the ICMP checksum */

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

      picmp->icmpchksum = 0;
      picmp->icmpchksum = ~uip_icmpchksum(dev, (((uint16_t)picmp->len[0] << 8) | (uint16_t)picmp->len[1]) - UIP_IPH_LEN);
      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
      uip_stat.icmp.sent++;
      uip_stat.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)uip_callbackexecute(dev, picmp, UIP_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
  uip_stat.icmp.typeerr++;
  uip_stat.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 (uip_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. */

              uiphdr_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;

          uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr);
          uiphdr_ipaddr_copy(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 = ~uip_icmp6chksum(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;

      uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr);
      uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr);
      picmp->icmpchksum = 0;
      picmp->icmpchksum = ~uip_icmp6chksum(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 = UIP_ECHOREPLY;

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

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

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

      if (flags == UIP_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
  uip_stat.icmp.sent++;
  uip_stat.ip.sent++;
#endif
  return;

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

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

#endif /* !CONFIG_NET_IPv6 */
}
示例#5
0
void uip_tcpreset(struct uip_driver_s *dev)
{
  struct uip_tcpip_hdr *pbuf = BUF;

  uint16_t tmp16;
  uint8_t  seqbyte;

#ifdef CONFIG_NET_STATISTICS
  uip_stat.tcp.rst++;
#endif

  pbuf->flags     = TCP_RST | TCP_ACK;
  dev->d_len      = UIP_IPTCPH_LEN;
  pbuf->tcpoffset = 5 << 4;

  /* Flip the seqno and ackno fields in the TCP header. */

  seqbyte         = pbuf->seqno[3];
  pbuf->seqno[3]  = pbuf->ackno[3];
  pbuf->ackno[3]  = seqbyte;

  seqbyte         = pbuf->seqno[2];
  pbuf->seqno[2]  = pbuf->ackno[2];
  pbuf->ackno[2]  = seqbyte;

  seqbyte         = pbuf->seqno[1];
  pbuf->seqno[1]  = pbuf->ackno[1];
  pbuf->ackno[1]  = seqbyte;

  seqbyte         = pbuf->seqno[0];
  pbuf->seqno[0]  = pbuf->ackno[0];
  pbuf->ackno[0]  = seqbyte;

  /* We also have to increase the sequence number we are
   * acknowledging. If the least significant byte overflowed, we need
   * to propagate the carry to the other bytes as well.
   */

  if (++(pbuf->ackno[3]) == 0)
    {
      if (++(pbuf->ackno[2]) == 0)
        {
          if (++(pbuf->ackno[1]) == 0)
            {
              ++(pbuf->ackno[0]);
            }
        }
    }

  /* Swap port numbers. */

  tmp16          = pbuf->srcport;
  pbuf->srcport  = pbuf->destport;
  pbuf->destport = tmp16;

  /* Swap IP addresses. */

  uiphdr_ipaddr_copy(pbuf->destipaddr, pbuf->srcipaddr);
  uiphdr_ipaddr_copy(pbuf->srcipaddr, &dev->d_ipaddr);

  /* And send out the RST packet */

  uip_tcpsendcomplete(dev);
}
示例#6
0
void uip_udpsend(struct uip_driver_s *dev, struct uip_udp_conn *conn)
{
  struct uip_udpip_hdr *pudpbuf = UDPBUF;

  if (dev->d_sndlen > 0)
    {
      /* The total lenth 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 + UIP_IPUDPH_LEN;

      /* 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     = UIP_PROTO_UDP;
      pudpbuf->hoplimit    = conn->ttl;

      uip_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr);
      uip_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       = UIP_PROTO_UDP;

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

      /* Calculate IP checksum. */

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

#endif /* CONFIG_NET_IPv6 */

      /* Initialize the UDP header */

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

#ifdef CONFIG_NET_UDP_CHECKSUMS
      /* Calculate UDP checksum. */

      pudpbuf->udpchksum   = 0;
      pudpbuf->udpchksum   = ~(uip_udpchksum(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
      uip_stat.udp.sent++;
      uip_stat.ip.sent++;
#endif
    }