static void idle(ClientData client_data, struct timeval *nowP) { int cnum; struct connect_s *conn; for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) { conn = &connects[cnum]; switch (conn->conn_state) { case CNST_READING: if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_READ_LIMIT_SEC) { nerr("ERROR: %s connection timed out reading\n", httpd_ntoa(&conn->hc->client_addr)); httpd_send_err(conn->hc, 408, httpd_err408title, "", httpd_err408form, ""); finish_connection(conn, nowP); } break; case CNST_SENDING: if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC) { nerr("ERROR: %s connection timed out sending\n", httpd_ntoa(&conn->hc->client_addr)); clear_connection(conn, nowP); } break; } } }
static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn, FAR const struct sockaddr_in *addr) { int port; int ret; /* Verify or select a local port and address */ net_lock(); /* Verify or select a local port (host byte order) */ #ifdef CONFIG_NETDEV_MULTINIC port = tcp_selectport(PF_INET, (FAR const union ip_addr_u *)&addr->sin_addr.s_addr, ntohs(addr->sin_port)); #else port = tcp_selectport(ntohs(addr->sin_port)); #endif if (port < 0) { nerr("ERROR: tcp_selectport failed: %d\n", port); return port; } /* Save the local address in the connection structure (network byte order). */ conn->lport = htons(port); #ifdef CONFIG_NETDEV_MULTINIC net_ipv4addr_copy(conn->u.ipv4.laddr, addr->sin_addr.s_addr); #endif /* Find the device that can receive packets on the network associated with * this local address. */ ret = tcp_local_ipv4_device(conn); if (ret < 0) { /* If no device is found, then the address is not reachable */ nerr("ERROR: tcp_local_ipv4_device failed: %d\n", ret); /* Back out the local address setting */ conn->lport = 0; #ifdef CONFIG_NETDEV_MULTINIC net_ipv4addr_copy(conn->u.ipv4.laddr, INADDR_ANY); #endif return ret; } net_unlock(); return OK; }
int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login) { FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; int errcode; int ret; /* Verify that we are connected to a server */ if (!ftpc_connected(session)) { nerr("ERROR: Not connected\n"); errcode = ENOTCONN; goto errout_with_err; } /* Verify that we are not already logged in to the server */ if (ftpc_loggedin(session)) { nerr("ERROR: Already logged in\n"); errcode = EINVAL; goto errout_with_err; } /* Save the login parameter */ session->uname = ftpc_dequote(login->uname); session->pwd = ftpc_dequote(login->pwd); session->initrdir = ftpc_dequote(login->rdir); /* Is passive mode requested? */ FTPC_CLR_PASSIVE(session); if (login->pasv) { ninfo("Setting passive mode\n"); FTPC_SET_PASSIVE(session); } /* The (Re-)login to the server */ ret = ftpc_relogin(session); if (ret != OK) { nerr("ERROR: login failed: %d\n", errno); goto errout; } return OK; errout_with_err: set_errno(errcode); errout: return ERROR; }
ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen) { ssize_t nsent; /* Verify that non-NULL pointers were passed */ #ifdef CONFIG_DEBUG_FEATURES if (buf == NULL) { return -EINVAL; } #endif /* If to is NULL or tolen is zero, then this function is same as send (for * connected socket types) */ if (to == NULL || tolen <= 0) { #if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) || \ defined(CONFIG_NET_USRSOCK) return psock_send(psock, buf, len, flags); #else nerr("ERROR: No 'to' address\n"); return -EINVAL; #endif } /* Verify that the psock corresponds to valid, allocated socket */ if (psock == NULL || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); return -EBADF; } /* Let the address family's sendto() method handle the operation */ DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_sendto != NULL); nsent = psock->s_sockif->si_sendto(psock, buf, len, flags, to, tolen); /* Check if the domain-specific sendto() logic failed */ if (nsent < 0) { nerr("ERROR: Family-specific send failed: %ld\n", (long)nsent); return nsent; } return nsent; }
static int local_tx_open(FAR struct local_conn_s *conn, FAR const char *path, bool nonblock) { int oflags = nonblock ? O_WRONLY | O_NONBLOCK : O_WRONLY; conn->lc_outfd = open(path, oflags); if (conn->lc_outfd < 0) { int errcode = get_errno(); DEBUGASSERT(errcode > 0); nerr("ERROR: Failed on open %s for writing: %d\n", path, errcode); /* Map the errcode to something consistent with the return * error codes from connect(): * * If errcode is ENOENT, meaning that the FIFO does exist, * return EFAULT meaning that the socket structure address is * outside the user's address space. */ return errcode == ENOENT ? -EFAULT : -errcode; } return OK; }
/**************************************************************************** * Name: local_release_fifo * * Description: * Release a reference from one of the FIFOs used in a connection. * ****************************************************************************/ #ifdef CONFIG_NET_LOCAL_STREAM /* Currently not used by datagram code */ static int local_release_fifo(FAR const char *path) { int ret; /* Unlink the client-to-server FIFO if it exists. */ if (local_fifo_exists(path)) { /* Un-linking the FIFO removes the FIFO from the namespace. It will * also mark the FIFO device "unlinked". When all of the open * references to the FIFO device are closed, the resources consumed * by the device instance will also be freed. */ ret = unlink(path); if (ret < 0) { int errcode = get_errno(); DEBUGASSERT(errcode > 0); nerr("ERROR: Failed to unlink FIFO %s: %d\n", path, errcode); return -errcode; } } /* The FIFO does not exist or we successfully unlinked it. */ return OK; }
static int local_create_fifo(FAR const char *path) { int ret; /* Create the client-to-server FIFO if it does not already exist. */ if (!local_fifo_exists(path)) { ret = mkfifo(path, 0644); if (ret < 0) { int errcode = get_errno(); DEBUGASSERT(errcode > 0); nerr("ERROR: Failed to create FIFO %s: %d\n", path, errcode); return -errcode; } } /* The FIFO (or some character driver) exists at PATH or we successfully * created the FIFO at that location. */ return OK; }
ssize_t psock_local_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags) { FAR struct local_conn_s *peer; int ret; DEBUGASSERT(psock && psock->s_conn && buf); peer = (FAR struct local_conn_s *)psock->s_conn; /* Verify that this is a connected peer socket and that it has opened the * outgoing FIFO for write-only access. */ if (peer->lc_state != LOCAL_STATE_CONNECTED || peer->lc_outfd < 0) { nerr("ERROR: not connected\n"); return -ENOTCONN; } /* Send the packet */ ret = local_send_packet(peer->lc_outfd, (FAR uint8_t *)buf, len); /* If the send was successful, then the full packet will have been sent */ return ret < 0 ? ret : len; }
FAR const struct sock_intf_s * net_sockif(sa_family_t family, int type, int protocol) { FAR const struct sock_intf_s *sockif = NULL; /* Get the socket interface. * * REVISIT: Should also support PF_UNSPEC which would permit the socket * to be used for anything. */ switch (family) { #ifdef HAVE_INET_SOCKETS #ifdef HAVE_PFINET_SOCKETS case PF_INET: #endif #ifdef HAVE_PFINET6_SOCKETS case PF_INET6: #endif sockif = inet_sockif(family, type, protocol); break; #endif #ifdef CONFIG_NET_LOCAL case PF_LOCAL: sockif = &g_local_sockif; break; #endif #ifdef CONFIG_NET_NETLINK case PF_NETLINK: sockif = &g_netlink_sockif; break; #endif #ifdef CONFIG_NET_PKT case PF_PACKET: sockif = &g_pkt_sockif; break; #endif #ifdef CONFIG_NET_BLUETOOTH case PF_BLUETOOTH: sockif = &g_bluetooth_sockif; break; #endif #ifdef CONFIG_NET_IEEE802154 case PF_IEEE802154: sockif = &g_ieee802154_sockif; break; #endif default: nerr("ERROR: Address family unsupported: %d\n", family); } return sockif; }
int bluetooth_input(FAR struct radio_driver_s *radio, FAR struct iob_s *framelist, FAR struct bluetooth_frame_meta_s *meta) { FAR struct bluetooth_conn_s *conn; FAR struct iob_s *frame; FAR struct iob_s *next; int ret = OK; /* Check if there is a connection that will accept this packet */ conn = bluetooth_conn_active(meta); if (conn != NULL) { /* Setup for the application callback (NOTE: These should not be * used by PF_BLUETOOTH sockets). */ radio->r_dev.d_appdata = radio->r_dev.d_buf; radio->r_dev.d_len = 0; radio->r_dev.d_sndlen = 0; /* The framelist probably contains only a single frame, but we will * process it as a list of frames. */ for (frame = framelist; frame != NULL; frame = next) { /* Remove the frame from the list */ next = frame->io_flink; frame->io_flink = NULL; /* Add the frame to the RX queue */ ret = bluetooth_queue_frame(conn, frame, meta); if (ret < 0) { nerr("ERROR: Failed to queue frame: %d\n", ret); iob_free(frame); } } /* Perform the application callback. The frame may be processed now * if there is a user wait for an incoming frame. Or it may pend in * the RX queue until some user process reads the frame. NOTE: The * return value from bluetooth_callback would distinguish these * cases: BLUETOOTH_NEWDATA will still be processed if the frame * was not consumed. */ (void)bluetooth_callback(radio, conn, BLUETOOTH_NEWDATA); } else { nwarn("WARNING: No listener\n"); } return ret; }
static uint16_t arp_send_eventhandler(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *priv, uint16_t flags) { FAR struct arp_send_s *state = (FAR struct arp_send_s *)priv; ninfo("flags: %04x sent: %d\n", flags, state->snd_sent); if (state) { /* Check if the network is still up */ if ((flags & NETDEV_DOWN) != 0) { nerr("ERROR: Interface is down\n"); arp_send_terminate(state, -ENETUNREACH); return flags; } /* Check if the outgoing packet is available. It may have been claimed * by a send event handler serving a different thread -OR- if the * output buffer currently contains unprocessed incoming data. In * these cases we will just have to wait for the next polling cycle. */ if (dev->d_sndlen > 0 || (flags & PKT_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ /* REVISIT: No timeout. Just wait for the next polling cycle */ return flags; } /* It looks like we are good to send the data */ /* Copy the packet data into the device packet buffer and send it */ arp_format(dev, state->snd_ipaddr); /* Make sure no ARP request overwrites this ARP request. This * flag will be cleared in arp_out(). */ IFF_SET_NOARP(dev->d_flags); /* Don't allow any further call backs. */ arp_send_terminate(state, OK); } return flags; }
int psock_tcp_cansend(FAR struct socket *psock) { if (!psock || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); return -EBADF; } if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { nerr("ERROR: Not connected\n"); return -ENOTCONN; } if (tcp_wrbuffer_test()) { return -EWOULDBLOCK; } return OK; }
static void clear_connection(struct connect_s *conn, struct timeval *tv) { ClientData client_data; if (conn->wakeup_timer != NULL) { tmr_cancel(conn->wakeup_timer); conn->wakeup_timer = 0; } /* This is our version of Apache's lingering_close() routine, which is * their version of the often-broken SO_LINGER socket option. For why * this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html * What we do is delay the actual closing for a few seconds, while reading * any bytes that come over the connection. However, we don't want to do * this unless it's necessary, because it ties up a connection slot and * file descriptor which means our maximum connection-handling rateis * lower. So, elsewhere we set a flag when we detect the few * circumstances that make a lingering close necessary. If the flag isn't * set we do the real close now. */ if (conn->conn_state == CNST_LINGERING) { /* If we were already lingering, shut down for real */ tmr_cancel(conn->linger_timer); conn->linger_timer = NULL; conn->hc->should_linger = false; } else if (conn->hc->should_linger) { fdwatch_del_fd(fw, conn->hc->conn_fd); conn->conn_state = CNST_LINGERING; fdwatch_add_fd(fw, conn->hc->conn_fd, conn); client_data.p = conn; conn->linger_timer = tmr_create(tv, linger_clear_connection, client_data, CONFIG_THTTPD_LINGER_MSEC, 0); if (conn->linger_timer != NULL) { return; } nerr("ERROR: tmr_create(linger_clear_connection) failed\n"); } /* Either we are done lingering, we shouldn't linger, or we failed to setup the linger */ really_clear_connection(conn); }
static int local_set_policy(int fd, unsigned long policy) { int ret; /* Set the buffer policy */ ret = ioctl(fd, PIPEIOC_POLICY, policy); if (ret < 0) { int errcode = get_errno(); DEBUGASSERT(errcode > 0); nerr("ERROR: Failed to set FIFO buffer policty: %d\n", errcode); return -errcode; } return OK; }
int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) { int ret = OK; if (g_dns_address) { #ifdef CONFIG_NET_IPv4 /* Check for an IPv4 address */ if (g_dns_server.addr.sa_family == AF_INET) { /* Perform the callback */ ret = callback(arg, (FAR struct sockaddr *)&g_dns_server.ipv4, sizeof(struct sockaddr_in)); } else #endif #ifdef CONFIG_NET_IPv6 /* Check for an IPv6 address */ if (g_dns_server.addr.sa_family == AF_INET6) { /* Perform the callback */ ret = callback(arg, (FAR struct sockaddr *)&g_dns_server.ipv6, sizeof(struct sockaddr_in6)); } else #endif { nerr("ERROR: Unsupported family: %d\n", g_dns_server.addr.sa_family); ret = -ENOSYS; } } return ret; }
static int slip_rxtask(int argc, FAR char *argv[]) { FAR struct slip_driver_s *priv; unsigned int index = *(argv[1]) - '0'; net_lock_t flags; int ch; nerr("index: %d\n", index); DEBUGASSERT(index < CONFIG_NET_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. */ ninfo("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); NETDEV_RXPACKETS(&priv->dev); /* 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 >= IPv4_HDRLEN) { NETDEV_RXIPV4(&priv->dev); /* Handle the IP input. Get exclusive access to the network. */ slip_semtake(priv); priv->dev.d_buf = priv->rxbuf; priv->dev.d_len = priv->rxlen; flags = net_lock(); ipv4_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); kill(priv->txpid, SIGALRM); } net_unlock(flags); slip_semgive(priv); } else { NETDEV_RXERRORS(&priv->dev); } } /* We won't get here */ return OK; }
static int bluetooth_queue_frame(FAR struct bluetooth_conn_s *conn, FAR struct iob_s *frame, FAR struct bluetooth_frame_meta_s *meta) { FAR struct bluetooth_container_s *container; /* Allocate a container for the frame */ container = bluetooth_container_allocate(); if (container == NULL) { nerr("ERROR: Failed to allocate a container\n"); return -ENOMEM; } /* Initialize the container */ memset(&container->bn_raddr, 0, sizeof(bt_addr_t)); container->bn_channel = meta->bm_channel; BLUETOOTH_ADDRCOPY(&container->bn_raddr, &meta->bm_raddr); DEBUGASSERT(frame != NULL); container->bn_iob = frame; /* Add the container to the tail of the list of incoming frames */ container->bn_flink = NULL; if (conn->bc_rxtail == NULL) { conn->bc_rxhead = container; } else { conn->bc_rxtail->bn_flink = container; } #if CONFIG_NET_BLUETOOTH_BACKLOG > 0 /* If incrementing the count would exceed the maximum bc_backlog value, then * delete the oldest frame from the head of the RX queue. */ if (conn->bc_backlog >= CONFIG_NET_BLUETOOTH_BACKLOG) { DEBUGASSERT(conn->bc_backlog == CONFIG_NET_BLUETOOTH_BACKLOG); /* Remove the container from the tail RX input queue. */ container = conn->bc_rxhead; DEBUGASSERT(container != NULL); conn->bc_rxhead = container->bn_flink; container->bn_flink = NULL; /* Did the RX queue become empty? */ if (conn->bc_rxhead == NULL) { conn->bc_rxtail = NULL; } DEBUGASSERT(container != NULL && container->bn_iob != NULL); /* Free both the IOB and the container */ iob_free(container->bn_iob); bluetooth_container_free(container); } else { /* Increment the count of frames in the queue. */ conn->bc_backlog++; } DEBUGASSERT((int)conn->bc_backlog == bluetooth_count_frames(conn)); #endif return OK; }
int tcp_getsockopt(FAR struct socket *psock, int option, FAR void *value, FAR socklen_t *value_len) { #ifdef CONFIG_NET_TCP_KEEPALIVE /* Keep alive options are the only TCP protocol socket option currently * supported. */ FAR struct tcp_conn_s *conn; int ret; DEBUGASSERT(psock != NULL && value != NULL && value_len != NULL && psock->s_conn != NULL); conn = (FAR struct tcp_conn_s *)psock->s_conn; /* All of the TCP protocol options apply only TCP sockets. The sockets * do not have to be connected.. that might occur later with the KeepAlive * already configured. */ if (psock->s_type != SOCK_STREAM) { nerr("ERROR: Not a TCP socket\n"); return -ENOTCONN; } /* Handle the Keep-Alive option */ switch (option) { /* Handle the SO_KEEPALIVE socket-level option. * * NOTE: SO_KEEPALIVE is not really a socket-level option; it is a * protocol-level option. A given TCP connection may service multiple * sockets (via dup'ing of the socket). There is, however, still only * one connection to be monitored and that is a global attribute across * all of the clones that may use the underlying connection. */ case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the * periodic transmission of probes */ if (*value_len < sizeof(int)) { /* REVISIT: POSIX says that we should truncate the value if it * is larger than value_len. That just doesn't make sense * to me in this case. */ ret = -EINVAL; } else { FAR int *keepalive = (FAR int *)value; *keepalive = (int)conn->keepalive; *value_len = sizeof(int); ret = OK; } break; case TCP_NODELAY: /* Avoid coalescing of small segments. */ nerr("ERROR: TCP_NODELAY not supported\n"); ret = -ENOSYS; break; case TCP_KEEPIDLE: /* Start keepalives after this IDLE period */ if (*value_len < sizeof(struct timeval)) { /* REVISIT: POSIX says that we should truncate the value if it * is larger than value_len. That just doesn't make sense * to me in this case. */ ret = -EINVAL; } else { FAR struct timeval *tv = (FAR struct timeval *)value; if (tv == NULL) { ret = -EINVAL; } else { /* Convert the KeepIdle time from deciseconds to struct * timeval. */ net_dsec2timeval(conn->keepidle, tv); *value_len = sizeof(struct timeval); ret = OK; } } break; case TCP_KEEPINTVL: /* Interval between keepalives */ if (*value_len < sizeof(struct timeval)) { /* REVISIT: POSIX says that we should truncate the value if it * is larger than value_len. That just doesn't make sense * to me in this case. */ ret = -EINVAL; } else { FAR struct timeval *tv = (FAR struct timeval *)value; if (tv == NULL) { ret = -EINVAL; } else { /* Convert the KeepIdle time from deciseconds to struct * timeval. */ net_dsec2timeval(conn->keepintvl, tv); *value_len = sizeof(struct timeval); ret = OK; } } break; case TCP_KEEPCNT: /* Number of keepalives before death */ if (*value_len < sizeof(int)) { /* REVISIT: POSIX says that we should truncate the value if it * is larger than value_len. That just doesn't make sense * to me in this case. */ ret = -EINVAL; } else { FAR int *keepcnt = (FAR int *)value; *keepcnt = (int)conn->keepcnt; *value_len = sizeof(int); ret = OK; } break; default: nerr("ERROR: Unrecognized TCP option: %d\n", option); ret = -ENOPROTOOPT; break; } return ret; #else return -ENOPROTOOPT; #endif /* CONFIG_NET_TCP_KEEPALIVE */ }
int arp_send(in_addr_t ipaddr) { FAR struct net_driver_s *dev; struct arp_notify_s notify; struct timespec delay; struct arp_send_s state; int ret; /* First check if destination is a local broadcast. */ if (ipaddr == INADDR_BROADCAST) { /* We don't need to send the ARP request */ return OK; } #ifdef CONFIG_NET_IGMP /* Check if the destination address is a multicast address * * - IPv4: multicast addresses lie in the class D group -- The address range * 224.0.0.0 to 239.255.255.255 (224.0.0.0/4) * * - IPv6 multicast addresses are have the high-order octet of the * addresses=0xff (ff00::/8.) */ if (NTOHL(ipaddr) >= 0xe0000000 && NTOHL(ipaddr) <= 0xefffffff) { /* We don't need to send the ARP request */ return OK; } #endif /* Get the device that can route this request */ dev = netdev_findby_ipv4addr(INADDR_ANY, ipaddr); if (!dev) { nerr("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr); ret = -EHOSTUNREACH; goto errout; } /* ARP support is only built if the Ethernet data link is supported. * Continue and send the ARP request only if this device uses the * Ethernet data link protocol. */ if (dev->d_lltype != NET_LL_ETHERNET) { return OK; } /* Check if the destination address is on the local network. */ if (!net_ipv4addr_maskcmp(ipaddr, dev->d_ipaddr, dev->d_netmask)) { in_addr_t dripaddr; /* Destination address is not on the local network */ #ifdef CONFIG_NET_ROUTE /* We have a routing table.. find the correct router to use in * this case (or, as a fall-back, use the device's default router * address). We will use the router IP address instead of the * destination address when determining the MAC address. */ netdev_ipv4_router(dev, ipaddr, &dripaddr); #else /* Use the device's default router IP address instead of the * destination address when determining the MAC address. */ net_ipv4addr_copy(dripaddr, dev->d_draddr); #endif ipaddr = dripaddr; } /* The destination address is on the local network. Check if it is * the sub-net broadcast address. */ else if (net_ipv4addr_broadcast(ipaddr, dev->d_netmask)) { /* Yes.. We don't need to send the ARP request */ return OK; } /* Allocate resources to receive a callback. This and the following * initialization is performed with the network lock because we don't * want anything to happen until we are ready. */ net_lock(); state.snd_cb = arp_callback_alloc(dev); if (!state.snd_cb) { nerr("ERROR: Failed to allocate a callback\n"); ret = -ENOMEM; goto errout_with_lock; } /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ (void)nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ nxsem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); state.snd_retries = 0; /* No retries yet */ state.snd_ipaddr = ipaddr; /* IP address to query */ /* Remember the routing device name */ strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ); /* Now loop, testing if the address mapping is in the ARP table and re- * sending the ARP request if it is not. */ ret = -ETIMEDOUT; /* Assume a timeout failure */ while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES) { /* Check if the address mapping is present in the ARP table. This * is only really meaningful on the first time through the loop. * * NOTE: If the ARP table is large than this could be a performance * issue. */ if (arp_find(ipaddr, NULL) >= 0) { /* We have it! Break out with success */ ret = OK; break; } /* Set up the ARP response wait BEFORE we send the ARP request */ arp_wait_setup(ipaddr, ¬ify); /* Arm/re-arm the callback */ state.snd_sent = false; state.snd_result = -EBUSY; state.snd_cb->flags = (ARP_POLL | NETDEV_DOWN); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = arp_send_eventhandler; /* Notify the device driver that new TX data is available. * NOTES: This is in essence what netdev_ipv4_txnotify() does, which * is not possible to call since it expects a in_addr_t as * its single argument to lookup the network interface. */ if (dev->d_txavail) { dev->d_txavail(dev); } /* Wait for the send to complete or an error to occur. * net_lockedwait will also terminate if a signal is received. */ do { (void)net_lockedwait(&state.snd_sem); } while (!state.snd_sent); /* Check the result of the send operation */ ret = state.snd_result; if (ret < 0) { /* Break out on a send failure */ nerr("ERROR: Send failed: %d\n", ret); break; } /* Now wait for response to the ARP response to be received. The * optimal delay would be the work case round trip time. * NOTE: The network is locked. */ delay.tv_sec = CONFIG_ARP_SEND_DELAYSEC; delay.tv_nsec = CONFIG_ARP_SEND_DELAYNSEC; ret = arp_wait(¬ify, &delay); /* arp_wait will return OK if and only if the matching ARP response * is received. Otherwise, it will return -ETIMEDOUT. */ if (ret >= OK) { /* Break out if arp_wait() fails */ break; } /* Increment the retry count */ state.snd_retries++; nerr("ERROR: arp_wait failed: %d\n", ret); } nxsem_destroy(&state.snd_sem); arp_callback_free(dev, state.snd_cb); errout_with_lock: net_unlock(); errout: return ret; }
int net_delroute_ipv6(net_ipv6addr_t target, net_ipv6addr_t netmask) { struct route_match_ipv6_s match; struct net_route_ipv6_s route; struct file fshandle; off_t filesize; ssize_t nwritten; ssize_t nread; off_t pos; int nentries; int index; int ret; /* We must lock out other accesses to the routing table while we remove * entry */ ret = net_lockroute_ipv6(); if (ret < 0) { nerr("ERROR: net_lockroute_ipv6 failed: %d\n", ret); return ret; } /* Get the size of the routing table (in entries) */ nentries = net_routesize_ipv6(); if (nentries < 0) { ret = nentries; goto errout_with_lock; } else if (nentries == 0) { ret = -ENOENT; goto errout_with_lock; } /* Set up the comparison structure */ net_ipv6addr_copy(match.target, target); net_ipv6addr_copy(match.netmask, netmask); match.index = 0; /* Then find the index into the routing table where the match can be found */ ret = net_foreachroute_ipv6(net_match_ipv6, &match); if (ret < 0) { /* And error occurred */ ret = ret; goto errout_with_lock; } else if (ret == 0) { /* No match found */ ret = -ENOENT; goto errout_with_lock; } /* Open the routing table for read/write access */ ret = net_openroute_ipv6(O_RDWR, &fshandle); if (ret < 0) { nerr("ERROR: Could not open IPv6 routing table: %d\n", ret); goto errout_with_lock; } #ifdef CONFIG_ROUTE_IPv6_CACHEROUTE /* We are committed to modifying the routing table. Flush the in-memory * routing table cache. */ net_flushcache_ipv6(); #endif /* Loop, copying each entry, to the previous entry thus removing the entry * to be deleted. */ for (index = match.index + 1; index < nentries; index++) { /* Seek to the current entry to be moved */ pos = net_seekroute_ipv6(&fshandle, index); if (pos < 0) { nerr("ERROR: net_readroute_ipv6 failed: %ld\n", (long)pos); ret =(int)pos; goto errout_with_fshandle; } /* Read the routing table entry at this position */ nread = net_readroute_ipv6(&fshandle, &route); if (nread < 0) { nerr("ERROR: net_readroute_ipv6 failed: %ld\n", (long)nread); ret = (int)nread; goto errout_with_fshandle; } else if (nread == 0) { nerr("ERROR: Unexpected end of file\n"); ret = -EINVAL; goto errout_with_fshandle; } /* Seek to the previous entry to be replaced */ pos = net_seekroute_ipv6(&fshandle, index - 1); if (pos < 0) { nerr("ERROR: net_readroute_ipv6 failed: %ld\n", (long)pos); ret =(int)pos; goto errout_with_fshandle; } /* Now write the record to its new location */ nwritten = net_writeroute_ipv6(&fshandle, &route); if (nwritten < 0) { nerr("ERROR: net_readroute_ipv6 failed: %ld\n", (long)nwritten); ret = (int)nwritten; goto errout_with_fshandle; } } /* Now truncate the one duplicate entry at the end of the file. This may * result in a zero length file. */ filesize = (nentries - 1) * sizeof(struct net_route_ipv6_s); ret = file_truncate(&fshandle, filesize); errout_with_fshandle: (void)net_closeroute_ipv6(&fshandle); errout_with_lock: (void)net_unlockroute_ipv6(); return ret; }
static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn, FAR uint8_t *buffer, uint16_t buflen) { FAR struct iob_s *iob; int ret; #ifdef CONFIG_NET_IPv6 FAR struct sockaddr_in6 src_addr6; #endif #ifdef CONFIG_NET_IPv4 FAR struct sockaddr_in src_addr4; #endif FAR void *src_addr; uint8_t src_addr_size; /* Allocate on I/O buffer to start the chain (throttling as necessary). * We will not wait for an I/O buffer to become available in this context. */ iob = iob_tryalloc(true); if (iob == NULL) { nerr("ERROR: Failed to create new I/O buffer chain\n"); return 0; } #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv6(dev->d_flags)) #endif { FAR struct udp_hdr_s *udp = UDPIPv6BUF; FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; src_addr6.sin6_family = AF_INET6; src_addr6.sin6_port = udp->srcport; net_ipv6addr_copy(src_addr6.sin6_addr.s6_addr, ipv6->srcipaddr); src_addr_size = sizeof(src_addr6); src_addr = &src_addr6; } #endif /* CONFIG_NET_IPv6 */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 else #endif { #ifdef CONFIG_NET_IPv6 /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special * class of addresses, the IPv4-mapped IPv6 addresses. */ if (conn->domain == PF_INET6) { FAR struct udp_hdr_s *udp = UDPIPv6BUF; FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; in_addr_t ipv4addr; /* Encode the IPv4 address as an IPv-mapped IPv6 address */ src_addr6.sin6_family = AF_INET6; src_addr6.sin6_port = udp->srcport; ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr); ip6_map_ipv4addr(ipv4addr, src_addr6.sin6_addr.s6_addr16); src_addr_size = sizeof(src_addr6); src_addr = &src_addr6; } else #endif { FAR struct udp_hdr_s *udp = UDPIPv4BUF; FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; src_addr4.sin_family = AF_INET; src_addr4.sin_port = udp->srcport; net_ipv4addr_copy(src_addr4.sin_addr.s_addr, net_ip4addr_conv32(ipv4->srcipaddr)); src_addr_size = sizeof(src_addr4); src_addr = &src_addr4; } } #endif /* CONFIG_NET_IPv4 */ /* Copy the src address info into the I/O buffer chain. We will not wait * for an I/O buffer to become available in this context. It there is * any failure to allocated, the entire I/O buffer chain will be discarded. */ ret = iob_trycopyin(iob, (FAR const uint8_t *)&src_addr_size, sizeof(uint8_t), 0, true); if (ret < 0) { /* On a failure, iob_trycopyin return a negated error value but does * not free any I/O buffers. */ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } ret = iob_trycopyin(iob, (FAR const uint8_t *)src_addr, src_addr_size, sizeof(uint8_t), true); if (ret < 0) { /* On a failure, iob_trycopyin return a negated error value but does * not free any I/O buffers. */ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } if (buflen > 0) { /* Copy the new appdata into the I/O buffer chain */ ret = iob_trycopyin(iob, buffer, buflen, src_addr_size + sizeof(uint8_t), true); if (ret < 0) { /* On a failure, iob_trycopyin return a negated error value but * does not free any I/O buffers. */ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } } /* Add the new I/O buffer chain to the tail of the read-ahead queue */ ret = iob_tryadd_queue(iob, &conn->readahead); if (ret < 0) { nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } #ifdef CONFIG_UDP_READAHEAD_NOTIFIER /* Provided notification(s) that additional UDP read-ahead data is * available. */ udp_notifier_signal(conn); #endif ninfo("Buffered %d bytes\n", buflen); return buflen; }
static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg) { int ret; FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)dev->d_private; /* Decode and dispatch the driver-specific IOCTL command */ switch (cmd) { case SIOCSIWSCAN: ret = bcmf_wl_start_scan(priv, (struct iwreq *)arg); break; case SIOCGIWSCAN: ret = bcmf_wl_get_scan_results(priv, (struct iwreq *)arg); break; case SIOCSIFHWADDR: /* Set device MAC address */ ret = bcmf_wl_set_mac_address(priv, (struct ifreq *)arg); break; case SIOCSIWAUTH: ret = bcmf_wl_set_auth_param(priv, (struct iwreq *)arg); break; case SIOCSIWENCODEEXT: ret = bcmf_wl_set_encode_ext(priv, (struct iwreq *)arg); break; case SIOCSIWFREQ: /* Set channel/frequency (Hz) */ wlwarn("WARNING: SIOCSIWFREQ not implemented\n"); ret = -ENOSYS; break; case SIOCGIWFREQ: /* Get channel/frequency (Hz) */ wlwarn("WARNING: SIOCGIWFREQ not implemented\n"); ret = -ENOSYS; break; case SIOCSIWMODE: /* Set operation mode */ ret = bcmf_wl_set_mode(priv, (struct iwreq *)arg); break; case SIOCGIWMODE: /* Get operation mode */ wlwarn("WARNING: SIOCGIWMODE not implemented\n"); ret = -ENOSYS; break; case SIOCSIWAP: /* Set access point MAC addresses */ wlwarn("WARNING: SIOCSIWAP not implemented\n"); ret = -ENOSYS; break; case SIOCGIWAP: /* Get access point MAC addresses */ wlwarn("WARNING: SIOCGIWAP not implemented\n"); ret = -ENOSYS; break; case SIOCSIWESSID: /* Set ESSID (network name) */ ret = bcmf_wl_set_ssid(priv, (struct iwreq *)arg); break; case SIOCGIWESSID: /* Get ESSID */ wlwarn("WARNING: SIOCGIWESSID not implemented\n"); ret = -ENOSYS; break; case SIOCSIWRATE: /* Set default bit rate (bps) */ wlwarn("WARNING: SIOCSIWRATE not implemented\n"); ret = -ENOSYS; break; case SIOCGIWRATE: /* Get default bit rate (bps) */ wlwarn("WARNING: SIOCGIWRATE not implemented\n"); ret = -ENOSYS; break; case SIOCSIWTXPOW: /* Set transmit power (dBm) */ wlwarn("WARNING: SIOCSIWTXPOW not implemented\n"); ret = -ENOSYS; break; case SIOCGIWTXPOW: /* Get transmit power (dBm) */ wlwarn("WARNING: SIOCGIWTXPOW not implemented\n"); ret = -ENOSYS; break; default: nerr("ERROR: Unrecognized IOCTL command: %d\n", cmd); ret = -ENOTTY; /* Special return value for this case */ break; } return ret; }
xcpt_t arch_phy_irq(FAR const char *intf, xcpt_t handler, phy_enable_t *enable) { irqstate_t flags; xcpt_t *phandler; xcpt_t oldhandler; gpio_pinset_t pinset; phy_enable_t enabler; int irq; DEBUGASSERT(intf); ninfo("%s: handler=%p\n", intf, handler); phyinfo("EMAC0: devname=%s\n", SAMV7_EMAC0_DEVNAME); if (strcmp(intf, SAMV7_EMAC0_DEVNAME) == 0) { phyinfo("Select EMAC0\n"); phandler = &g_emac0_handler; pinset = GPIO_EMAC0_INT; irq = IRQ_EMAC0_INT; enabler = sam_emac0_phy_enable; } else { nerr("ERROR: Unsupported interface: %s\n", intf); return NULL; } /* Disable interrupts until we are done. This guarantees that the * following operations are atomic. */ flags = enter_critical_section(); /* Get the old interrupt handler and save the new one */ oldhandler = *phandler; *phandler = handler; /* Configure the interrupt */ if (handler) { phyinfo("Configure pin: %08x\n", pinset); sam_gpioirq(pinset); phyinfo("Attach IRQ%d\n", irq); (void)irq_attach(irq, handler); } else { phyinfo("Detach IRQ%d\n", irq); (void)irq_detach(irq); enabler = NULL; } /* Return with the interrupt disabled in either case */ sam_gpioirqdisable(irq); /* Return the enabling function pointer */ if (enable) { *enable = enabler; } /* Return the old handler (so that it can be restored) */ leave_critical_section(flags); return oldhandler; }
int sam_emac0_setmac(void) { struct i2c_master_s *i2c; struct mtd_dev_s *at24; uint8_t mac[6]; ssize_t nread; int ret; /* Get an instance of the TWI0 interface */ i2c = sam_i2cbus_initialize(0); if (!i2c) { nerr("ERROR: Failed to initialize TWI0\n"); return -ENODEV; } /* Initialize the AT24 driver */ at24 = at24c_initialize(i2c); if (!at24) { nerr("ERROR: Failed to initialize the AT24 driver\n"); (void)sam_i2cbus_uninitialize(i2c); return -ENODEV; } /* Configure the AT24 to access the extended memory region */ ret = at24->ioctl(at24, MTDIOC_EXTENDED, 1); if (ret < 0) { nerr("ERROR: AT24 ioctl(MTDIOC_EXTENDED) failed: %d\n", ret); (void)sam_i2cbus_uninitialize(i2c); return ret; } /* Read the MAC address */ nread = at24->read(at24, AT24XX_MACADDR_OFFSET, 6, mac); if (nread < 6) { nerr("ERROR: AT24 read(AT24XX_MACADDR_OFFSET) failed: ld\n", (long)nread); (void)sam_i2cbus_uninitialize(i2c); return (int)nread; } /* Put the AT24 back in normal memory access mode */ ret = at24->ioctl(at24, MTDIOC_EXTENDED, 0); if (ret < 0) { nerr("ERROR: AT24 ioctl(MTDIOC_EXTENDED) failed: %d\n", ret); } /* Release the I2C instance. * REVISIT: Need an interface to release the AT24 instance too */ ret = sam_i2cbus_uninitialize(i2c); if (ret < 0) { nerr("ERROR: Failed to release the I2C interface: %d\n", ret); } ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); /* Now configure the EMAC driver to use this MAC address */ ret = sam_emac_setmacaddr(EMAC0_INTF, mac); if (ret < 0) { nerr("ERROR: Failed to set MAC address: %d\n", ret); } return ret; }
ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct tcp_conn_s *conn; FAR struct tcp_wrbuffer_s *wrb; net_lock_t save; ssize_t result = 0; int errcode; int ret = OK; if (!psock || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); errcode = EBADF; goto errout; } if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { nerr("ERROR: Not connected\n"); errcode = ENOTCONN; goto errout; } /* Make sure that we have the IP address mapping */ conn = (FAR struct tcp_conn_s *)psock->s_conn; DEBUGASSERT(conn); #if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) #ifdef CONFIG_NET_ARP_SEND #ifdef CONFIG_NET_ICMPv6_NEIGHBOR if (psock->s_domain == PF_INET) #endif { /* Make sure that the IP address mapping is in the ARP table */ ret = arp_send(conn->u.ipv4.raddr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { /* Make sure that the IP address mapping is in the Neighbor Table */ ret = icmpv6_neighbor(conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { nerr("ERROR: Not reachable\n"); errcode = ENETUNREACH; goto errout; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Dump the incoming buffer */ BUF_DUMP("psock_tcp_send", buf, len); /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); if (len > 0) { /* Allocate a write buffer. Careful, the network will be momentarily * unlocked here. */ save = net_lock(); wrb = tcp_wrbuffer_alloc(); if (!wrb) { /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate write buffer\n"); errcode = ENOMEM; goto errout_with_lock; } /* Allocate resources to receive a callback */ if (!psock->s_sndcb) { psock->s_sndcb = tcp_callback_alloc(conn); } /* Test if the callback has been allocated */ if (!psock->s_sndcb) { /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate callback\n"); errcode = ENOMEM; goto errout_with_wrb; } /* Set up the callback in the connection */ psock->s_sndcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | TCP_DISCONN_EVENTS); psock->s_sndcb->priv = (FAR void *)psock; psock->s_sndcb->event = psock_send_interrupt; /* Initialize the write buffer */ WRB_SEQNO(wrb) = (unsigned)-1; WRB_NRTX(wrb) = 0; result = WRB_COPYIN(wrb, (FAR uint8_t *)buf, len); /* Dump I/O buffer chain */ WRB_DUMP("I/O buffer chain", wrb, WRB_PKTLEN(wrb), 0); /* psock_send_interrupt() will send data in FIFO order from the * conn->write_q */ sq_addlast(&wrb->wb_node, &conn->write_q); ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n", wrb, WRB_PKTLEN(wrb), conn->write_q.head, conn->write_q.tail); /* Notify the device driver of the availability of TX data */ send_txnotify(psock, conn); net_unlock(save); } /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for errors. Errors are signalled by negative errno values * for the send length */ if (result < 0) { errcode = result; goto errout; } /* If net_lockedwait failed, then we were probably reawakened by a signal. * In this case, net_lockedwait will have set errno appropriately. */ if (ret < 0) { errcode = -ret; goto errout; } /* Return the number of bytes actually sent */ return result; errout_with_wrb: tcp_wrbuffer_release(wrb); errout_with_lock: net_unlock(save); errout: set_errno(errcode); return ERROR; }
static void slip_txtask(int argc, FAR char *argv[]) { FAR struct slip_driver_s *priv; unsigned int index = *(argv[1]) - '0'; net_lock_t flags; systime_t msec_start; systime_t msec_now; unsigned int hsec; nerr("index: %d\n", index); DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES); /* Get our private data structure instance and wake up the waiting * initialization logic. */ priv = &g_slip[index]; slip_semgive(priv); /* Loop forever */ msec_start = clock_systimer() * MSEC_PER_TICK; for (; ; ) { /* Wait for the timeout to expire (or until we are signaled by by */ slip_semtake(priv); if (!priv->txnodelay) { slip_semgive(priv); usleep(SLIP_WDDELAY); } else { priv->txnodelay = false; slip_semgive(priv); } /* Is the interface up? */ if (priv->bifup) { /* Get exclusive access to the network (if it it is already being used * slip_rxtask, then we have to wait). */ slip_semtake(priv); /* Poll the networking layer for new XMIT data. */ flags = net_lock(); priv->dev.d_buf = priv->txbuf; /* Has a half second elapsed since the last timer poll? */ msec_now = clock_systimer() * MSEC_PER_TICK; hsec = (unsigned int)(msec_now - msec_start) / (MSEC_PER_SEC / 2); if (hsec) { /* Yes, perform the timer poll */ (void)devif_timer(&priv->dev, slip_txpoll); msec_start += hsec * (MSEC_PER_SEC / 2); } else { /* No, perform the normal TX poll */ (void)devif_poll(&priv->dev, slip_txpoll); } net_unlock(flags); slip_semgive(priv); } } }
int net_foreachroute_ipv4(route_handler_ipv4_t handler, FAR void *arg) { struct net_route_ipv4_s route; struct file fshandle; ssize_t nread; int ret = 0; /* Open the IPv4 routing table for read-only access */ ret = net_openroute_ipv4(O_RDONLY, &fshandle); if (ret < 0) { /* Special case: the routing table has not yet been created. This is * not an error. We will just want to return successful completion of * the traversal. */ if (ret == -ENOENT) { /* The routing table does not exit.. return successful completion */ ninfo("The IPv4 routing table file does not exist\n"); return OK; } /* Some other error occurred. */ nerr("ERROR: Could not open IPv4 routing table: %d\n", ret); return ret; } /* Read each entry from the routing table */ for (; ; ) { nread = net_readroute_ipv4(&fshandle, &route); if (nread < 0) { /* File read error */ nerr("ERROR: net_readroute_ipv4() failed: %ld\n", (long)nread); ret = (int)nread; break; } else if (nread == 0) { /* End of file */ ret = OK; break; } /* Call the handler. */ ret = handler(&route, arg); if (ret != OK) { /* Terminate early if the handler returns any non-zero value. */ break; } } (void)net_closeroute_ipv4(&fshandle); 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. */ ninfo("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: { ninfo("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) { ninfo("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: { ninfo("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: ninfo("ESC-END\n"); ch = SLIP_END; break; case SLIP_ESC_ESC: ninfo("ESC-ESC\n"); ch = SLIP_ESC; break; default: nerr("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_SLIP_MTU+2) { priv->rxbuf[priv->rxlen++] = ch; } } break; } } }
static int iob_copyin_internal(FAR struct iob_s *iob, FAR const uint8_t *src, unsigned int len, unsigned int offset, bool throttled, bool can_block) { FAR struct iob_s *head = iob; FAR struct iob_s *next; FAR uint8_t *dest; unsigned int ncopy; unsigned int avail; unsigned int total = len; ninfo("iob=%p len=%u offset=%u\n", iob, len, offset); DEBUGASSERT(iob && src); /* The offset must applied to data that is already in the I/O buffer chain */ if (offset > iob->io_pktlen) { nerr("ERROR: offset is past the end of data: %u > %u\n", offset, iob->io_pktlen); return -ESPIPE; } /* Skip to the I/O buffer containing the data offset */ while (offset > iob->io_len) { offset -= iob->io_len; iob = iob->io_flink; } /* Then loop until all of the I/O data is copied from the user buffer */ while (len > 0) { next = iob->io_flink; /* Get the destination I/O buffer address and the amount of data * available from that address. */ dest = &iob->io_data[iob->io_offset + offset]; avail = iob->io_len - offset; ninfo("iob=%p avail=%u len=%u next=%p\n", iob, avail, len, next); /* Will the rest of the copy fit into this buffer, overwriting * existing data. */ if (len > avail) { /* No.. Is this the last buffer in the chain? */ if (next) { /* No.. clip to size that will overwrite. We cannot * extend the length of an I/O block in mid-chain. */ ncopy = avail; } else { unsigned int maxlen; unsigned int newlen; /* Yes.. We can extend this buffer to the up to the very end. */ maxlen = CONFIG_IOB_BUFSIZE - iob->io_offset; /* This is the new buffer length that we need. Of course, * clipped to the maximum possible size in this buffer. */ newlen = len + offset; if (newlen > maxlen) { newlen = maxlen; } /* Set the new length and increment the packet length */ head->io_pktlen += (newlen - iob->io_len); iob->io_len = newlen; /* Set the new number of bytes to copy */ ncopy = newlen - offset; } } else { /* Yes.. Copy all of the remaining bytes */ ncopy = len; } /* Copy from the user buffer to the I/O buffer. */ memcpy(dest, src, ncopy); ninfo("iob=%p Copy %u bytes new len=%u\n", iob, ncopy, iob->io_len); /* Adjust the total length of the copy and the destination address in * the user buffer. */ len -= ncopy; src += ncopy; /* Skip to the next I/O buffer in the chain. First, check if we * are at the end of the buffer chain. */ if (len > 0 && !next) { /* Yes.. allocate a new buffer. * * Copy as many bytes as possible. If we have successfully copied * any already don't block, otherwise block if we're allowed. */ if (!can_block || len < total) { next = iob_tryalloc(throttled); } else { next = iob_alloc(throttled); } if (next == NULL) { nerr("ERROR: Failed to allocate I/O buffer\n"); return len; } /* Add the new, empty I/O buffer to the end of the buffer chain. */ iob->io_flink = next; ninfo("iob=%p added to the chain\n", iob); } iob = next; offset = 0; } return 0; }
int slip_initialize(int intf, FAR const char *devname) { FAR struct slip_driver_s *priv; char buffer[8]; FAR char *argv[2]; /* Get the interface structure associated with this interface number. */ DEBUGASSERT(intf < CONFIG_NET_SLIP_NINTERFACES); priv = &g_slip[intf]; /* Initialize the driver structure */ memset(priv, 0, sizeof(struct slip_driver_s)); priv->dev.d_ifup = slip_ifup; /* I/F up (new IP address) callback */ priv->dev.d_ifdown = slip_ifdown; /* I/F down callback */ priv->dev.d_txavail = slip_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP priv->dev.d_addmac = slip_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = slip_rmmac; /* Remove multicast MAC address */ #endif priv->dev.d_private = priv; /* Used to recover private state from dev */ /* Open the device */ priv->fd = open(devname, O_RDWR, 0666); if (priv->fd < 0) { nerr("ERROR: Failed to open %s: %d\n", devname, errno); return -errno; } /* Initialize the wait semaphore */ sem_init(&priv->waitsem, 0, 0); /* Put the interface in the down state. This usually amounts to resetting * the device and/or calling slip_ifdown(). */ slip_ifdown(&priv->dev); /* Start the SLIP receiver task */ snprintf(buffer, 8, "%d", intf); argv[0] = buffer; argv[1] = NULL; priv->rxpid = task_create("rxslip", CONFIG_NET_SLIP_DEFPRIO, CONFIG_NET_SLIP_STACKSIZE, (main_t)slip_rxtask, (FAR char * const *)argv); if (priv->rxpid < 0) { nerr("ERROR: Failed to start receiver task\n"); return -errno; } /* Wait and make sure that the receive task is started. */ slip_semtake(priv); /* Start the SLIP transmitter task */ priv->txpid = task_create("txslip", CONFIG_NET_SLIP_DEFPRIO, CONFIG_NET_SLIP_STACKSIZE, (main_t)slip_txtask, (FAR char * const *)argv); if (priv->txpid < 0) { nerr("ERROR: Failed to start receiver task\n"); return -errno; } /* Wait and make sure that the transmit task is started. */ slip_semtake(priv); /* Bump the semaphore count so that it can now be used as a mutex */ slip_semgive(priv); /* Register the device with the OS so that socket IOCTLs can be performed */ (void)netdev_register(&priv->dev, NET_LL_SLIP); /* When the RX and TX tasks were created, the TTY file descriptor was * dup'ed for each task. This task no longer needs the file descriptor * and we can safely close it. */ close(priv->fd); return OK; }