Exemple #1
0
static int netdev_ifrioctl(FAR struct socket *psock, int cmd, struct ifreq *req)
{
  FAR struct uip_driver_s *dev;
  int ret = OK;

  nvdbg("cmd: %d\n", cmd);

  /* Find the network device associated with the device name
   * in the request data.
   */

  dev = netdev_findbyname(req->ifr_name);
  if (!dev)
    {
      ret = -EINVAL;
      goto errout;
    }

  /* Execute the command */

  switch (cmd)
    {
      case SIOCGIFADDR:     /* Get IP address */
        ioctl_getipaddr(&req->ifr_addr, &dev->d_ipaddr);
        break;

      case SIOCSIFADDR:     /* Set IP address */
        ioctl_ifdown(dev);
        ioctl_setipaddr(&dev->d_ipaddr, &req->ifr_addr);
        ioctl_ifup(dev);
        break;

      case SIOCGIFDSTADDR:  /* Get P-to-P address */
        ioctl_getipaddr(&req->ifr_dstaddr, &dev->d_draddr);
        break;

      case SIOCSIFDSTADDR:  /* Set P-to-P address */
        ioctl_setipaddr(&dev->d_draddr, &req->ifr_dstaddr);
        break;

      case SIOCGIFNETMASK:  /* Get network mask */
        ioctl_getipaddr(&req->ifr_addr, &dev->d_netmask);
        break;

      case SIOCSIFNETMASK:  /* Set network mask */
        ioctl_setipaddr(&dev->d_netmask, &req->ifr_addr);
        break;

      case SIOCGIFMTU:  /* Get MTU size */
        req->ifr_mtu = CONFIG_NET_BUFSIZE;
        break;

      /* MAC address operations only make sense if Ethernet is supported */

#ifdef CONFIG_NET_ETHERNET
      case SIOCGIFHWADDR:  /* Get hardware address */
        req->ifr_hwaddr.sa_family = AF_INETX;
        memcpy(req->ifr_hwaddr.sa_data, dev->d_mac.ether_addr_octet, IFHWADDRLEN);
        break;

      case SIOCSIFHWADDR:  /* Set hardware address -- will not take effect until ifup */
        req->ifr_hwaddr.sa_family = AF_INETX;
        memcpy(dev->d_mac.ether_addr_octet, req->ifr_hwaddr.sa_data, IFHWADDRLEN);
        break;
#endif

      case SIOCDIFADDR:  /* Delete IP address */
        ioctl_ifdown(dev);
        memset(&dev->d_ipaddr, 0, sizeof(uip_ipaddr_t));
        break;

      case SIOCGIFCOUNT:  /* Get number of devices */
        req->ifr_count = netdev_count();
        ret = -ENOSYS;
        break;

      case SIOCGIFBRDADDR:  /* Get broadcast IP address	*/
      case SIOCSIFBRDADDR:  /* Set broadcast IP address	*/
        ret = -ENOSYS;
        break;

#ifdef CONFIG_NET_ARPIOCTLS
      case SIOCSARP:  /* Set a ARP mapping */
      case SIOCDARP:  /* Delete an ARP mapping */
      case SIOCGARP:  /* Get an ARP mapping */
# error "IOCTL Commands not implemented"
#endif

      default:
        ret = -EINVAL;
        break;;
    }

errout:
  return ret;
}
int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream)
{
  FAR struct pollfd fds;
  int ret;

  /* Make sure that we are still connected */

  if (!ftpc_connected(session))
    {
      return ERROR;
    }

  /* Check if there is data waiting to be read from the cmd channel */

  fds.fd     = session->cmd.sd;
  fds.events = POLLIN;
  ret        = poll(&fds, 1, 0);
  if (ret > 0)
  {
    /* Read data from command channel */

    nvdbg("Flush cmd channel data\n");
    while (stream && fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0);
    return OK;
  }

  FTPC_SET_INTERRUPT(session);

  /* Send the Telnet interrupt sequence to abort the transfer:
   * <IAC IP><IAC DM>ABORT<CR><LF>
   */

  nvdbg("Telnet ABORt sequence\n");
  ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_IP); /* Interrupt process */
  ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_DM); /* Telnet synch signal */
  ftpc_sockprintf(&session->cmd, "ABOR\r\n");                    /* Abort */
  ftpc_sockflush(&session->cmd);

  /* Read remaining bytes from connection */

  while (stream && fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0);

  /* Get the ABORt reply */

  fptc_getreply(session);

  /* Expected replys are: "226 Closing data connection" or
   * "426 Connection closed; transfer aborted"
   */

  if (session->code != 226 && session->code != 426)
    {
      nvdbg("Expected 226 or 426 reply\n");
    }
  else
    {
      /* Get the next reply */

      fptc_getreply(session);

     /* Expected replys are:  or "225 Data connection open; no transfer in progress"
      * "226 Closing data connection"
      */

     if (session->code != 226 && session->code != 225)
       {
         nvdbg("Expected 225 or 226 reply\n");
       }
    }

  return ERROR;
}
Exemple #3
0
void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize)
{
  struct sockaddr_in myaddr;
#ifdef CONFIG_NET_HAVE_SOLINGER
  struct linger ling;
#endif
  pthread_t child;
  pthread_attr_t attr;
  socklen_t addrlen;
  int listensd;
  int acceptsd;
  int ret;

  /* Create a new TCP socket to use to listen for connections */

  listensd = uip_listenon(portno);
  if (listensd < 0)
    {
      return;
    }

  /* Begin serving connections */

  for (;;)
    {
      /* Accept the next connectin */

      addrlen = sizeof(struct sockaddr_in);
      acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
      if (acceptsd < 0)
        {
          ndbg("accept failure: %d\n", errno);
          break;
        }

      nvdbg("Connection accepted -- spawning sd=%d\n", acceptsd);

      /* Configure to "linger" until all data is sent when the socket is
       * closed.
       */

#ifdef CONFIG_NET_HAVE_SOLINGER
      ling.l_onoff  = 1;
      ling.l_linger = 30;     /* timeout is seconds */

      ret = setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger));
      if (ret < 0)
        {
          close(acceptsd);
          ndbg("setsockopt SO_LINGER failure: %d\n", errno);
          break;
        }
