int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds) { FAR struct udp_conn_s *conn = psock->s_conn; FAR struct udp_poll_s *info; net_lock_t flags; /* Sanity check */ #ifdef CONFIG_DEBUG if (!conn || !fds->priv) { return -EINVAL; } #endif /* Recover the socket descriptor poll state info from the poll structure */ info = (FAR struct udp_poll_s *)fds->priv; DEBUGASSERT(info && info->fds && info->cb); if (info) { /* Release the callback */ flags = net_lock(); udp_callback_free(info->dev, conn, info->cb); net_unlock(flags); /* Release the poll/select data slot */ info->fds->priv = NULL; /* Then free the poll info container */ kmm_free(info); } return OK; }
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; }
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; }