void igmp_waitmsg(FAR struct igmp_group_s *group, uint8_t msgid) { net_lock_t flags; /* Schedule to send the message */ flags = net_lock(); DEBUGASSERT(!IS_WAITMSG(group->flags)); SET_WAITMSG(group->flags); igmp_schedmsg(group, msgid); /* Then wait for the message to be sent */ while (IS_SCHEDMSG(group->flags)) { /* Wait for the semaphore to be posted */ while (net_lockedwait(&group->sem) != 0) { /* The only error that should occur from net_lockedwait() is if * the wait is awakened by a signal. */ ASSERT(get_errno() == EINTR); } } /* The message has been sent and we are no longer waiting */ CLR_WAITMSG(group->flags); net_unlock(flags); }
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void) { FAR struct tcp_wrbuffer_s *wrb; /* We need to allocate two things: (1) A write buffer structure and (2) * at least one I/O buffer to start the chain. * * Allocate the write buffer structure first then the IOBG. In order to * avoid deadlocks, we will need to free the IOB first, then the write * buffer */ DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem)); /* Now, we are guaranteed to have a write buffer structure reserved * for us in the free list. */ wrb = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); DEBUGASSERT(wrb); memset(wrb, 0, sizeof(struct tcp_wrbuffer_s)); /* Now get the first I/O buffer for the write buffer structure */ wrb->wb_iob = iob_alloc(false); if (!wrb->wb_iob) { ndbg("ERROR: Failed to allocate I/O buffer\n"); tcp_wrbuffer_release(wrb); return NULL; } return wrb; }
int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int option, FAR const void *value, FAR socklen_t value_len) { struct usrsock_reqstate_s state = {}; net_lock_t save; ssize_t ret; DEBUGASSERT(conn); save = net_lock(); if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || conn->state == USRSOCK_CONN_STATE_ABORTED) { /* Invalid state or closed by daemon. */ nlldbg("usockid=%d; connect() with uninitialized usrsock.\n", conn->usockid); ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; goto errout_unlock; } /* Set up event callback for usrsock. */ ret = usrsock_setup_request_callback(conn, &state, setsockopt_event, USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); if (ret < 0) { ndbg("usrsock_setup_request_callback failed: %d\n", ret); goto errout_unlock; } /* Request user-space daemon to close socket. */ ret = do_setsockopt_request(conn, level, option, value, value_len); if (ret >= 0) { /* Wait for completion of request. */ while (net_lockedwait(&state.recvsem) != OK) { DEBUGASSERT(*get_errno_ptr() == EINTR); } ret = state.result; } usrsock_teardown_request_callback(&state); errout_unlock: net_unlock(save); return ret; }
static inline void _udp_semtake(FAR sem_t *sem) { /* Take the semaphore (perhaps waiting) */ while (net_lockedwait(sem) != 0) { /* The only case that an error should occur here is if * the wait was awakened by a signal. */ ASSERT(*get_errno_ptr() == EINTR); } }
static void _net_semtake(FAR struct socketlist *list) { /* Take the semaphore (perhaps waiting) */ while (net_lockedwait(&list->sl_sem) != 0) { /* The only case that an error should occr here is if * the wait was awakened by a signal. */ ASSERT(*get_errno_ptr() == EINTR); } }
static void _netlink_semtake(FAR sem_t *sem) { int ret; /* Take the semaphore (perhaps waiting) */ while ((ret = net_lockedwait(sem)) < 0) { /* The only case that an error should occur here is if * the wait was awakened by a signal. */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); } }
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_conn_s *)psock->s_conn; struct send_s state; net_lock_t save; int err; int ret = OK; /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { ndbg("ERROR: Invalid socket\n"); err = EBADF; goto errout; } /* If this is an un-connected socket, then return ENOTCONN */ if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { ndbg("ERROR: Not connected\n"); err = 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) { ndbg("ERROR: Not reachable\n"); err = ENETUNREACH; goto errout; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Perform the TCP send operation */ /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct send_s)); (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ state.snd_sock = psock; /* Socket descriptor to use */ state.snd_buflen = len; /* Number of bytes to send */ state.snd_buffer = buf; /* Buffer to send from */ if (len > 0) { /* Allocate resources to receive a callback */ state.snd_cb = tcp_callback_alloc(conn); if (state.snd_cb) { /* Get the initial sequence number that will be used */ state.snd_isn = tcp_getsequence(conn->sndseq); /* There is no outstanding, unacknowledged data after this * initial sequence number. */ conn->unacked = 0; /* Set the initial time for calculating timeouts */ #ifdef CONFIG_NET_SOCKOPTS state.snd_time = clock_systimer(); #endif /* Set up the callback in the connection */ state.snd_cb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | TCP_DISCONN_EVENTS); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = tcpsend_interrupt; /* Notify the device driver of the availability of TX data */ send_txnotify(psock, conn); /* 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.snd_sem); /* Make sure that no further interrupts are processed */ tcp_callback_free(conn, state.snd_cb); } } sem_destroy(&state.snd_sem); net_unlock(save); /* 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.snd_sent < 0) { err = state.snd_sent; 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) { err = -ret; goto errout; } /* Return the number of bytes actually sent */ return state.snd_sent; errout: set_errno(err); 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) { #ifdef CONFIG_NET_UDP FAR struct udp_conn_s *conn; #ifdef CONFIG_NET_IPv6 FAR const struct sockaddr_in6 *into = (const struct sockaddr_in6 *)to; #else FAR const struct sockaddr_in *into = (const struct sockaddr_in *)to; #endif struct sendto_s state; net_lock_t save; int ret; #endif int err; /* If to is NULL or tolen is zero, then this function is same as send (for * connected socket types) */ if (!to || !tolen) { #ifdef CONFIG_NET_TCP return psock_send(psock, buf, len, flags); #else ndbg("ERROR: No to address\n"); err = EINVAL; goto errout; #endif } /* Verify that a valid address has been provided */ #ifdef CONFIG_NET_IPv6 if (to->sa_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6)) #else if (to->sa_family != AF_INET || tolen < sizeof(struct sockaddr_in)) #endif { ndbg("ERROR: Invalid address\n"); err = EBADF; goto errout; } /* Verify that the psock corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { ndbg("ERROR: Invalid socket\n"); err = EBADF; goto errout; } /* If this is a connected socket, then return EISCONN */ if (psock->s_type != SOCK_DGRAM) { ndbg("ERROR: Connected socket\n"); err = EISCONN; goto errout; } /* Make sure that the IP address mapping is in the ARP table */ #ifdef CONFIG_NET_ARP_SEND ret = arp_send(into->sin_addr.s_addr); if (ret < 0) { ndbg("ERROR: Not reachable\n"); err = ENETUNREACH; goto errout; } #endif /* Perform the UDP sendto operation */ #ifdef CONFIG_NET_UDP /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct sendto_s)); sem_init(&state.st_sem, 0, 0); state.st_buflen = len; state.st_buffer = buf; /* Set the initial time for calculating timeouts */ #ifdef CONFIG_NET_SENDTO_TIMEOUT state.st_sock = psock; state.st_time = clock_systimer(); #endif /* Setup the UDP socket */ conn = (FAR struct udp_conn_s *)psock->s_conn; ret = udp_connect(conn, into); if (ret < 0) { net_unlock(save); err = -ret; goto errout; } /* Set up the callback in the connection */ state.st_cb = udp_callback_alloc(conn); if (state.st_cb) { state.st_cb->flags = UDP_POLL; state.st_cb->priv = (void*)&state; state.st_cb->event = sendto_interrupt; /* Notify the device driver of the availabilty of TX data */ netdev_txnotify(conn->ripaddr); /* Wait for either the receive to complete or for an error/timeout 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. */ net_lockedwait(&state.st_sem); /* Make sure that no further interrupts are processed */ udp_callback_free(conn, state.st_cb); } net_unlock(save); sem_destroy(&state.st_sem); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for errors */ if (state.st_sndlen < 0) { err = -state.st_sndlen; goto errout; } /* Success */ return state.st_sndlen; #else err = ENOSYS; #endif errout: set_errno(err); return ERROR; }
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 icmpv6_neighbor(const net_ipv6addr_t ipaddr) { FAR struct net_driver_s *dev; struct icmpv6_notify_s notify; struct timespec delay; struct icmpv6_neighbor_s state; FAR const uint16_t *lookup; net_lock_t save; int ret; /* First check if destination is a local broadcast or a multicast address. * * - IPv6 multicast addresses are have the high-order octet of the * addresses=0xff (ff00::/8.) */ if (net_ipv6addr_cmp(ipaddr, g_ipv6_allzeroaddr) || (ipaddr[0] & NTOHS(0xff00)) == NTOHS(0xff00)) { /* We don't need to send the Neighbor Solicitation */ return OK; } /* Get the device that can route this request */ #ifdef CONFIG_NETDEV_MULTINIC dev = netdev_findby_ipv6addr(g_ipv6_allzeroaddr, ipaddr); #else dev = netdev_findby_ipv6addr(ipaddr); #endif if (!dev) { ndbg("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr); ret = -EHOSTUNREACH; goto errout; } #ifdef CONFIG_NET_MULTILINK /* If we are supporting multiple network devices and using different * link level protocols then we can get here for other link protocols * as well. Continue and send the Neighbor Solicitation request only * if this device uses the Ethernet data link protocol. * * REVISIT: Other link layer protocols may require Neighbor Discovery * as well (but not SLIP which is the only other option at the moment). */ if (dev->d_lltype != NET_LL_ETHERNET) { return OK; } #endif /* Check if the destination address is on the local network. */ if (net_ipv6addr_maskcmp(ipaddr, dev->d_ipv6addr, dev->d_ipv6netmask)) { /* Yes.. use the input address for the lookup */ lookup = ipaddr; } else { net_ipv6addr_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_ipv6_router(dev, ipaddr, dripaddr); #else /* Use the device's default router IP address instead of the * destination address when determining the MAC address. */ net_ipv6addr_copy(dripaddr, dev->d_ipv6draddr); #endif /* Use the router address for the lookup */ lookup = dripaddr; } /* 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. */ save = net_lock(); state.snd_cb = icmpv6_callback_alloc(); if (!state.snd_cb) { ndbg("ERROR: Failed to allocate a cllback\n"); ret = -ENOMEM; goto errout_with_lock; } /* Initialize the state structure. This is done with interrupts * disabled */ (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ state.snd_retries = 0; /* No retries yet */ net_ipv6addr_copy(state.snd_ipaddr, lookup); /* IP address to query */ #ifdef CONFIG_NETDEV_MULTINIC /* Remember the routing device name */ strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ); #endif /* Now loop, testing if the address mapping is in the Neighbor Table and * re-sending the Neighbor Solicitation if it is not. */ ret = -ETIMEDOUT; /* Assume a timeout failure */ while (state.snd_retries < CONFIG_ICMPv6_NEIGHBOR_MAXTRIES) { /* Check if the address mapping is present in the Neighbor Table. This * is only really meaningful on the first time through the loop. * * NOTE: If the Neighbor Table is large than this could be a performance * issue. */ if (neighbor_findentry(lookup) != NULL) { /* We have it! Break out with success */ ret = OK; break; } /* Set up the Neighbor Advertisement wait BEFORE we send the Neighbor * Solicitation. */ icmpv6_wait_setup(lookup, ¬ify); /* Arm/re-arm the callback */ state.snd_sent = false; state.snd_cb->flags = ICMPv6_POLL; state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = icmpv6_neighbor_interrupt; /* Notify the device driver that new TX data is available. */ dev->d_txavail(dev); /* 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. */ do { (void)net_lockedwait(&state.snd_sem); } while (!state.snd_sent); /* Now wait for response to the Neighbor Advertisement to be received. * The optimal delay would be the work case round trip time. * NOTE: The network is locked. */ delay.tv_sec = CONFIG_ICMPv6_NEIGHBOR_DELAYSEC; delay.tv_nsec = CONFIG_ICMPv6_NEIGHBOR_DELAYNSEC; ret = icmpv6_wait(¬ify, &delay); /* icmpv6_wait will return OK if and only if the matching Neighbor * Advertisement is received. Otherwise, it will return -ETIMEDOUT. */ if (ret == OK) { break; } /* Increment the retry count */ state.snd_retries++; } sem_destroy(&state.snd_sem); icmpv6_callback_free(state.snd_cb); errout_with_lock: net_unlock(save); errout: return ret; }
int icmp_ping(in_addr_t addr, uint16_t id, uint16_t seqno, uint16_t datalen, int dsecs) { struct icmp_ping_s state; net_lock_t save; #ifdef CONFIG_NET_ARP_SEND int ret; /* Make sure that the IP address mapping is in the ARP table */ ret = arp_send(addr); if (ret < 0) { ndbg("ERROR: Not reachable\n"); return -ENETUNREACH; } #endif /* Initialize the state structure */ sem_init(&state.png_sem, 0, 0); state.png_ticks = DSEC2TICK(dsecs); /* System ticks to wait */ state.png_result = -ENOMEM; /* Assume allocation failure */ state.png_addr = addr; /* Address of the peer to be ping'ed */ state.png_id = id; /* The ID to use in the ECHO request */ state.png_seqno = seqno; /* The seqno to use in the ECHO request */ state.png_datlen = datalen; /* The length of data to send in the ECHO request */ state.png_sent = false; /* ECHO request not yet sent */ save = net_lock(); state.png_time = clock_systimer(); /* Set up the callback */ state.png_cb = icmp_callback_alloc(); if (state.png_cb) { state.png_cb->flags = (ICMP_POLL | ICMP_ECHOREPLY); state.png_cb->priv = (void*)&state; state.png_cb->event = ping_interrupt; state.png_result = -EINTR; /* Assume sem-wait interrupted by signal */ /* Notify the device driver of the availability of TX data */ #ifdef CONFIG_NETDEV_MULTINIC netdev_ipv4_txnotify(g_ipv4_allzeroaddr, state.png_addr); #else netdev_ipv4_txnotify(state.png_addr); #endif /* Wait for either the full round trip transfer to complete or * for timeout to occur. (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. */ nllvdbg("Start time: 0x%08x seqno: %d\n", state.png_time, seqno); net_lockedwait(&state.png_sem); icmp_callback_free(state.png_cb); } net_unlock(save); /* Return the negated error number in the event of a failure, or the * sequence number of the ECHO reply on success. */ if (!state.png_result) { nllvdbg("Return seqno=%d\n", state.png_seqno); return (int)state.png_seqno; } else { nlldbg("Return error=%d\n", -state.png_result); return state.png_result; } }
ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, size_t count) { FAR struct socket *psock = sockfd_socket(outfd); FAR struct tcp_conn_s *conn; struct sendfile_s state; net_lock_t save; int err; /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { ndbg("ERROR: Invalid socket\n"); err = EBADF; goto errout; } /* If this is an un-connected socket, then return ENOTCONN */ if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { ndbg("ERROR: Not connected\n"); err = 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) { ndbg("ERROR: Not reachable\n"); err = ENETUNREACH; goto errout; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct sendfile_s)); sem_init(&state. snd_sem, 0, 0); /* Doesn't really fail */ state.snd_sock = psock; /* Socket descriptor to use */ state.snd_foffset = offset ? *offset : 0; /* Input file offset */ state.snd_flen = count; /* Number of bytes to send */ state.snd_file = infile; /* File to read from */ /* Allocate resources to receive a callback */ state.snd_datacb = tcp_callback_alloc(conn); if (state.snd_datacb == NULL) { nlldbg("Failed to allocate data callback\n"); err = ENOMEM; goto errout_locked; } state.snd_ackcb = tcp_callback_alloc(conn); if (state.snd_ackcb == NULL) { nlldbg("Failed to allocate ack callback\n"); err = ENOMEM; goto errout_datacb; } /* Get the initial sequence number that will be used */ state.snd_isn = tcp_getsequence(conn->sndseq); /* There is no outstanding, unacknowledged data after this * initial sequence number. */ conn->unacked = 0; #ifdef CONFIG_NET_SOCKOPTS /* Set the initial time for calculating timeouts */ state.snd_time = clock_systimer(); #endif /* Set up the ACK callback in the connection */ state.snd_ackcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_DISCONN_EVENTS); state.snd_ackcb->priv = (FAR void *)&state; state.snd_ackcb->event = ack_interrupt; /* Perform the TCP send operation */ do { state.snd_datacb->flags = TCP_POLL; state.snd_datacb->priv = (FAR void *)&state; state.snd_datacb->event = sendfile_interrupt; /* Notify the device driver of the availability of TX data */ sendfile_txnotify(psock, conn); net_lockedwait(&state.snd_sem); } while (state.snd_sent >= 0 && state.snd_acked < state.snd_flen); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); tcp_callback_free(conn, state.snd_ackcb); errout_datacb: tcp_callback_free(conn, state.snd_datacb); errout_locked: sem_destroy(&state. snd_sem); net_unlock(save); errout: if (err) { set_errno(err); return ERROR; } else if (state.snd_sent < 0) { set_errno(-state.snd_sent); return ERROR; } else { return state.snd_sent; } }
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 */ ninfo("Pending conn=%p\n", state.acpt_newconn); accept_tcpsender(psock, state.acpt_newconn, addr, addrlen); } /* In general, this 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 the network * locked 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; /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ nxsem_init(&state.acpt_sem, 0, 0); nxsem_setprotocol(&state.acpt_sem, SEM_PRIO_NONE); /* Set up the callback in the connection */ conn->accept_private = (FAR void *)&state; conn->accept = accept_eventhandler; /* Wait for the send to complete or an error to occur: NOTES: * net_lockedwait will also terminate if a signal is received. */ ret = net_lockedwait(&state.acpt_sem); /* Make sure that no further events are processed */ conn->accept_private = NULL; conn->accept = NULL; nxsem_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, net_lockedwait will have returned negated * errno appropriately. */ if (ret < 0) { return ret; } } *newconn = (FAR void *)state.acpt_newconn; return OK; }
int usrsock_socket(int domain, int type, int protocol, FAR struct socket *psock) { struct usrsock_reqstate_s state = {}; FAR struct usrsock_conn_s *conn; net_lock_t save; int err; /* Allocate the usrsock socket connection structure and save in the new * socket instance. */ conn = usrsock_alloc(); if (!conn) { /* Failed to reserve a connection structure */ return -ENOMEM; } save = net_lock(); /* Set up event callback for usrsock. */ err = usrsock_setup_request_callback(conn, &state, socket_event, USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); if (err < 0) { goto errout_free_conn; } /* Request user-space daemon for new socket. */ err = do_socket_request(conn, domain, type, protocol); if (err < 0) { goto errout_teardown_callback; } /* Wait for completion of request. */ while (net_lockedwait(&state.recvsem) != OK) { DEBUGASSERT(*get_errno_ptr() == EINTR); } if (state.result < 0) { err = state.result; goto errout_teardown_callback; } psock->s_type = SOCK_USRSOCK_TYPE; psock->s_domain = PF_USRSOCK_DOMAIN; conn->type = type; psock->s_conn = conn; conn->crefs = 1; usrsock_teardown_request_callback(&state); net_unlock(save); return OK; errout_teardown_callback: usrsock_teardown_request_callback(&state); errout_free_conn: usrsock_free(conn); net_unlock(save); return err; }
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 inline int netclose_disconnect(FAR struct socket *psock) { struct tcp_close_s state; FAR struct tcp_conn_s *conn; net_lock_t flags; #ifdef CONFIG_NET_SOLINGER bool linger; #endif int ret = OK; /* Interrupts are disabled here to avoid race conditions */ flags = net_lock(); conn = (FAR struct tcp_conn_s *)psock->s_conn; /* If we have a semi-permanent write buffer callback in place, then * release it now. */ #ifdef CONFIG_NET_TCP_WRITE_BUFFERS if (psock->s_sndcb) { tcp_callback_free(conn, psock->s_sndcb); psock->s_sndcb = NULL; } #endif /* There shouldn't be any callbacks registered. */ DEBUGASSERT(conn && conn->list == NULL); /* Check for the case where the host beat us and disconnected first */ if (conn->tcpstateflags == TCP_ESTABLISHED && (state.cl_cb = tcp_callback_alloc(conn)) != NULL) { /* Set up to receive TCP data event callbacks */ state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT); state.cl_cb->event = netclose_interrupt; #ifdef CONFIG_NET_SOLINGER /* Check for a lingering close */ linger = _SO_GETOPT(psock->s_options, SO_LINGER); /* Has a lingering close been requested */ if (linger) { /* A non-NULL value of the priv field means that lingering is * enabled. */ state.cl_cb->priv = (FAR void *)&state; /* Set up for the lingering wait */ state.cl_psock = psock; state.cl_result = -EBUSY; sem_init(&state.cl_sem, 0, 0); /* Record the time that we started the wait (in ticks) */ state.cl_start = clock_systimer(); } else #endif /* CONFIG_NET_SOLINGER */ { /* We will close immediately. The NULL priv field signals this */ state.cl_cb->priv = NULL; /* No further references on the connection */ conn->crefs = 0; } /* Notify the device driver of the availability of TX data */ netdev_txnotify(conn->ripaddr); #ifdef CONFIG_NET_SOLINGER /* Wait only if we are lingering */ if (linger) { /* Wait for the disconnect event */ (void)net_lockedwait(&state.cl_sem); /* We are now disconnected */ sem_destroy(&state.cl_sem); tcp_callback_free(conn, state.cl_cb); /* Free the connection */ conn->crefs = 0; /* No more references on the connection */ tcp_free(conn); /* Free uIP resources */ /* Get the result of the close */ ret = state.cl_result; } #endif /* CONFIG_NET_SOLINGER */ } else { tcp_free(conn); } net_unlock(flags); return ret; }
ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen) { FAR struct udp_conn_s *conn; FAR struct net_driver_s *dev; struct sendto_s state; net_lock_t save; int ret; #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 { FAR const struct sockaddr_in *into; /* Make sure that the IP address mapping is in the ARP table */ into = (FAR const struct sockaddr_in *)to; ret = arp_send(into->sin_addr.s_addr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { FAR const struct sockaddr_in6 *into; /* Make sure that the IP address mapping is in the Neighbor Table */ into = (FAR const struct sockaddr_in6 *)to; ret = icmpv6_neighbor(into->sin6_addr.s6_addr16); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { ndbg("ERROR: Peer not reachable\n"); return -ENETUNREACH; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct sendto_s)); sem_init(&state.st_sem, 0, 0); state.st_buflen = len; state.st_buffer = buf; #if defined(CONFIG_NET_SENDTO_TIMEOUT) || defined(NEED_IPDOMAIN_SUPPORT) /* Save the reference to the socket structure if it will be needed for * asynchronous processing. */ state.st_sock = psock; #endif #ifdef CONFIG_NET_SENDTO_TIMEOUT /* Set the initial time for calculating timeouts */ state.st_time = clock_systimer(); #endif /* Setup the UDP socket. udp_connect will set the remote address in the * connection structure. */ conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn); ret = udp_connect(conn, to); if (ret < 0) { ndbg("ERROR: udp_connect failed: %d\n", ret); goto errout_with_lock; } /* Get the device that will handle the remote packet transfers. This * should never be NULL. */ dev = udp_find_raddr_device(conn); if (dev == NULL) { ndbg("ERROR: udp_find_raddr_device failed\n"); ret = -ENETUNREACH; goto errout_with_lock; } /* Set up the callback in the connection */ state.st_cb = udp_callback_alloc(dev, conn); if (state.st_cb) { state.st_cb->flags = (UDP_POLL | NETDEV_DOWN); state.st_cb->priv = (void*)&state; state.st_cb->event = sendto_interrupt; /* Notify the device driver of the availability of TX data */ netdev_txnotify_dev(dev); /* Wait for either the receive to complete or for an error/timeout 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. */ net_lockedwait(&state.st_sem); /* Make sure that no further interrupts are processed */ udp_callback_free(dev, conn, state.st_cb); } /* The result of the sendto operation is the number of bytes transferred */ ret = state.st_sndlen; errout_with_lock: /* Release the semaphore */ sem_destroy(&state.st_sem); /* Set the socket state back to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Unlock the network and return the result of the sendto() operation */ net_unlock(save); return ret; }
static int icmpv6_send_message(FAR struct net_driver_s *dev, bool advertise) { struct icmpv6_router_s state; int ret; /* Initialize the state structure. This is done with interrupts * disabled */ /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ sem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); #ifdef CONFIG_NETDEV_MULTINIC /* Remember the routing device name */ strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ); #endif /* 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. */ state.snd_cb = icmpv6_callback_alloc(dev); if (!state.snd_cb) { nerr("ERROR: Failed to allocate a cllback\n"); ret = -ENOMEM; goto errout_with_semaphore; } /* Arm the callback */ state.snd_sent = false; state.snd_result = -EBUSY; state.snd_advertise = advertise; state.snd_cb->flags = (ICMPv6_POLL | NETDEV_DOWN); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = icmpv6_router_interrupt; /* Notify the device driver that new TX data is available. */ dev->d_txavail(dev); /* 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. */ do { (void)net_lockedwait(&state.snd_sem); } while (!state.snd_sent); ret = state.snd_result; icmpv6_callback_free(dev, state.snd_cb); errout_with_semaphore: sem_destroy(&state.snd_sem); return ret; }
ssize_t ieee802154_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { FAR struct ieee802154_conn_s *conn = (FAR struct ieee802154_conn_s *)psock->s_conn; FAR struct radio_driver_s *radio; struct ieee802154_recvfrom_s state; ssize_t ret; /* If a 'from' address has been provided, verify that it is large * enough to hold this address family. */ if (from != NULL && *fromlen < sizeof(struct sockaddr_ieee802154_s)) { return -EINVAL; } if (psock->s_type != SOCK_DGRAM) { nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); return -EPROTONOSUPPORT; } /* Perform the packet recvfrom() operation */ /* Initialize the state structure. This is done with the network * locked because we don't want anything to happen until we are ready. */ net_lock(); memset(&state, 0, sizeof(struct ieee802154_recvfrom_s)); state.ir_buflen = len; state.ir_buffer = buf; state.ir_sock = psock; state.ir_from = from; /* Get the device driver that will service this transfer */ radio = ieee802154_find_device(conn, &conn->laddr); if (radio == NULL) { ret = -ENODEV; goto errout_with_lock; } /* Before we wait for data, let's check if there are already frame(s) * waiting in the RX queue. */ ret = ieee802154_recvfrom_rxqueue(radio, &state); if (ret > 0) { /* Good newe! We have a frame and we are done. */ net_unlock(); return ret; } /* We will have to wait. This semaphore is used for signaling and, * hence, should not have priority inheritance enabled. */ (void)nxsem_init(&state.ir_sem, 0, 0); /* Doesn't really fail */ (void)nxsem_setprotocol(&state.ir_sem, SEM_PRIO_NONE); /* Set the socket state to receiving */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); /* Set up the callback in the connection */ state.ir_cb = ieee802154_callback_alloc(&radio->r_dev, conn); if (state.ir_cb) { state.ir_cb->flags = (IEEE802154_NEWDATA | IEEE802154_POLL); state.ir_cb->priv = (FAR void *)&state; state.ir_cb->event = ieee802154_recvfrom_eventhandler; /* Wait for either the receive to complete or for an error/timeout to * occur. NOTES: (1) net_lockedwait will also terminate if a signal * is received, (2) the network is locked! It will be un-locked while * the task sleeps and automatically re-locked when the task restarts. */ (void)net_lockedwait(&state.ir_sem); /* Make sure that no further events are processed */ ieee802154_callback_free(&radio->r_dev, conn, state.ir_cb); ret = state.ir_result; } else { ret = -EBUSY; } /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); nxsem_destroy(&state.ir_sem); errout_with_lock: net_unlock(); return ret; }
static inline int psock_tcp_connect(FAR struct socket *psock, FAR const struct sockaddr_in *inaddr) #endif { struct tcp_connect_s state; net_lock_t flags; int ret = OK; /* Interrupts must be disabled through all of the following because * we cannot allow the network callback to occur until we are completely * setup. */ flags = net_lock(); /* Get the connection reference from the socket */ if (!psock->s_conn) /* Should always be non-NULL */ { ret = -EINVAL; } else { /* Perform the uIP connection operation */ ret = tcp_connect(psock->s_conn, inaddr); } if (ret >= 0) { /* Set up the callbacks in the connection */ ret = psock_setup_callbacks(psock, &state); if (ret >= 0) { /* Wait for either the connect to complete or for an error/timeout * 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-disabled * when the task restarts. */ ret = net_lockedwait(&state.tc_sem); /* Uninitialize the state structure */ (void)sem_destroy(&state.tc_sem); /* If net_lockedwait failed, recover the negated error (probably -EINTR) */ if (ret < 0) { ret = -errno; } else { /* If the wait succeeded, then get the new error value from * the state structure */ ret = state.tc_result; } /* Make sure that no further interrupts are processed */ psock_teardown_callbacks(&state, ret); } /* Mark the connection bound and connected */ if (ret >= 0) { psock->s_flags |= (_SF_BOUND|_SF_CONNECTED); } } net_unlock(flags); return ret; }