#endif

      /* Create a thread to handle the connection.  The socket descriptor is
       * provided in as the single argument to the new thread.
       */

      (void)pthread_attr_init(&attr);
      (void)pthread_attr_setstacksize(&attr, stacksize);

      ret = pthread_create(&child, &attr, handler, (void*)acceptsd);
      if (ret != 0)
        {
          /* Close the connection */

          close(acceptsd);
          ndbg("pthread_create failed\n");

          if (ret == EAGAIN)
            {
              /* Lacked resources to create a new thread. This is a temporary
               * condition, so we close this peer, but keep serving for
               * other connections.
               */

              continue;
            }

          /* Something is very wrong... Break out and stop serving */

          break;
        }

      /* We don't care when/how the child thread exits so detach from it now
       * in order to avoid memory leaks.
       */

      (void)pthread_detach(child);
    }

  /* Close the listerner socket */

  close(listensd);
}
int icmpv6_autoconfig(FAR struct net_driver_s *dev)
{
#ifndef CONFIG_NET_ETHERNET
  /* Only Ethernet supported for now */

  ndbg("ERROR: Only Ethernet is supported\n");
  return -ENOSYS;

#else /* CONFIG_NET_ETHERNET */
  struct icmpv6_rnotify_s notify;
  net_ipv6addr_t lladdr;
  net_lock_t save;
  int retries;
  int ret;

  /* Sanity checks */

  DEBUGASSERT(dev);
  nvdbg("Auto-configuring %s\n", dev->d_ifname);

#ifdef CONFIG_NET_MULTILINK
  /* Only Ethernet devices are supported for now */

  if (dev->d_lltype != NET_LL_ETHERNET)
    {
      ndbg("ERROR: Only Ethernet is supported\n");
      return -ENOSYS;
    }
#endif

  /* The interface should be in the down state */

  save = net_lock();
  netdev_ifdown(dev);
  net_unlock(save);

  /* IPv6 Stateless Autoconfiguration
   * Reference: http://www.tcpipguide.com/free/t_IPv6AutoconfigurationandRenumbering.htm
   *
   * The following is a summary of the steps a device takes when using
   * stateless auto-configuration:
   *
   * 1. Link-Local Address Generation: The device generates a link-local
   *    address. Recall that this is one of the two types of local-use IPv6
   *    addresses. Link-local addresses have "1111 1110 10" for the first
   *    ten bits. The generated address uses those ten bits followed by 54
   *    zeroes and then the 64 bit interface identifier. Typically this
   *    will be derived from the data link layer (MAC) address.
   *
   *    IEEE 802 MAC addresses, used by Ethernet and other IEEE 802 Project
   *    networking technologies, have 48 bits.  The IEEE has also defined a
   *    format called the 64-bit extended unique identifier, abbreviated
   *    EUI-64.  To get the modified EUI-64 interface ID for a device, you
   *    simply take the EUI-64 address and change the 7th bit from the left
   *    (the"universal/local" or "U/L" bit) from a zero to a one.
   *
   *    128  112  96   80    64   48   32   16
   *    ---- ---- ---- ----  ---- ---- ---- ----
   *    fe80 0000 0000 0000  0000 xxxx xxxx xxxx
   */

  lladdr[0] = HTONS(0xfe80);                        /* 10-bit address + 6 zeroes */
  memset(&lladdr[1], 0, 4 * sizeof(uint16_t));      /* 64 more zeroes */
  memcpy(&lladdr[5], dev->d_mac.ether_addr_octet,
        sizeof(struct ether_addr));                 /* 48-bit Ethernet address */

  nvdbg("lladdr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
        lladdr[0], lladdr[1], lladdr[2], lladdr[3],
        lladdr[4], lladdr[6], lladdr[6], lladdr[7]);

#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
  /* Bring the interface up with no IP address */

  save = net_lock();
  netdev_ifup(dev);
  net_unlock(save);

  /* 2. Link-Local Address Uniqueness Test: The node tests to ensure that
   *    the address it generated isn't for some reason already in use on the
   *    local network. (This is very unlikely to be an issue if the link-local
   *    address came from a MAC address but more likely if it was based on a
   *    generated token.) It sends a Neighbor Solicitation message using the
   *    Neighbor Discovery (ND) protocol. It then listens for a Neighbor
   *    Advertisement in response that indicates that another device is
   *    already using its link-local address; if so, either a new address
   *    must be generated, or auto-configuration fails and another method
   *    must be employed.
   */

  ret = icmpv6_neighbor(lladdr);

  /* Take the interface back down */

  save = net_lock();
  netdev_ifdown(dev);
  net_unlock(save);

  if (ret == OK)
    {
      /* Hmmm... someone else responded to our Neighbor Solicitation.  We
       * have not back-up plan in place.  Just bail.
       */

      ndbg("ERROR: IP conflict\n");
      return -EEXIST;
    }
#endif

  /* 3. Link-Local Address Assignment: Assuming the uniqueness test passes,
   *    the device assigns the link-local address to its IP interface. This
   *    address can be used for communication on the local network, but not
   *    on the wider Internet (since link-local addresses are not routed).
   */

  save = net_lock();
  net_ipv6addr_copy(dev->d_ipv6addr, lladdr);

  /* Bring the interface up with the new, temporary IP address */

  netdev_ifup(dev);

  /* 4. Router Contact: The node next attempts to contact a local router for
   *    more information on continuing the configuration. This is done either
   *    by listening for Router Advertisement messages sent periodically by
   *    routers, or by sending a specific Router Solicitation to ask a router
   *    for information on what to do next.
   */

  for (retries = 0; retries < CONFIG_ICMPv6_AUTOCONF_MAXTRIES; retries++)
    {
      /* Set up the Router Advertisement BEFORE we send the Router
       * Solicitation.
       */

      icmpv6_rwait_setup(dev, &notify);

      /* Send the ICMPv6 Router solicitation message */

      ret = icmpv6_send_message(dev, false);
      if (ret < 0)
        {
          ndbg("ERROR: Failed send router solicitation: %d\n", ret);
          break;
        }

      /* Wait to receive the Router Advertisement message */

      ret = icmpv6_wait_radvertise(dev, &notify, &save);
      if (ret != -ETIMEDOUT)
        {
          /* ETIMEDOUT is the only expected failure.  We will retry on that
           * case only.
           */

          break;
        }

      nvdbg("Timed out... retrying %d\n", retries + 1);
    }

  /* Check for failures.  Note:  On successful return, the network will be 
   * in the down state, but not in the event of failures.
   */

  if (ret < 0)
    {
      ndbg("ERROR: Failed to get the router advertisement: %d (retries=%d)\n",
           ret, retries);

      /* Claim the link local address as ours by sending the ICMPv6 Neighbor
       * Advertisement message.
       */

      ret = icmpv6_send_message(dev, true);
      if (ret < 0)
        {
          ndbg("ERROR: Failed send neighbor advertisement: %d\n", ret);
          netdev_ifdown(dev);
        }

      /* No off-link communications; No router address. */

      net_ipv6addr_copy(dev->d_ipv6draddr, g_ipv6_allzeroaddr);

      /* Set a netmask for the local link address */

      net_ipv6addr_copy(dev->d_ipv6netmask, g_ipv6_llnetmask);

      /* Leave the network up and return success (even though things did not
       * work out quite the way we wanted).
       */

      net_unlock(save);
      return ret;
    }

  /* 5. Router Direction: The router provides direction to the node on how to
   *    proceed with the auto-configuration. It may tell the node that on this
   *    network "stateful" auto-configuration is in use, and tell it the
   *    address of a DHCP server to use. Alternately, it will tell the host
   *    how to determine its global Internet address.
   *
   * 6. Global Address Configuration: Assuming that stateless auto-
   *    configuration is in use on the network, the host will configure
   *    itself with its globally-unique Internet address. This address is
   *    generally formed from a network prefix provided to the host by the
   *    router, combined with the device's identifier as generated in the
   *    first step.
   */

  /* On success, the new address was already set (in icmpv_rnotify()).  We
   * need only to bring the network back to the up state and return success.
   */

  netdev_ifup(dev);
  net_unlock(save);
  return OK;
#endif /* CONFIG_NET_ETHERNET */
}
Exemple #5
0
time_t tdate_parse(char *str)
{
#ifdef TDATE_PARSE_WORKS /* REVISIT -- doesn't work */
  struct tm tm;
  char *cp;
  char str_mon[32];
  int tm_year;
  int tm_mday;
  int tm_hour;
  int tm_min;
  int tm_sec;
  long tm_mon;
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
  char str_wday[32];
  long tm_wday;
#endif

  nvdbg("str: \"%s\"\n", str);

  /* Initialize. */

  (void)memset((char *)&tm, 0, sizeof(struct tm));

  /* Skip initial whitespace ourselves - sscanf is clumsy at this. */

  for (cp = str; *cp == ' ' || *cp == '\t'; ++cp)
    {
      continue;
    }

  /* And do the sscanfs.  WARNING: you can add more formats here, but be
   * careful! You can easily screw up the parsing of existing formats when
   * you add new ones.  The order is important. */

  /* DD-mth-YY HH:MM:SS GMT */
  if (sscanf(cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
             &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
             &tm_sec) == 6 && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_mday = tm_mday;
      tm.tm_mon  = tm_mon;
      tm.tm_year = tm_year;
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
    }

  /* DD mth YY HH:MM:SS GMT */
  else if (sscanf(cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
                  &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                  &tm_sec) == 6 && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_mday = tm_mday;
      tm.tm_mon  = tm_mon;
      tm.tm_year = tm_year;
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
    }

  /* HH:MM:SS GMT DD-mth-YY */
  else if (sscanf(cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
                  &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
                  &tm_year) == 6 && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
      tm.tm_mday = tm_mday;
      tm.tm_mon  = tm_mon;
      tm.tm_year = tm_year;
    }

  /* HH:MM:SS GMT DD mth YY */
  else if (sscanf(cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
                  &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
                  &tm_year) == 6 && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
      tm.tm_mday = tm_mday;
      tm.tm_mon  = tm_mon;
      tm.tm_year = tm_year;
    }

#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
  /* wdy, DD-mth-YY HH:MM:SS GMT */
  else if (sscanf(cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
                  str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                  &tm_sec) == 7 &&
           scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_wday = tm_wday;
      tm.tm_mday = tm_mday;
      tm.tm_mon  = tm_mon;
      tm.tm_year = tm_year;
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
    }
#endif /* Day of week not yet supported by NuttX */

#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
  /* wdy, DD mth YY HH:MM:SS GMT */
  else if (sscanf(cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
                  str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                  &tm_sec) == 7 &&
           scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_wday = tm_wday;
      tm.tm_mday = tm_mday;
      tm.tm_mon  = tm_mon;
      tm.tm_year = tm_year;
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
    }
#endif /* Day of week not yet supported by NuttX */

#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
  /* wdy mth DD HH:MM:SS GMT YY */
  else if (sscanf(cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
                  str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
                  &tm_year) == 7 &&
           scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon))
    {
      tm.tm_wday = tm_wday;
      tm.tm_mon  = tm_mon;
      tm.tm_mday = tm_mday;
      tm.tm_hour = tm_hour;
      tm.tm_min  = tm_min;
      tm.tm_sec  = tm_sec;
      tm.tm_year = tm_year;
    }
#endif /* Day of week not yet supported by NuttX */
  else
    {
      return (time_t) - 1;
    }

  if (tm.tm_year > 1900)
    {
      tm.tm_year -= 1900;
    }
  else if (tm.tm_year < 70)
    {
      tm.tm_year += 100;
    }

  return mktime(&tm);
#else
  return 0; // for now
