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; }
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, ¬ify); /* 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, ¬ify, &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 */ }
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 }
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; }
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; }
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; } } }
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; }
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; }
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; }
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; }
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); } }
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); }
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; }
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; }
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); }
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; }
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 */ }