Exemplo n.º 1
0
uint16_t tcp_callback(FAR struct net_driver_s *dev,
                      FAR struct tcp_conn_s *conn, uint16_t flags)
{
  /* Preserve the TCP_ACKDATA, TCP_CLOSE, and TCP_ABORT in the response.
   * These is needed by uIP to handle responses and buffer state.  The
   * TCP_NEWDATA indication will trigger the ACK response, but must be
   * explicitly set in the callback.
   */

  nllvdbg("flags: %04x\n", flags);

  /* Perform the data callback.  When a data callback is executed from 'list',
   * the input flags are normally returned, however, the implementation
   * may set one of the following:
   *
   *   TCP_CLOSE   - Gracefully close the current connection
   *   TCP_ABORT   - Abort (reset) the current connection on an error that
   *                 prevents TCP_CLOSE from working.
   *
   * And/Or set/clear the following:
   *
   *   TCP_NEWDATA - May be cleared to indicate that the data was consumed
   *                 and that no further process of the new data should be
   *                 attempted.
   *   TCP_SNDACK  - If TCP_NEWDATA is cleared, then TCP_SNDACK may be set
   *                 to indicate that an ACK should be included in the response.
   *                 (In TCP_NEWDATA is cleared but TCP_SNDACK is not set, then
   *                 dev->d_len should also be cleared).
   */

  flags = devif_callback_execute(dev, conn, flags, conn->list);

  /* There may be no new data handler in place at them moment that the new
   * incoming data is received.  If the new incoming data was not handled, then
   * either (1) put the unhandled incoming data in the read-ahead buffer (if
   * enabled) or (2) suppress the ACK to the data in the hope that it will
   * be re-transmitted at a better time.
   */

  if ((flags & TCP_NEWDATA) != 0)
    {
      /* Data was not handled.. dispose of it appropriately */

      flags = tcp_data_event(dev, conn, flags);
    }

  /* Check if there is a connection-related event and a connection
   * callback.
   */

  if (((flags & TCP_CONN_EVENTS) != 0) && conn->connection_event)
    {
      /* Perform the callback */

      conn->connection_event(conn, flags);
    }

  return flags;
}
Exemplo n.º 2
0
void icmpv6_poll(FAR struct net_driver_s *dev)
{
  /* Setup for the application callback */

  dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + IPICMPv6_HDRLEN];
  dev->d_len     = 0;
  dev->d_sndlen  = 0;

  /* Perform the application callback */

  (void)devif_callback_execute(dev, NULL, ICMPv6_POLL, g_icmpv6_conn.list);
}
Exemplo n.º 3
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 */
}