#endif
}
Exemple #6
0
static inline int dhcpd_request(void)
{
  struct lease_s *lease;
  in_addr_t ipaddr = 0;
  uint8_t response = 0;

  /* Check if this client already holds a lease.  This can happen when the client (1)
   * the IP is reserved for the client from a previous offer, or (2) the client is
   * re-initializing or rebooting while the lease is still valid.
   */

  lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr);
  if (lease)
    {
      /* Yes.. the client already holds a lease.  Verify that the request is consistent
       * with the existing lease (host order).
       */

      ipaddr = dhcp_leaseipaddr(lease);
      nvdbg("Lease ipaddr: %08x Server IP: %08x Requested IP: %08x\n",
            ipaddr, g_state.ds_optserverip, g_state.ds_optreqip);

      if (g_state.ds_optserverip)
        {
          /* ACK if the serverip is correct and the requested IP address is the one
           * already offered to the client.
           */

          if (g_state.ds_optserverip == ntohl(g_state.ds_serverip) &&
             (g_state.ds_optreqip != 0 || g_state.ds_optreqip == ipaddr))
            {
              response = DHCPACK;
            }
          else
            {
              response = DHCPNAK;
            }
        }

      /* We have the lease and no server IP was requested. Was a specific IP address
       * requested? (host order)
       */

      else if (g_state.ds_optreqip)
        {
          /* Yes..ACK if the requested IP address is the one already leased.
           * Both addresses are in host order.
           */

          if (ipaddr == g_state.ds_optreqip)
            {
              response = DHCPACK;
            }
          else
            {
              response = DHCPNAK;
            }
        }

      /* The client has specified neither a server IP nor requested IP address */

      else
        {
          /* ACK if the IP used by the client is the one already assigned to it.
           * NOTE ipaddr is in host order; ciaddr is network order!
           */

          uint32_t tmp = htonl(ipaddr);
          if (memcmp(&tmp, g_state.ds_inpacket.ciaddr, 4) == 0)
            {
              response = DHCPACK;
            }
          else
            {
              response = DHCPNAK;
            }
        }
    }

  /* The client does not hold a lease (referenced by its MAC address) and is
   * requesting a specific IP address that was, apparently, never offered to
   * to the client.  Perform some sanity checks before sending the NAK.
   */

  else if (g_state.ds_optreqip && !g_state.ds_optserverip)
    {
      nvdbg("Server IP: %08x Requested IP: %08x\n",
            g_state.ds_optserverip, g_state.ds_optreqip);

      /* Is this IP address already assigned? */

      lease = dhcpd_findbyipaddr(g_state.ds_optreqip);
      if (lease)
        {
          /* Yes.. Send NAK unless the lease has expired */

          if (!dhcpd_leaseexpired(lease))
            {
              response = DHCPNAK;
            }
        }

      /* No.. is the requested IP address in range? NAK if not */

      else if (g_state.ds_optreqip < CONFIG_NETUTILS_DHCPD_STARTIP ||
               g_state.ds_optreqip > CONFIG_NETUTILS_DHCP_OPTION_ENDIP)
        {
          response = DHCPNAK;
        }
    }

  /* Otherwise, the client does not hold a lease and is not requesting any
   * specific IP address.
   */

  /* Finally, either (1) send the ACK, (2) send a NAK, or (3) remain silent
   * based on the checks above.
   */

  if (response == DHCPACK)
    {
      nvdbg("ACK IP %08lx\n", (long)ipaddr);
      dhcpd_sendack(ipaddr);
    }
  else if (response == DHCPNAK)
    {
      nvdbg("NAK IP %08lx\n", (long)ipaddr);
      dhcpd_sendnak();
    }
  else
    {
      nvdbg("Remaining silent IP %08lx\n", (long)ipaddr);
    }

  return OK;
}
Exemple #7
0
static int dhcpd_sendpacket(int bbroadcast)
{
  struct sockaddr_in addr;
  in_addr_t ipaddr;
  int sockfd;
  int len;
  int ret = ERROR;

#ifdef CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST
  /* This is a hack.  I've had problems with Windows machines responding
   * to unicast.  I think this is associated with a Windows registry key in
   * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DHCPServer\Parameters:
   * The IgnoreBroadcastFlag value controls this behavior:  A value of 1 will
   * cause the server to ignore the client broadcast flag and always respond
   * with multicast; the value 0 to allows clients to request unicast.
   */

   ipaddr = INADDR_BROADCAST;
#else
  /* Determine which address to respond to (or if we need to broadcast the response)
   *
   * (1) If he caller know that it needs to multicast the response, it will set bbroadcast.
   * (2) Otherwise, if the client already has and address (ciaddr), then use that for uni-cast
   * (3) Broadcast if the client says it can't handle uni-cast (BOOTP_BROADCAST set)
   * (4) Otherwise, the client claims it can handle the uni-casst response and we
   *     will uni-cast to the offered address (yiaddr).
   *
   * NOTE: We really should also check the giaddr field.  If no zero, the server should
   * send any return messages to the 'DHCP server' port on the BOOTP relay agent whose
   * address appears in 'giaddr'.
   */

  if (bbroadcast)
    {
      ipaddr = INADDR_BROADCAST;
    }
  else if (memcmp(g_state.ds_outpacket.ciaddr, g_anyipaddr, 4) != 0)
    {
      dhcpd_arpupdate((uint16_t*)g_state.ds_outpacket.ciaddr, g_state.ds_outpacket.chaddr);
      memcpy(&ipaddr, g_state.ds_outpacket.ciaddr, 4);
    }
  else if (g_state.ds_outpacket.flags & HTONS(BOOTP_BROADCAST))
    {
      ipaddr = INADDR_BROADCAST;
    }
  else
    {
      dhcpd_arpupdate((uint16_t*)g_state.ds_outpacket.yiaddr, g_state.ds_outpacket.chaddr);
      memcpy(&ipaddr, g_state.ds_outpacket.yiaddr, 4);
    }
#endif

  /* Create a socket to respond with a packet to the client.  We
   * cannot re-use the listener socket because it is not bound correctly
   */

  sockfd = dhcpd_openresponder();
  if (sockfd >= 0)
    {
      /* Then send the reponse to the DHCP client port at that address */

      memset(&addr, 0, sizeof(struct sockaddr_in));
      addr.sin_family      = AF_INET;
      addr.sin_port        = HTONS(DHCP_CLIENT_PORT);
      addr.sin_addr.s_addr = ipaddr;

      /* Send the minimum sized packet that includes the END option */

      len = (g_state.ds_optend - (uint8_t*)&g_state.ds_outpacket) + 1;
      nvdbg("sendto %08lx:%04x len=%d\n",
            (long)ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port), len);

      ret = sendto(sockfd, &g_state.ds_outpacket, len, 0,
                   (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
      close(sockfd);
    }

  return ret;
}
Exemple #8
0
static inline void slip_receive(FAR struct slip_driver_s *priv)
{
  uint8_t ch;

  /* Copy the data data from the hardware to to the RX buffer until we
   * put together a whole packet. Make sure not to copy them into the
   * packet if we run out of room.
   */

  nvdbg("Receiving packet\n");
  for (;;)
    {
      /* Get the next character in the stream. */

      ch = slip_getc(priv);

      /* Handle bytestuffing if necessary */
 
      switch (ch)
        {
        /* If it's an END character then we're done with the packet.
         * (OR we are just starting a packet)
         */

        case SLIP_END:
          nvdbg("END\n");

          /* A minor optimization: if there is no data in the packet, ignore
           * it. This is meant to avoid bothering IP with all the empty
           * packets generated by the duplicate END characters which are in
           * turn sent to try to detect line noise.
           */

          if (priv->rxlen > 0)
            {
              nvdbg("Received packet size %d\n", priv->rxlen);
              return;
            }
          break;

        /* if it's the same code as an ESC character, wait and get another
         * character and then figure out what to store in the packet based
         * on that.
         */

        case SLIP_ESC:
          nvdbg("ESC\n");
          ch = slip_getc(priv);

          /* if "ch" is not one of these two, then we have a protocol
           * violation.  The best bet seems to be to leave the byte alone
           * and just stuff it into the packet
           */

          switch (ch)
            {
            case SLIP_ESC_END:
              nvdbg("ESC-END\n");
              ch = SLIP_END;
              break;
             case SLIP_ESC_ESC:
              nvdbg("ESC-ESC\n");
              ch = SLIP_ESC;
              break;
            default:
              ndbg("ERROR: Protocol violation: %02x\n", ch);
              break;
            }

          /* Here we fall into the default handler and let it store the
           * character for us
           */

        default:
          if (priv->rxlen < CONFIG_NET_BUFSIZE+2)
            {
              priv->rxbuf[priv->rxlen++] = ch;
            }
          break;
        }
    }
}
Exemple #9
0
static int slip_rxtask(int argc, char *argv[])
{
  FAR struct slip_driver_s *priv;
  unsigned int index = *(argv[1]) - '0';
  uip_lock_t flags;
  int ch;

  ndbg("index: %d\n", index);
  DEBUGASSERT(index < CONFIG_SLIP_NINTERFACES);

  /* Get our private data structure instance and wake up the waiting
   * initialization logic.
   */

  priv = &g_slip[index];
  slip_semgive(priv);

  /* Loop forever */

  for (;;)
    {
      /* Wait for the next character to be available on the input stream. */

      nvdbg("Waiting...\n");
      ch = slip_getc(priv);

      /* Ignore any input that we receive before the interface is up. */

      if (!priv->bifup)
        {
          continue;
        }

      /* We have something...
       *
       * END characters may appear at packet boundaries BEFORE as well as
       * after the beginning of the packet.  This is normal and expected.
       */

      if (ch == SLIP_END)
        {
          priv->rxlen = 0;
        }

      /* Otherwise, we are in danger of being out-of-sync.  Apparently the
       * leading END character is optional.  Let's try to continue.
       */

      else
        {
          priv->rxbuf[0] = (uint8_t)ch;
          priv->rxlen    = 1;
        }

      /* Copy the data data from the hardware to priv->rxbuf until we put
       * together a whole packet.
       */

      slip_receive(priv);
      SLIP_STAT(priv, received);

      /* All packets are assumed to be IP packets (we don't have a choice..
       * there is no Ethernet header containing the EtherType).  So pass the
       * received packet on for IP processing -- but only if it is big
       * enough to hold an IP header.
       */

      if (priv->rxlen >= UIP_IPH_LEN)
        {
          /* Handle the IP input.  Get exclusive access to uIP. */

          slip_semtake(priv);
          priv->dev.d_buf = priv->rxbuf;
          priv->dev.d_len = priv->rxlen;

          flags = uip_lock();
          uip_input(&priv->dev);

          /* If the above function invocation resulted in data that should
           * be sent out on the network, the field  d_len will set to a
           * value > 0.  NOTE that we are transmitting using the RX buffer!
           */

          if (priv->dev.d_len > 0)
            {
              slip_transmit(priv); 
            }
          uip_unlock(flags);
          slip_semgive(priv);
        }
      else
        {
          SLIP_STAT(priv, rxsmallpacket);
        }
    }

  /* We won't get here */

  return OK;
}
Exemple #10
0
int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
                     FAR socklen_t *addrlen, FAR void **newconn)
{
    FAR struct tcp_conn_s *conn;
    struct accept_s state;
    int ret;

    DEBUGASSERT(psock && newconn);

    /* Check the backlog to see if there is a connection already pending for
     * this listener.
     */

    conn = (FAR struct tcp_conn_s *)psock->s_conn;

#ifdef CONFIG_NET_TCPBACKLOG
    state.acpt_newconn = tcp_backlogremove(conn);
    if (state.acpt_newconn)
    {
        /* Yes... get the address of the connected client */

        nvdbg("Pending conn=%p\n", state.acpt_newconn);
        accept_tcpsender(psock, state.acpt_newconn, addr, addrlen);
    }

    /* In general, this uIP-based implementation will not support non-blocking
     * socket operations... except in a few cases:  Here for TCP accept with
     * backlog enabled.  If this socket is configured as non-blocking then
     * return EAGAIN if there is no pending connection in the backlog.
     */

    else if (_SS_ISNONBLOCK(psock->s_flags))
    {
        return -EAGAIN;
    }
    else
#endif
    {
        /* Set the socket state to accepting */

        psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT);

        /* Perform the TCP accept operation */

        /* Initialize the state structure.  This is done with interrupts
         * disabled because we don't want anything to happen until we
         * are ready.
         */

        state.acpt_sock       = psock;
        state.acpt_addr       = addr;
        state.acpt_addrlen    = addrlen;
        state.acpt_newconn    = NULL;
        state.acpt_result     = OK;
        sem_init(&state.acpt_sem, 0, 0);

        /* Set up the callback in the connection */

        conn->accept_private  = (FAR void *)&state;
        conn->accept          = accept_interrupt;

        /* Wait for the send to complete or an error to occur:  NOTES: (1)
         * net_lockedwait will also terminate if a signal is received, (2)
         * interrupts may be disabled!  They will be re-enabled while the
         * task sleeps and automatically re-enabled when the task restarts.
         */

        ret = net_lockedwait(&state.acpt_sem);
        if (ret < 0)
        {
            /* The value returned by net_lockedwait() the same as the value
             * returned by sem_wait():  Zero (OK) is returned on success; -1
             * (ERROR) is returned on a failure with the errno value set
             * appropriately.
             *
             * We have to preserve the errno value here because it may be
             * altered by intervening operations.
             */

            ret = -get_errno();
            DEBUGASSERT(ret < 0);
        }

        /* Make sure that no further interrupts are processed */

        conn->accept_private = NULL;
        conn->accept         = NULL;

        sem_destroy(&state. acpt_sem);

        /* Set the socket state to idle */

        psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);

        /* Check for a errors.  Errors are signalled by negative errno values
         * for the send length.
         */

        if (state.acpt_result != 0)
        {
            DEBUGASSERT(state.acpt_result > 0);
            return -state.acpt_result;
        }

        /* If net_lockedwait failed, then we were probably reawakened by a
         * signal. In this case, logic above will have set 'ret' to the
         * errno value returned by net_lockedwait().
         */

        if (ret < 0)
        {
            return ret;
        }
    }

    *newconn = (FAR void *)state.acpt_newconn;
    return OK;
}
Exemple #11
0
static int slip_transmit(FAR struct slip_driver_s *priv)
{
  uint8_t *src;
  uint8_t *start;
  uint8_t  esc;
  int      remaining;
  int      len;

  /* Increment statistics */

  nvdbg("Sending packet size %d\n", priv->dev.d_len);
  SLIP_STAT(priv, transmitted);

  /* Send an initial END character to flush out any data that may have
   * accumulated in the receiver due to line noise
   */

  slip_putc(priv, SLIP_END);

  /* For each byte in the packet, send the appropriate character sequence */

  src       = priv->dev.d_buf;
  remaining = priv->dev.d_len;
  start     = src;
  len       = 0;
  
  while (remaining-- > 0)
    {
      switch (*src)
        {
          /* If it's the same code as an END character, we send a special two
           * character code so as not to make the receiver think we sent an
           * END
           */

          case SLIP_END:
            esc = SLIP_ESC_END;
            goto escape;

          /* If it's the same code as an ESC character, we send a special two
           * character code so as not to make the receiver think we sent an
           * ESC
           */

          case SLIP_ESC:
            esc = SLIP_ESC_ESC;

          escape:
            {
              /* Flush any unsent data */

              if (len > 0)
                {
                  slip_write(priv, start, len);

                  /* Reset */

                  start = src + 1;
                  len   = 0;
                }

              /* Then send the escape sequence */

              slip_putc(priv, SLIP_ESC);
              slip_putc(priv, esc);
            }
          break;

          /* otherwise, just bump up the count */

          default:
            len++;
            break;
        }

      /* Point to the next character in the packet */

      src++;
    }

  /* We have looked at every character in the packet.  Now flush any unsent
   * data
   */

  if (len > 0)
    {
      slip_write(priv, start, len);
    }

  /* And send the END token */

  slip_putc(priv, SLIP_END);
  return OK;
}
static int wget_base(FAR const char *url, FAR char *buffer, int buflen,
                     wget_callback_t callback, FAR void *arg,
                     FAR const char *posts, uint8_t mode)
{
  struct sockaddr_in server;
  struct wget_s ws;
  bool redirected;
  char *dest,post_size[8];
  int sockfd;
  int len,post_len;
  int ret;

  /* Initialize the state structure */

  memset(&ws, 0, sizeof(struct wget_s));
  ws.buffer = buffer;
  ws.buflen = buflen;
  ws.port   = 80;

  /* Parse the hostname (with optional port number) and filename from the URL */

  ret = uip_parsehttpurl(url, &ws.port,
                         ws.hostname, CONFIG_WEBCLIENT_MAXHOSTNAME,
                         ws.filename, CONFIG_WEBCLIENT_MAXFILENAME);
  if (ret != 0)
    {
      ndbg("Malformed HTTP URL: %s\n", url);
      set_errno(-ret);
      return ERROR;
    }

  nvdbg("hostname='%s' filename='%s'\n", ws.hostname, ws.filename);

  /* The following sequence may repeat indefinitely if we are redirected */

  do
    {
      /* Re-initialize portions of the state structure that could have
       * been left from the previous time through the loop and should not
       * persist with the new connection.
       */

      ws.httpstatus = HTTPSTATUS_NONE;
      ws.offset     = 0;
      ws.datend     = 0;
      ws.ndx        = 0;

      /* Create a socket */

      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0)
        {
          /* socket failed.  It will set the errno appropriately */

          ndbg("socket failed: %d\n", errno);
          return ERROR;
        }

      /* Get the server adddress from the host name */

      server.sin_family = AF_INET;
      server.sin_port   = htons(ws.port);
      ret = dns_gethostip(ws.hostname, &server.sin_addr.s_addr);
      if (ret < 0)
        {
          /* Could not resolve host (or malformed IP address) */

          ndbg("Failed to resolve hostname\n");
          ret = -EHOSTUNREACH;
          goto errout_with_errno;
        }

      /* Connect to server.  First we have to set some fields in the
       * 'server' address structure.  The system will assign me an arbitrary
       * local port that is not in use.
       */

      ret = connect(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
      if (ret < 0)
        {
          ndbg("connect failed: %d\n", errno);
          goto errout;
        }

      /* Send the GET request */

      dest = ws.buffer;
      if (mode == WGET_MODE_POST)
        {
          dest = wget_strcpy(dest, g_httppost);
        }
      else
        {
          dest = wget_strcpy(dest, g_httpget);
        }

#ifndef WGET_USE_URLENCODE
      dest = wget_strcpy(dest, ws.filename);
#else
    //dest = wget_urlencode_strcpy(dest, ws.filename);
      dest = wget_strcpy(dest, ws.filename);
#endif

      *dest++ = ISO_space;
      dest = wget_strcpy(dest, g_http10);
      dest = wget_strcpy(dest, g_httpcrnl);
      dest = wget_strcpy(dest, g_httphost);
      dest = wget_strcpy(dest, ws.hostname);
      dest = wget_strcpy(dest, g_httpcrnl);

      if (mode == WGET_MODE_POST)
        {
          dest = wget_strcpy(dest, g_httpform);
          dest = wget_strcpy(dest, g_httpcrnl);
          dest = wget_strcpy(dest, g_httpcontsize);

          /* Post content size */

          post_len = strlen((char *)posts);
          sprintf(post_size,"%d", post_len);
          dest = wget_strcpy(dest, post_size);
          dest = wget_strcpy(dest, g_httpcrnl);
        }

      dest = wget_strcpy(dest, g_httpuseragentfields);
      if (mode == WGET_MODE_POST)
        {
          dest = wget_strcpy(dest, (char *)posts);
        }

      len = dest - buffer;

      ret = send(sockfd, buffer, len, 0);
      if (ret < 0)
        {
          ndbg("send failed: %d\n", errno);
          goto errout;
        }

      /* Now loop to get the file sent in response to the GET.  This
       * loop continues until either we read the end of file (nbytes == 0)
       * or until we detect that we have been redirected.
       */

      ws.state   = WEBCLIENT_STATE_STATUSLINE;
      redirected = false;
      for(;;)
        {
          ws.datend = recv(sockfd, ws.buffer, ws.buflen, 0);
          if (ws.datend < 0)
            {
              ndbg("recv failed: %d\n", errno);
              ret = ws.datend;
              goto errout_with_errno;
            }
          else if (ws.datend == 0)
            {
              nvdbg("Connection lost\n");
              close(sockfd);
              break;
            }

          /* Handle initial parsing of the status line */

          ws.offset = 0;
          if (ws.state == WEBCLIENT_STATE_STATUSLINE)
            {
              ret = wget_parsestatus(&ws);
              if (ret < 0)
                {
                  goto errout_with_errno;
                }
            }

          /* Parse the HTTP data */

          if (ws.state == WEBCLIENT_STATE_HEADERS)
            {
              ret = wget_parseheaders(&ws);
              if (ret < 0)
                {
                  goto errout_with_errno;
                }
            }

          /* Dispose of the data payload */

          if (ws.state == WEBCLIENT_STATE_DATA)
            {
              if (ws.httpstatus != HTTPSTATUS_MOVED)
                {
                  /* Let the client decide what to do with the received file */

                  callback(&ws.buffer, ws.offset, ws.datend, &buflen, arg);
                }
              else
                {
                  redirected = true;
                  close(sockfd);
                  break;
                }
            }
        }
    }
  while (redirected);
  return OK;

errout_with_errno:
  set_errno(-ret);
errout:
  close(sockfd);
  return ERROR;
}
static inline int wget_parseheaders(struct wget_s *ws)
{
  int offset;
  int ndx;

  offset = ws->offset;
  ndx    = ws->ndx;

  while (offset < ws->datend)
    {
      ws->line[ndx] = ws->buffer[offset];
      if (ws->line[ndx] == ISO_nl)
        {
          /* We have an entire HTTP header line in s.line, so
           * we parse it.
           */

          if (ndx > 0) /* Should always be true */
            {
              if (ws->line[0] == ISO_cr)
                {
                  /* This was the last header line (i.e., and empty "\r\n"), so
                   * we are done with the headers and proceed with the actual
                   * data.
                   */

                  ws->state = WEBCLIENT_STATE_DATA;
                  goto exit;
               }

              /* Truncate the trailing \r\n */

              ws->line[ndx-1] = '\0';

              /* Check for specific HTTP header fields. */

#ifdef CONFIG_WEBCLIENT_GETMIMETYPE
              if (strncasecmp(ws->line, g_httpcontenttype, strlen(g_httpcontenttype)) == 0)
                {
                  /* Found Content-type field. */

                  char *dest = strchr(ws->line, ';');
                  if (dest != NULL)
                    {
                      *dest = 0;
                   }
                  strncpy(ws->mimetype, ws->line + strlen(g_httpcontenttype), sizeof(ws->mimetype));
                }
              else
#endif
              if (strncasecmp(ws->line, g_httplocation, strlen(g_httplocation)) == 0)
                {
                  /* Parse the new HTTP host and filename from the URL.  Note that
                   * the return value is ignored.  In the event of failure, we
                   * retain the current location.
                   */

                  (void)uip_parsehttpurl(ws->line + strlen(g_httplocation), &ws->port,
                                         ws->hostname, CONFIG_WEBCLIENT_MAXHOSTNAME,
                                         ws->filename, CONFIG_WEBCLIENT_MAXFILENAME);
                  nvdbg("New hostname='%s' filename='%s'\n", ws->hostname, ws->filename);
                }
            }

          /* We're done parsing this line, so we reset the index to the start
           * of the next line.
           */

          ndx = 0;
        }
      else
        {
          ndx++;
        }
      offset++;
    }

exit:
  ws->offset = offset;
  ws->ndx    = ndx;
  return OK;
}
Exemple #14
0
static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
                         FILE *stream, uint8_t how, uint8_t xfrmode)
{
  long offset = session->offset;
#ifdef CONFIG_DEBUG
  FAR char *rname;
  FAR char *str;
  int len;
#endif
  int ret;

  session->offset = 0;

  /* Were we asked to store a file uniquely?  Does the host support the STOU
   * command?
   */

  if (how == FTPC_PUT_UNIQUE && !FTPC_HAS_STOU(session))
    {
      /* We cannot store a file uniquely */

      return ERROR;
    }

  ftpc_xfrreset(session);
  FTPC_SET_PUT(session);

  /* Initialize for the transfer */

  ret = ftpc_xfrinit(session);
  if (ret != OK)
    {
      return ERROR;
    }

  ftpc_xfrmode(session, xfrmode);

  /* The REST command sets the start position in the file.  Some servers
   * allow REST immediately before STOR for binary files.
   */

  if (offset > 0)
    {
      ret = ftpc_cmd(session, "REST %ld", offset);
      session->size = offset;
    }

  /* Send the file using STOR, STOU, or APPE:
   *
   * - STOR request asks the server to receive the contents of a file from
   *   the data connection already established by the client.
   * - APPE is just like STOR except that, if the file already exists, the
   *   server appends the client's data to the file.
   * - STOU is just like STOR except that it asks the server to create a
   *   file under a new pathname selected by the server. If the server
   *   accepts STOU, it provides the pathname in a human-readable format in
   *   the text of its response.
   */

  switch (how)
    {
    case FTPC_PUT_UNIQUE:
      {
        ret = ftpc_cmd(session, "STOU %s", path);

        /* Check for "502 Command not implemented" */

        if (session->code == 502)
          {
            /* The host does not support the STOU command */

            FTPC_CLR_STOU(session);
            return ERROR;
          }

        /* Get the remote filename from the response */

#ifdef CONFIG_DEBUG
        str = strstr(session->reply, " for ");
        if (str)
          {
            str += 5;
            len = strlen(str);
            if (len)
              {
                if (*str == '\'')
                  {
                    rname = strndup(str+1, len-3);
                  }
                else
                  {
                    rname = strndup(str, len-1);
                    nvdbg("Unique filename is: %s\n",  rname);
                  }
                free(rname);
              }
          }
#endif
      }
      break;

    case FTPC_PUT_APPEND:
      ret = ftpc_cmd(session, "APPE %s", path);
      break;

    case FTPC_PUT_NORMAL:
    default:
      ret = ftpc_cmd(session, "STOR %s", path);
      break;
  }

  /* If the server is willing to create a new file under that name, or
   * replace an existing file under that name, it responds with a mark
   * using code 150:
   *
   * - "150 File status okay; about to open data connection"
   *
   * It then attempts to read the contents of the file from the data
   * connection, and closes the data connection. Finally it accepts the STOR
   * with:
   *
   * - "226 Closing data connection" if the entire file was successfully
   *    received and stored
   *
   * Or rejects the STOR with:
   *
   * - "425 Can't open data connection" if no TCP connection was established
   * - "426 Connection closed; transfer aborted" if the TCP connection was
   *    established but then broken by the client or by network failure
   * - "451 Requested action aborted: local error in processing",
   *   "452 - Requested action not taken", or "552 Requested file action
   *   aborted" if the server had trouble saving the file to disk.
   *
   * The server may reject the STOR request with:
   *
   * - "450 Requested file action not taken", "452 - Requested action not
   *   taken" or "553 Requested action not taken" without first responding
   *   with a mark. 
   */

  /* In active mode, we need to accept a connection on the data socket
   * (in passive mode, we have already connected the data channel to
   * the FTP server).
   */

  if (!FTPC_IS_PASSIVE(session))
    {
      ret = ftpc_sockaccept(&session->data);
      if (ret != OK)
        {
          ndbg("Data connection not accepted\n");
          return ERROR;
        }
    }

  /* Then perform the data transfer */

  if (xfrmode == FTPC_XFRMODE_ASCII)
    {
      ret = ftpc_sendtext(session, stream, session->data.outstream);
    }
  else
    {
      ret = ftpc_sendbinary(session, stream, session->data.outstream);
    }

  ftpc_sockflush(&session->data);
  ftpc_sockclose(&session->data);

  if (ret == 0)
    {
      fptc_getreply(session);
    }

  return OK;
}
static int netdev_ifrioctl(FAR struct socket *psock, int cmd,
                           FAR struct ifreq *req)
{
  FAR struct net_driver_s *dev;
  int ret = -EINVAL;

  nvdbg("cmd: %d\n", cmd);

  /* Execute the command */

  switch (cmd)
    {
#ifdef CONFIG_NET_IPv4
      case SIOCGIFADDR:  /* Get IP address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              ioctl_getipv4addr(&req->ifr_addr, dev->d_ipaddr);
              ret = OK;
            }
        }
        break;
#endif


#ifdef CONFIG_NET_IPv4
      case SIOCSIFADDR:  /* Set IP address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              netdev_ifdown(dev);
              ioctl_setipv4addr(&dev->d_ipaddr, &req->ifr_addr);
              netdev_ifup(dev);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv4
      case SIOCGIFDSTADDR:  /* Get P-to-P address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              ioctl_getipv4addr(&req->ifr_dstaddr, dev->d_draddr);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv4
      case SIOCSIFDSTADDR:  /* Set P-to-P address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              ioctl_setipv4addr(&dev->d_draddr, &req->ifr_dstaddr);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv4
      case SIOCGIFBRDADDR:  /* Get broadcast IP address */
      case SIOCSIFBRDADDR:  /* Set broadcast IP address */
        {
          ret = -ENOSYS;
        }
        break;
#endif

#ifdef CONFIG_NET_IPv4
      case SIOCGIFNETMASK:  /* Get network mask */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              ioctl_getipv4addr(&req->ifr_addr, dev->d_netmask);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv4
      case SIOCSIFNETMASK:  /* Set network mask */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              ioctl_setipv4addr(&dev->d_netmask, &req->ifr_addr);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCGLIFADDR:  /* Get IP address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              FAR struct lifreq *lreq = (FAR struct lifreq *)req;

              ioctl_getipv6addr(&lreq->lifr_addr, dev->d_ipv6addr);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCSLIFADDR:  /* Set IP address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              FAR struct lifreq *lreq = (FAR struct lifreq *)req;

              netdev_ifdown(dev);
              ioctl_setipv6addr(dev->d_ipv6addr, &lreq->lifr_addr);
              netdev_ifup(dev);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCGLIFDSTADDR:  /* Get P-to-P address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              FAR struct lifreq *lreq = (FAR struct lifreq *)req;

              ioctl_getipv6addr(&lreq->lifr_dstaddr, dev->d_ipv6draddr);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCSLIFDSTADDR:  /* Set P-to-P address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              FAR struct lifreq *lreq = (FAR struct lifreq *)req;

              ioctl_setipv6addr(dev->d_ipv6draddr, &lreq->lifr_dstaddr);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCGLIFBRDADDR:  /* Get broadcast IP address */
      case SIOCSLIFBRDADDR:  /* Set broadcast IP address */
        {
          ret = -ENOSYS;
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCGLIFNETMASK:  /* Get network mask */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              FAR struct lifreq *lreq = (FAR struct lifreq *)req;

              ioctl_getipv6addr(&lreq->lifr_addr, dev->d_ipv6netmask);
              ret = OK;
            }
        }
        break;
#endif

#ifdef CONFIG_NET_IPv6
      case SIOCSLIFNETMASK:  /* Set network mask */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              FAR struct lifreq *lreq = (FAR struct lifreq *)req;
              ioctl_setipv6addr(dev->d_ipv6netmask, &lreq->lifr_addr);
              ret = OK;
            }
        }
        break;
#endif

      case SIOCGLIFMTU:  /* Get MTU size */
      case SIOCGIFMTU:   /* Get MTU size */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              req->ifr_mtu = NET_DEV_MTU(dev);
              ret = OK;
            }
        }
        break;

#ifdef CONFIG_NET_ICMPv6_AUTOCONF
      case SIOCIFAUTOCONF:  /* Perform ICMPv6 auto-configuration */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              ret = icmpv6_autoconfig(dev);
            }
        }
        break;
#endif

      case SIOCSIFFLAGS:  /* Sets the interface flags */
        {
          /* Is this a request to bring the interface up? */

          dev = netdev_ifrdev(req);
          if (dev)
            {
              if (req->ifr_flags & IFF_UP)
                {
                  /* Yes.. bring the interface up */

                  netdev_ifup(dev);
                }

              /* Is this a request to take the interface down? */

              else if (req->ifr_flags & IFF_DOWN)
                {
                  /* Yes.. take the interface down */

                  netdev_ifdown(dev);
                }
            }

          ret = OK;
        }
        break;

      case SIOCGIFFLAGS:  /* Gets the interface flags */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              req->ifr_flags = dev->d_flags;
            }

          ret = OK;
        }
        break;

      /* MAC address operations only make sense if Ethernet is supported */

#ifdef CONFIG_NET_ETHERNET
      case SIOCGIFHWADDR:  /* Get hardware address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              req->ifr_hwaddr.sa_family = AF_INETX;
              memcpy(req->ifr_hwaddr.sa_data,
                     dev->d_mac.ether_addr_octet, IFHWADDRLEN);
              ret = OK;
            }
        }
        break;

      case SIOCSIFHWADDR:  /* Set hardware address -- will not take effect until ifup */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              memcpy(dev->d_mac.ether_addr_octet,
                     req->ifr_hwaddr.sa_data, IFHWADDRLEN);
              ret = OK;
            }
        }
        break;
#endif

      case SIOCDIFADDR:  /* Delete IP address */
        {
          dev = netdev_ifrdev(req);
          if (dev)
            {
              netdev_ifdown(dev);
#ifdef CONFIG_NET_IPv4
              dev->d_ipaddr = 0;
#endif
#ifdef CONFIG_NET_IPv6
              memset(&dev->d_ipv6addr, 0, sizeof(net_ipv6addr_t));
#endif
              ret = OK;
            }
        }
        break;

      case SIOCGIFCOUNT:  /* Get number of devices */
        {
          req->ifr_count = netdev_count();
          ret = -ENOSYS;
        }
        break;

#ifdef CONFIG_NET_ARPIOCTLS
      case SIOCSARP:  /* Set a ARP mapping */
      case SIOCDARP:  /* Delete an ARP mapping */
      case SIOCGARP:  /* Get an ARP mapping */
# error "IOCTL Commands not implemented"
#endif

#ifdef CONFIG_NETDEV_PHY_IOCTL
#ifdef CONFIG_ARCH_PHY_INTERRUPT
      case SIOCMIINOTIFY: /* Set up for PHY event notifications */
        {
          dev = netdev_ifrdev(req);
          if (dev && dev->d_ioctl)
            {
              struct mii_iotcl_notify_s *notify = &req->ifr_ifru.ifru_mii_notify;
              ret = dev->d_ioctl(dev, cmd, ((long)(uintptr_t)notify));
            }
        }
        break;
#endif

      case SIOCGMIIPHY: /* Get address of MII PHY in use */
      case SIOCGMIIREG: /* Get MII register via MDIO */
      case SIOCSMIIREG: /* Set MII register via MDIO */
        {
          dev = netdev_ifrdev(req);
          if (dev && dev->d_ioctl)
            {
              struct mii_ioctl_data_s *mii_data = &req->ifr_ifru.ifru_mii_data;
              ret = dev->d_ioctl(dev, cmd, ((long)(uintptr_t)mii_data));
            }
        }
        break;
#endif

      default:
        {
          ret = -ENOTTY;
        }
        break;;
    }

  return ret;
}
Exemple #16
0
static int handle_newconnect(struct timeval *tv, int listen_fd)
{
  struct connect_s *conn;
  ClientData client_data;

  /* This loops until the accept() fails, trying to start new connections as
   * fast as possible so we don't overrun the listen queue.
   */

  nvdbg("New connection(s) on listen_fd %d\n", listen_fd);
  for (;;)
    {
      /* Get the next free connection from the free list */

      conn = free_connections;

      /* Are there any free connections? */

      if (!conn)
        {
          /* Out of connection slots.  Run the timers, then the  existing
           * connections, and maybe we'll free up a slot  by the time we get
           * back here.
           */

          ndbg("No free connections\n");
          tmr_run(tv);
          return -1;
        }

      /* Make the httpd_conn if necessary */

      if (!conn->hc)
        {
          conn->hc = NEW(httpd_conn, 1);
          if (conn->hc == NULL)
            {
              ndbg("out of memory allocating an httpd_conn\n");
              exit(1);
            }

          conn->hc->initialized = 0;
        }

      /* Get the connection */

      switch (httpd_get_conn(hs, listen_fd, conn->hc))
        {
          /* Some error happened.  Run the timers, then the  existing
           * connections.  Maybe the error will clear.
           */

        case GC_FAIL:
          tmr_run(tv);
          return -1;

          /* No more connections to accept for now */

        case GC_NO_MORE:
          return 0;

        default:
          break;
        }

      nvdbg("New connection fd %d\n", conn->hc->conn_fd);

      /* Remove the connection entry from the free list */

      conn->conn_state        = CNST_READING;
      free_connections        = conn->next;
      conn->next              = NULL;

      client_data.p           = conn;
      conn->active_at         = tv->tv_sec;
      conn->wakeup_timer      = NULL;
      conn->linger_timer      = NULL;
      conn->offset            = 0;

      /* Set the connection file descriptor to no-delay mode */

      httpd_set_ndelay(conn->hc->conn_fd);
      fdwatch_add_fd(fw, conn->hc->conn_fd, conn);
    }
}
Exemple #17
0
static inline int dhcpd_discover(void)
{
  struct lease_s *lease;
  in_addr_t ipaddr;
  uint32_t leasetime = CONFIG_NETUTILS_DHCPD_LEASETIME;

  /* Check if the client is aleady in the lease table */

  lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr);
  if (lease)
    {
      /* Yes... get the remaining time on the lease */

#ifdef HAVE_LEASE_TIME
      if (!dhcpd_leaseexpired(lease))
        {
          leasetime = lease->expiry - dhcpd_time();
          if (leasetime < CONFIG_NETUTILS_DHCPD_MINLEASETIME)
            {
              leasetime = CONFIG_NETUTILS_DHCPD_MINLEASETIME;
            }
        }
#endif
      /* Get the IP address associated with the lease (host order) */

      ipaddr = dhcp_leaseipaddr(lease);
      nvdbg("Already have lease for IP %08lx\n", (long)ipaddr);
    }

  /* Check if the client has requested a specific IP address */

  else if (dhcpd_verifyreqip())
    {
      /* Use the requested IP address (host order) */

      ipaddr = g_state.ds_optreqip;
      nvdbg("User requested IP %08lx\n", (long)ipaddr);
    }
  else
    {
      /* No... allocate a new IP address (host order)*/

      ipaddr = dhcpd_allocipaddr();
      nvdbg("Allocated IP %08lx\n", (long)ipaddr);
    }

  /* Did we get any IP address? */

  if (!ipaddr)
    {
      /* Nope... return failure */

      ndbg("Failed to get IP address\n");
      return ERROR;
    }

  /* Reserve the leased IP for a shorter time for the offer */

  if (!dhcpd_setlease(g_state.ds_inpacket.chaddr, ipaddr, CONFIG_NETUTILS_DHCPD_OFFERTIME))
    {
      ndbg("Failed to set lease\n");
      return ERROR;
    }

  /* Check if the client has requested a specific lease time */

  (void)dhcpd_verifyreqleasetime(&leasetime);

  /* Send the offer response */

  return dhcpd_sendoffer(ipaddr, leasetime);
}
Exemple #18
0
static void handle_send(struct connect_s *conn, struct timeval *tv)
{
  httpd_conn *hc = conn->hc;
  int nwritten;
  int nread;

  /* Read until the entire file is sent -- this could take awhile!! */

  while (conn->offset < conn->end_offset)
    {
      nvdbg("offset: %d end_offset: %d bytes_sent: %d\n",
            conn->offset, conn->end_offset, conn->hc->bytes_sent);

      /* Fill the rest of the response buffer with file data */

      nread = read_buffer(conn);
      if (nread < 0)
        {
          ndbg("File read error: %d\n", errno);
          goto errout_clear_connection;
        }
      nvdbg("Read %d bytes, buflen %d\n", nread, hc->buflen);

      /* Send the buffer */

      if (hc->buflen > 0)
        {
          /* httpd_write does not return until all bytes have been sent
           * (or an error occurs).
           */

          nwritten = httpd_write(hc->conn_fd, hc->buffer, hc->buflen);
          if (nwritten < 0)
            {
              ndbg("Error sending %s: %d\n", hc->encodedurl, errno);
              goto errout_clear_connection;
            }

          /* We wrote one full buffer of data (httpd_write does not
           * return until the full buffer is written (or an error occurs).
           */

          conn->active_at       = tv->tv_sec;
          hc->buflen            = 0;

          /* And update how much of the file we wrote */

          conn->offset         += nwritten;
          conn->hc->bytes_sent += nwritten;
          nvdbg("Wrote %d bytes\n", nwritten);
        }
    }

  /* The file transfer is complete -- finish the connection */

  nvdbg("Finish connection\n");
  finish_connection(conn, tv);
  return;

errout_clear_connection:
  ndbg("Clear connection\n");
  clear_connection(conn, tv);
  return;
}
Exemple #19
0
int dhcpd_run(void)
{
  int sockfd;
  int nbytes;

  nvdbg("Started\n");

  /* Initialize everything to zero */

  memset(&g_state, 0, sizeof(struct dhcpd_state_s));

  /* Now loop indefinitely, reading packets from the DHCP server socket */

  sockfd = -1;
  for (;;)
    {
      /* Create a socket to listen for requests from DHCP clients */

      if (sockfd < 0)
        {
          sockfd = dhcpd_openlistener();
          if (sockfd < 0)
            {
                ndbg("Failed to create socket\n");
                break;
            }
        }

      /* Read the next g_state.ds_outpacket */

      nbytes = recv(sockfd, &g_state.ds_inpacket, sizeof(struct dhcpmsg_s), 0);
      if (nbytes < 0)
        {
          /* On errors (other EINTR), close the socket and try again */

          ndbg("recv failed: %d\n", errno);
          if (errno != EINTR)
            {
              close(sockfd);
              sockfd = -1;
            }
          continue;
        }

      /* Parse the incoming message options */

      if (!dhcpd_parseoptions())
        {
          /* Failed to parse the message options */

          ndbg("No msg type\n");
          continue;
        }

#ifdef CONFIG_NETUTILS_DHCPD_HOST
      /* Get the poor little uC a change to get its recvfrom in place */

      usleep(500*1000);
#endif

      /* Now process the incoming DHCP message by its message type */

      switch (g_state.ds_optmsgtype)
        {
          case DHCPDISCOVER:
            nvdbg("DHCPDISCOVER\n");
            dhcpd_discover();
            break;

          case DHCPREQUEST:
            nvdbg("DHCPREQUEST\n");
            dhcpd_request();
            break;

          case DHCPDECLINE:
            nvdbg("DHCPDECLINE\n");
            dhcpd_decline();
            break;

          case DHCPRELEASE:
            nvdbg("DHCPRELEASE\n");
            dhcpd_release();
            break;

          case DHCPINFORM: /* Not supported */
          default:
            ndbg("Unsupported message type: %d\n", g_state.ds_optmsgtype);
            break;
        }
    }

  return OK;
}
Exemple #20
0
int thttpd_main(int argc, char **argv)
{
  int num_ready;
  int cnum;
  FAR struct connect_s *conn;
  FAR httpd_conn *hc;
  httpd_sockaddr sa;
  struct timeval tv;
#ifdef CONFIG_THTTPD_DIR
  int ret;
#endif

  nvdbg("THTTPD started\n");

  /* Setup host address */

#ifdef  CONFIG_NET_IPv6
#  error "IPv6 support not yet implemented"
#else
  sa.sin_family      = AF_INET;
  sa.sin_port        = HTONS(CONFIG_THTTPD_PORT);
  sa.sin_addr.s_addr = HTONL(CONFIG_THTTPD_IPADDR);
#endif

  /* Initialize the fdwatch package to handle all of the configured
   * socket descriptors
   */

  fw = fdwatch_initialize(CONFIG_NSOCKET_DESCRIPTORS);
  if (!fw)
    {
      ndbg("fdwatch initialization failure\n");
      exit(1);
    }

  /* Switch directories again if requested */

#ifdef CONFIG_THTTPD_DATADIR
  if (chdir(CONFIG_THTTPD_DATADIR) < 0)
    {
      ndbg("chdir to %s: %d\n", CONFIG_THTTPD_DATADIR, errno);
      exit(1);
    }
#endif

  /* Initialize the timer package */

  tmr_init();

  /* Initialize the HTTP layer */

  nvdbg("Calling httpd_initialize()\n");
  hs = httpd_initialize(&sa);
  if (!hs)
    {
      ndbg("httpd_initialize() failed\n");
      exit(1);
    }

  /* Set up the occasional timer */

  if (tmr_create(NULL, occasional, JunkClientData, CONFIG_THTTPD_OCCASIONAL_MSEC * 1000L, 1) == NULL)
    {
      ndbg("tmr_create(occasional) failed\n");
      exit(1);
    }

  /* Set up the idle timer */

  if (tmr_create(NULL, idle, JunkClientData, 5 * 1000L, 1) == NULL)
    {
      ndbg("tmr_create(idle) failed\n");
      exit(1);

    }

  /* Initialize our connections table */

  connects = NEW(struct connect_s, AVAILABLE_FDS);
  if (connects == NULL)
    {
      ndbg("Out of memory allocating a struct connect_s\n");
      exit(1);
    }

  for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum)
    {
      connects[cnum].conn_state  = CNST_FREE;
      connects[cnum].next        = &connects[cnum + 1];
      connects[cnum].hc          = NULL;
    }

  connects[AVAILABLE_FDS-1].next = NULL;      /* End of link list */
  free_connections               = connects;  /* Beginning of the link list */

  if (hs != NULL)
    {
      if (hs->listen_fd != -1)
        {
          fdwatch_add_fd(fw, hs->listen_fd, NULL);
        }
    }

  /* Main loop */

  nvdbg("Entering the main loop\n");
  (void)gettimeofday(&tv, NULL);
  for (;;)
    {
      /* Do the fd watch */

      num_ready = fdwatch(fw, tmr_mstimeout(&tv));
      if (num_ready < 0)
        {
          if (errno == EINTR || errno == EAGAIN)
            {
              /* Not errors... try again */

              continue;
            }

          ndbg("fdwatch failed: %d\n", errno);
          exit(1);
        }

      (void)gettimeofday(&tv, NULL);

      if (num_ready == 0)
        {
          /* No fd's are ready - run the timers */

          tmr_run(&tv);
          continue;
        }

      /* Is it a new connection? */

      if (fdwatch_check_fd(fw, hs->listen_fd))
        {
          if (!handle_newconnect(&tv, hs->listen_fd))
            {
              /* Go around the loop and do another fdwatch, rather than
               * dropping through and processing existing connections.  New
               * connections always get priority.
               */

              continue;
            }
        }

      /* Find the connections that need servicing */

      while ((conn = (struct connect_s*)fdwatch_get_next_client_data(fw)) != (struct connect_s*)-1)
        {
          if (conn)
            {
              hc = conn->hc;
              if (fdwatch_check_fd(fw, hc->conn_fd))
                {
                  nvdbg("Handle conn_state %d\n", conn->conn_state);
                  switch (conn->conn_state)
                    {
                      case CNST_READING:
                        {
                          handle_read(conn, &tv);

                          /* If a GET request was received and a file is ready to
                           * be sent, then fall through to send the file.
                           */

                          if (conn->conn_state != CNST_SENDING)
                            {
                              break;
                            }
                        }

                      case CNST_SENDING:
                        {
                          /* Send a file -- this really should be performed on a
                           * separate thread to keep the serve from locking up during
                           * the write.
                           */

                          handle_send(conn, &tv);
                        }
                        break;

                      case CNST_LINGERING:
                        {
                          /* Linger close the connection */

                          handle_linger(conn, &tv);
                        }
                        break;
                    }
                }
            }
        }
      tmr_run(&tv);
    }

  /* The main loop terminated */

  shut_down();
  ndbg("Exiting\n");
  exit(0);
}
Exemple #21
0
int tftpget(const char *remote, const char *local, in_addr_t addr, bool binary)
{
  struct sockaddr_in server;  /* The address of the TFTP server */
  struct sockaddr_in from;    /* The address the last UDP message recv'd from */
  uint8_t *packet;            /* Allocated memory to hold one packet */
  uint16_t blockno = 0;       /* The current transfer block number */
  uint16_t opcode;            /* Received opcode */
  uint16_t rblockno;          /* Received block number */
  int len;                    /* Generic length */
  int sd;                     /* Socket descriptor for socket I/O */
  int fd;                     /* File descriptor for file I/O */
  int retry;                  /* Retry counter */
  int nbytesrecvd = 0;        /* The number of bytes received in the packet */
  int ndatabytes;             /* The number of data bytes received */
  int result = ERROR;         /* Assume failure */
  int ret;                    /* Generic return status */

  /* Allocate the buffer to used for socket/disk I/O */

  packet = (uint8_t*)zalloc(TFTP_IOBUFSIZE);
  if (!packet)
    {
      ndbg("packet memory allocation failure\n");
      set_errno(ENOMEM);
      goto errout;
    }

  /* Open the file for writing */

  fd = open(local, O_WRONLY|O_CREAT|O_TRUNC, 0666);
  if (fd < 0)
    {
      ndbg("open failed: %d\n", errno);
      goto errout_with_packet;
   }

  /* Initialize a UDP socket and setup the server addresss */

  sd = tftp_sockinit(&server, addr);
  if (sd < 0)
    {
      goto errout_with_fd;
    }

  /* Then enter the transfer loop.  Loop until the entire file has
   * been received or until an error occurs.
   */

  do
    {
      /* Increment the TFTP block number for the next transfer */

      blockno++;

      /* Send the next block if the file within a loop.  We will
       * retry up to TFTP_RETRIES times before giving up on the
       * transfer.
       */

      for (retry = 0; retry < TFTP_RETRIES; retry++)
        {
          /* Send the read request using the well-known port number before
           * receiving the first block.  Each retry of the first block will
           * re-send the request.
           */

          if (blockno == 1)
            {
              len             = tftp_mkreqpacket(packet, TFTP_RRQ, remote, binary);
              server.sin_port = HTONS(CONFIG_NETUTILS_TFTP_PORT);
              ret             = tftp_sendto(sd, packet, len, &server);
              if (ret != len)
                {
                  goto errout_with_sd;
                }

              /* Subsequent sendto will use the port number selected by the TFTP
               * server in the DATA packet.  Setting the server port to zero
               * here indicates that we have not yet received the server port number.
               */

              server.sin_port = 0;
            }

          /* Get the next packet from the server */

          nbytesrecvd = tftp_recvfrom(sd, packet, TFTP_IOBUFSIZE, &from);

          /* Check if anything valid was received */

          if (nbytesrecvd >= 0)
            {
              /* Verify the sender address and port number */

              if (server.sin_addr.s_addr != from.sin_addr.s_addr)
                {
                  nvdbg("Invalid address in DATA\n");
                  retry--;
                  continue;
                }

              if (server.sin_port && server.sin_port != from.sin_port)
                {
                  nvdbg("Invalid port in DATA\n");
                  len = tftp_mkerrpacket(packet, TFTP_ERR_UNKID, TFTP_ERRST_UNKID);
                  ret = tftp_sendto(sd, packet, len, &from);
                  retry--;
                  continue;
                }

              /* Parse the incoming DATA packet */

              if (nbytesrecvd < TFTP_DATAHEADERSIZE ||
                  tftp_parsedatapacket(packet, &opcode, &rblockno) != OK ||
                  blockno != rblockno)
                {
                  nvdbg("Parse failure\n");
                  if (opcode > TFTP_MAXRFC1350)
                    {
                      len = tftp_mkerrpacket(packet, TFTP_ERR_ILLEGALOP, TFTP_ERRST_ILLEGALOP);
                      ret = tftp_sendto(sd, packet, len, &from);
                    }
                  continue;
                }

              /* Replace the server port to the one in the good data response */

              if (!server.sin_port)
                {
                  server.sin_port = from.sin_port;
                }

              /* Then break out of the loop */

              break;
            }
        }

      /* Did we exhaust all of the retries? */

      if (retry == TFTP_RETRIES)
        {
          nvdbg("Retry limit exceeded\n");
          goto errout_with_sd;
        }

      /* Write the received data chunk to the file */

      ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE;
      tftp_dumpbuffer("Recvd DATA", packet + TFTP_DATAHEADERSIZE, ndatabytes);
      if (tftp_write(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0)
        {
          goto errout_with_sd;
        }

      /* Send the acknowledgment */

      len = tftp_mkackpacket(packet, blockno);
      ret = tftp_sendto(sd, packet, len, &server);
      if (ret != len)
        {
          goto errout_with_sd;
        }
      nvdbg("ACK blockno %d\n", blockno);
    }
  while (ndatabytes >= TFTP_DATASIZE);

  /* Return success */

  result = OK;

errout_with_sd:
  close(sd);
errout_with_fd:
  close(fd);
errout_with_packet:
  free(packet);
errout:
  return result;
}
Exemple #22
0
static int tftp_rcvack(int sd, uint8_t *packet, struct sockaddr_in *server,
                       uint16_t *port, uint16_t *blockno)
{
  struct sockaddr_in from;     /* The address the last UDP message recv'd from */
  ssize_t nbytes;              /* The number of bytes received. */
  uint16_t opcode;             /* The received opcode */
  uint16_t rblockno;           /* The received block number */
  int packetlen;               /* Packet length */
  int retry;                   /* Retry counter */

  /* Try up to TFTP_RETRIES times */

  for (retry = 0; retry < TFTP_RETRIES; retry++)
    {
      /* Try for until a valid ACK is received or some error occurs */

      for (;;)
        {
          /* Receive the next UDP packet from the server */

          nbytes = tftp_recvfrom(sd, packet, TFTP_IOBUFSIZE, &from);
          if (nbytes < TFTP_ACKHEADERSIZE)
            {
              /* Failed to receive a good packet */

              if (nbytes == 0)
                {
                  ndbg("Connection lost: %d bytes\n", nbytes);
                }
              else if (nbytes > 0)
                {
                  ndbg("Short packet: %d bytes\n", nbytes);
                }
              else
                {
                  ndbg("Recveid failure\n");
                }

              /* Break out to bump up the retry count */

              break;
            }
          else
            {
               /* Get the port being used by the server if that has not yet been established */

               if (!*port)
                 {
                   *port            = from.sin_port;
                   server->sin_port = from.sin_port;
                 }

               /* Verify that the packet was received from the correct host and port */

               if (server->sin_addr.s_addr != from.sin_addr.s_addr)
                 {
                   nvdbg("Invalid address in DATA\n");
                   continue;
                 }

              if (*port != server->sin_port)
                {
                  nvdbg("Invalid port in DATA\n");
                  packetlen = tftp_mkerrpacket(packet, TFTP_ERR_UNKID, TFTP_ERRST_UNKID);
                  (void)tftp_sendto(sd, packet, packetlen, server);
                  continue;
                }

              /* Parse the error message */

               opcode   = (uint16_t)packet[0] << 8 | (uint16_t)packet[1];
               rblockno = (uint16_t)packet[2] << 8 | (uint16_t)packet[3];

              /* Verify that the message that we received is an ACK for the
               * expected block number.
               */

               if (opcode != TFTP_ACK)
                 {
                   nvdbg("Bad opcode\n");
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
                  if (opcode == TFTP_ERR)
                    {
                      (void)tftp_parseerrpacket(packet);
                    }
                  else
#endif
                  if (opcode > TFTP_MAXRFC1350)
                    {
                      packetlen = tftp_mkerrpacket(packet, TFTP_ERR_ILLEGALOP, TFTP_ERRST_ILLEGALOP);
                      (void)tftp_sendto(sd, packet, packetlen, server);
                    }

                  /* Break out an bump up the retry count */

                  break;
                }

              /* Success! */

              nvdbg("Received ACK for block %d\n", rblockno);
              *blockno = rblockno;
              return OK;
            }
        }
    }

  /* We have tried TFTP_RETRIES times */

  ndbg("Timeout, Waiting for ACK\n");
  return ERROR; /* Will never get here */
}