udp: add IPVx_PKTINFO related support
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
parent
94cf99f310
commit
9bff29d7e7
9 changed files with 268 additions and 130 deletions
|
|
@ -127,6 +127,8 @@
|
|||
* to IPv6 communications only */
|
||||
#define IPV6_PKTINFO (__SO_PROTOCOL + 8) /* Get some information about
|
||||
* the incoming packet */
|
||||
#define IPV6_RECVPKTINFO (__SO_PROTOCOL + 9) /* It functions just same as
|
||||
* IPV6_PKTINFO for now */
|
||||
|
||||
/* Values used with SIOCSIFMCFILTER and SIOCGIFMCFILTER ioctl's */
|
||||
|
||||
|
|
|
|||
|
|
@ -1569,17 +1569,13 @@ static ssize_t inet_sendfile(FAR struct socket *psock,
|
|||
static ssize_t inet_recvmsg(FAR struct socket *psock,
|
||||
FAR struct msghdr *msg, int flags)
|
||||
{
|
||||
FAR void *buf = msg->msg_iov->iov_base;
|
||||
size_t len = msg->msg_iov->iov_len;
|
||||
FAR struct sockaddr *from = msg->msg_name;
|
||||
FAR socklen_t *fromlen = &msg->msg_namelen;
|
||||
ssize_t ret;
|
||||
|
||||
/* If a 'from' address has been provided, verify that it is large
|
||||
* enough to hold this address family.
|
||||
*/
|
||||
|
||||
if (from)
|
||||
if (msg->msg_name)
|
||||
{
|
||||
socklen_t minlen;
|
||||
|
||||
|
|
@ -1608,7 +1604,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (*fromlen < minlen)
|
||||
if (msg->msg_namelen < minlen)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1624,7 +1620,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
|
|||
case SOCK_STREAM:
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
ret = psock_tcp_recvfrom(psock, buf, len, flags, from, fromlen);
|
||||
ret = psock_tcp_recvfrom(psock, msg, flags);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif
|
||||
|
|
@ -1636,7 +1632,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
|
|||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
ret = psock_udp_recvfrom(psock, buf, len, flags, from, fromlen);
|
||||
ret = psock_udp_recvfrom(psock, msg, flags);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -203,6 +203,34 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
|
|||
}
|
||||
break;
|
||||
|
||||
case IP_PKTINFO:
|
||||
{
|
||||
FAR struct udp_conn_s *conn;
|
||||
int enable;
|
||||
|
||||
if (psock->s_type != SOCK_DGRAM ||
|
||||
value == NULL || value_len == 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
enable = (value_len >= sizeof(int)) ?
|
||||
*(FAR int *)value : (int)*(FAR unsigned char *)value;
|
||||
conn = (FAR struct udp_conn_s *)psock->s_conn;
|
||||
if (enable)
|
||||
{
|
||||
conn->flags |= _UDP_FLAG_PKTINFO;
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->flags &= ~_UDP_FLAG_PKTINFO;
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
break;
|
||||
|
||||
/* The following IPv4 socket options are defined, but not implemented */
|
||||
|
||||
case IP_MULTICAST_IF: /* Set local device for a multicast
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "mld/mld.h"
|
||||
#include "inet/inet.h"
|
||||
#include "udp/udp.h"
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
|
||||
|
|
@ -110,6 +111,35 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
|
|||
}
|
||||
break;
|
||||
|
||||
case IPV6_PKTINFO:
|
||||
case IPV6_RECVPKTINFO:
|
||||
{
|
||||
FAR struct udp_conn_s *conn;
|
||||
int enable;
|
||||
|
||||
if (psock->s_type != SOCK_DGRAM ||
|
||||
value == NULL || value_len == 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
enable = (value_len >= sizeof(int)) ?
|
||||
*(FAR int *)value : (int)*(FAR unsigned char *)value;
|
||||
conn = (FAR struct udp_conn_s *)psock->s_conn;
|
||||
if (enable)
|
||||
{
|
||||
conn->flags |= _UDP_FLAG_PKTINFO;
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->flags &= ~_UDP_FLAG_PKTINFO;
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
break;
|
||||
|
||||
/* The following IPv6 socket options are defined, but not implemented */
|
||||
|
||||
case IPV6_MULTICAST_HOPS: /* Multicast hop limit */
|
||||
|
|
|
|||
|
|
@ -1378,11 +1378,8 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
*
|
||||
* Input Parameters:
|
||||
* psock Pointer to the socket structure for the SOCK_DRAM socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* msg Receive info and buffer for receive data
|
||||
* flags Receive flags
|
||||
* from INET address of source (may be NULL)
|
||||
* fromlen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. On error,
|
||||
|
|
@ -1392,9 +1389,8 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
int flags);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_tcp_send
|
||||
|
|
|
|||
|
|
@ -594,11 +594,8 @@ static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate)
|
|||
*
|
||||
* Input Parameters:
|
||||
* psock Pointer to the socket structure for the SOCK_DRAM socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* msg Receive info and buffer for receive data
|
||||
* flags Receive flags
|
||||
* from INET address of source (may be NULL)
|
||||
* fromlen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. On error,
|
||||
|
|
@ -608,10 +605,13 @@ static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen)
|
||||
ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
int flags)
|
||||
{
|
||||
FAR struct sockaddr *from = msg->msg_name;
|
||||
FAR socklen_t *fromlen = &msg->msg_namelen;
|
||||
FAR void *buf = msg->msg_iov->iov_base;
|
||||
size_t len = msg->msg_iov->iov_len;
|
||||
struct tcp_recvfrom_s state;
|
||||
FAR struct tcp_conn_s *conn;
|
||||
int ret;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
/* Definitions for the UDP connection struct flag field */
|
||||
|
||||
#define _UDP_FLAG_CONNECTMODE (1 << 0) /* Bit 0: UDP connection-mode */
|
||||
#define _UDP_FLAG_PKTINFO (1 << 1) /* Bit 1: UDP PKTINFO */
|
||||
|
||||
#define _UDP_ISCONNECTMODE(f) (((f) & _UDP_FLAG_CONNECTMODE) != 0)
|
||||
|
||||
|
|
@ -689,11 +690,8 @@ uint16_t udp_callback(FAR struct net_driver_s *dev,
|
|||
*
|
||||
* Input Parameters:
|
||||
* psock Pointer to the socket structure for the SOCK_DRAM socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* msg Receive info and buffer for receive data
|
||||
* flags Receive flags
|
||||
* from INET address of source (may be NULL)
|
||||
* fromlen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. On error,
|
||||
|
|
@ -703,9 +701,8 @@ uint16_t udp_callback(FAR struct net_driver_s *dev,
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
int flags);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_udp_sendto
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
|
|||
|
||||
FAR void *src_addr;
|
||||
uint8_t src_addr_size;
|
||||
uint8_t offset = 0;
|
||||
|
||||
#if CONFIG_NET_RECV_BUFSIZE > 0
|
||||
while (iob_get_queue_size(&conn->readahead) > conn->rcvbufs)
|
||||
|
|
@ -172,7 +173,8 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
|
|||
*/
|
||||
|
||||
ret = iob_trycopyin(iob, (FAR const uint8_t *)&src_addr_size,
|
||||
sizeof(uint8_t), 0, true);
|
||||
sizeof(uint8_t), offset, true);
|
||||
offset += sizeof(uint8_t);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* On a failure, iob_trycopyin return a negated error value but does
|
||||
|
|
@ -185,7 +187,8 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
|
|||
}
|
||||
|
||||
ret = iob_trycopyin(iob, (FAR const uint8_t *)src_addr, src_addr_size,
|
||||
sizeof(uint8_t), true);
|
||||
offset, true);
|
||||
offset += src_addr_size;
|
||||
if (ret < 0)
|
||||
{
|
||||
/* On a failure, iob_trycopyin return a negated error value but does
|
||||
|
|
@ -197,12 +200,26 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETDEV_IFINDEX
|
||||
ret = iob_trycopyin(iob, &dev->d_ifindex, sizeof(uint8_t), offset, true);
|
||||
offset += sizeof(uint8_t);
|
||||
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 dindex to the I/O buffer chain: %d\n", ret);
|
||||
iob_free_chain(iob);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
ret = iob_trycopyin(iob, buffer, buflen, offset, true);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* On a failure, iob_trycopyin return a negated error value but
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/ip.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "devif/devif.h"
|
||||
|
|
@ -60,11 +61,8 @@ struct udp_recvfrom_s
|
|||
{
|
||||
FAR struct udp_conn_s *ir_conn; /* Connection associated with the socket */
|
||||
FAR struct devif_callback_s *ir_cb; /* Reference to callback instance */
|
||||
FAR struct msghdr *ir_msg; /* Receive info and buffer */
|
||||
sem_t ir_sem; /* Semaphore signals recv completion */
|
||||
size_t ir_buflen; /* Length of receive buffer */
|
||||
uint8_t *ir_buffer; /* Pointer to receive buffer */
|
||||
FAR struct sockaddr *ir_from; /* Address of sender */
|
||||
FAR socklen_t *ir_fromlen; /* Number of bytes allocated for address of sender */
|
||||
ssize_t ir_recvlen; /* The received length */
|
||||
int ir_result; /* Success:OK, failure:negated errno */
|
||||
};
|
||||
|
|
@ -99,8 +97,64 @@ static inline void udp_update_recvlen(FAR struct udp_recvfrom_s *pstate,
|
|||
}
|
||||
|
||||
pstate->ir_recvlen += recvlen;
|
||||
pstate->ir_buffer += recvlen;
|
||||
pstate->ir_buflen -= recvlen;
|
||||
}
|
||||
|
||||
static void udp_recvpktinfo(FAR struct udp_recvfrom_s *pstate,
|
||||
FAR void *srcaddr, uint8_t ifindex)
|
||||
{
|
||||
FAR struct msghdr *msg = pstate->ir_msg;
|
||||
FAR struct udp_conn_s *conn = pstate->ir_conn;
|
||||
FAR struct cmsghdr *control = msg->msg_control;
|
||||
size_t cmsg_len = 0;
|
||||
|
||||
if (!(conn->flags & _UDP_FLAG_PKTINFO))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
if (conn->domain == PF_INET)
|
||||
{
|
||||
FAR struct sockaddr_in *infrom = srcaddr;
|
||||
FAR struct in_pktinfo *pkt_info = CMSG_DATA(control);
|
||||
|
||||
if (msg->msg_controllen < CMSG_LEN(sizeof(struct in_pktinfo)))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
control->cmsg_level = IPPROTO_IP;
|
||||
control->cmsg_type = IP_PKTINFO;
|
||||
control->cmsg_len = cmsg_len;
|
||||
pkt_info->ipi_ifindex = ifindex;
|
||||
pkt_info->ipi_addr.s_addr = infrom->sin_addr.s_addr;
|
||||
pkt_info->ipi_spec_dst.s_addr = conn->u.ipv4.laddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (conn->domain == PF_INET6)
|
||||
{
|
||||
FAR struct sockaddr_in6 *infrom = srcaddr;
|
||||
FAR struct in6_pktinfo *pkt_info = CMSG_DATA(control);
|
||||
|
||||
if (msg->msg_controllen < CMSG_LEN(sizeof(struct in6_pktinfo)))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
control->cmsg_level = IPPROTO_IPV6;
|
||||
control->cmsg_type = IPV6_PKTINFO;
|
||||
control->cmsg_len = cmsg_len;
|
||||
pkt_info->ipi6_ifindex = ifindex;
|
||||
net_ipv6addr_copy(&pkt_info->ipi6_addr, infrom->sin6_addr.s6_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
msg->msg_controllen = cmsg_len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -128,9 +182,9 @@ static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
|
|||
|
||||
/* Get the length of the data to return */
|
||||
|
||||
if (dev->d_len > pstate->ir_buflen)
|
||||
if (dev->d_len > pstate->ir_msg->msg_iov->iov_len)
|
||||
{
|
||||
recvlen = pstate->ir_buflen;
|
||||
recvlen = pstate->ir_msg->msg_iov->iov_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -139,7 +193,7 @@ static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
|
|||
|
||||
/* Copy the new appdata into the user buffer */
|
||||
|
||||
memcpy(pstate->ir_buffer, dev->d_appdata, recvlen);
|
||||
memcpy(pstate->ir_msg->msg_iov->iov_base, dev->d_appdata, recvlen);
|
||||
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
|
||||
|
||||
/* Update the accumulated size of the data read */
|
||||
|
|
@ -194,7 +248,14 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
|
|||
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
|
||||
{
|
||||
FAR struct iob_s *tmp;
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
uint8_t srcaddr[sizeof(struct sockaddr_in6)];
|
||||
#else
|
||||
uint8_t srcaddr[sizeof(struct sockaddr_in)];
|
||||
#endif
|
||||
uint8_t src_addr_size;
|
||||
uint8_t offset = 0;
|
||||
uint8_t ifindex = 0;
|
||||
|
||||
DEBUGASSERT(iob->io_pktlen > 0);
|
||||
|
||||
|
|
@ -202,12 +263,29 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
|
|||
* the user buffer.
|
||||
*/
|
||||
|
||||
recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), 0);
|
||||
recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), offset);
|
||||
offset += sizeof(uint8_t);
|
||||
if (recvlen != sizeof(uint8_t))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
recvlen = iob_copyout(srcaddr, iob, src_addr_size, offset);
|
||||
offset += src_addr_size;
|
||||
if (recvlen != src_addr_size)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETDEV_IFINDEX
|
||||
recvlen = iob_copyout(&ifindex, iob, sizeof(uint8_t), offset);
|
||||
offset += sizeof(uint8_t);
|
||||
if (recvlen != sizeof(uint8_t))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (0
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
|| src_addr_size == sizeof(struct sockaddr_in6)
|
||||
|
|
@ -217,40 +295,36 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
|
|||
#endif
|
||||
)
|
||||
{
|
||||
if (pstate->ir_from)
|
||||
if (pstate->ir_msg->msg_name)
|
||||
{
|
||||
socklen_t len = *pstate->ir_fromlen;
|
||||
len = (socklen_t)
|
||||
src_addr_size > len ? len : (socklen_t)src_addr_size;
|
||||
pstate->ir_msg->msg_namelen =
|
||||
src_addr_size > pstate->ir_msg->msg_namelen ?
|
||||
pstate->ir_msg->msg_namelen : src_addr_size;
|
||||
|
||||
recvlen = iob_copyout((FAR uint8_t *)pstate->ir_from, iob,
|
||||
len, sizeof(uint8_t));
|
||||
if (recvlen != len)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
memcpy(pstate->ir_msg->msg_name, srcaddr,
|
||||
pstate->ir_msg->msg_namelen);
|
||||
}
|
||||
}
|
||||
|
||||
if (pstate->ir_buflen > 0)
|
||||
if (pstate->ir_msg->msg_iov->iov_len > 0)
|
||||
{
|
||||
recvlen = iob_copyout(pstate->ir_buffer, iob, pstate->ir_buflen,
|
||||
src_addr_size + sizeof(uint8_t));
|
||||
recvlen = iob_copyout(pstate->ir_msg->msg_iov->iov_base,
|
||||
iob, pstate->ir_msg->msg_iov->iov_len,
|
||||
offset);
|
||||
|
||||
ninfo("Received %d bytes (of %d)\n", recvlen, iob->io_pktlen);
|
||||
|
||||
/* Update the accumulated size of the data read */
|
||||
|
||||
pstate->ir_recvlen = recvlen;
|
||||
pstate->ir_buffer += recvlen;
|
||||
pstate->ir_buflen -= recvlen;
|
||||
*pstate->ir_fromlen = src_addr_size;
|
||||
pstate->ir_recvlen = recvlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
pstate->ir_recvlen = 0;
|
||||
}
|
||||
|
||||
udp_recvpktinfo(pstate, srcaddr, ifindex);
|
||||
|
||||
out:
|
||||
/* Remove the I/O buffer chain from the head of the read-ahead
|
||||
* buffer queue.
|
||||
|
|
@ -287,6 +361,13 @@ out:
|
|||
static inline void udp_sender(FAR struct net_driver_s *dev,
|
||||
FAR struct udp_recvfrom_s *pstate)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
uint8_t srcaddr[sizeof(struct sockaddr_in6)];
|
||||
#else
|
||||
uint8_t srcaddr[sizeof(struct sockaddr_in)];
|
||||
#endif
|
||||
socklen_t fromlen = 0;
|
||||
|
||||
/* Get the family from the packet type, IP address from the IP header, and
|
||||
* the port number from the UDP header.
|
||||
*/
|
||||
|
|
@ -296,21 +377,15 @@ static inline void udp_sender(FAR struct net_driver_s *dev,
|
|||
if (IFF_IS_IPv6(dev->d_flags))
|
||||
#endif
|
||||
{
|
||||
FAR struct sockaddr_in6 *infrom =
|
||||
(FAR struct sockaddr_in6 *)pstate->ir_from;
|
||||
FAR socklen_t *fromlen = pstate->ir_fromlen;
|
||||
FAR struct sockaddr_in6 *infrom = (FAR struct sockaddr_in6 *)srcaddr;
|
||||
FAR struct udp_hdr_s *udp = UDPIPv6BUF;
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
|
||||
if (infrom)
|
||||
{
|
||||
FAR struct udp_hdr_s *udp = UDPIPv6BUF;
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
infrom->sin6_family = AF_INET6;
|
||||
infrom->sin6_port = udp->srcport;
|
||||
fromlen = sizeof(struct sockaddr_in6);
|
||||
|
||||
infrom->sin6_family = AF_INET6;
|
||||
infrom->sin6_port = udp->srcport;
|
||||
*fromlen = sizeof(struct sockaddr_in6);
|
||||
|
||||
net_ipv6addr_copy(infrom->sin6_addr.s6_addr, ipv6->srcipaddr);
|
||||
}
|
||||
net_ipv6addr_copy(infrom->sin6_addr.s6_addr, ipv6->srcipaddr);
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
|
||||
|
|
@ -319,53 +394,59 @@ static inline void udp_sender(FAR struct net_driver_s *dev,
|
|||
else
|
||||
#endif
|
||||
{
|
||||
FAR struct sockaddr_in *infrom =
|
||||
(FAR struct sockaddr_in *)pstate->ir_from;
|
||||
FAR socklen_t *fromlen = pstate->ir_fromlen;
|
||||
|
||||
if (infrom)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
FAR struct udp_conn_s *conn = pstate->ir_conn;
|
||||
FAR struct udp_conn_s *conn = pstate->ir_conn;
|
||||
|
||||
if (conn->domain == PF_INET6)
|
||||
{
|
||||
/* Hybrid dual-stack IPv6/IPv4 implementations recognize a special
|
||||
* class of addresses, the IPv4-mapped IPv6 addresses.
|
||||
*/
|
||||
|
||||
if (conn->domain == PF_INET6)
|
||||
{
|
||||
FAR struct sockaddr_in6 *infrom6 =
|
||||
(FAR struct sockaddr_in6 *)infrom;
|
||||
FAR struct udp_hdr_s *udp = UDPIPv6BUF;
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
in_addr_t ipv4addr;
|
||||
FAR struct sockaddr_in6 *infrom6 =
|
||||
(FAR struct sockaddr_in6 *)srcaddr;
|
||||
FAR struct udp_hdr_s *udp = UDPIPv6BUF;
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
in_addr_t ipv4addr;
|
||||
|
||||
/* Encode the IPv4 address as an IPv4-mapped IPv6 address */
|
||||
/* Encode the IPv4 address as an IPv4-mapped IPv6 address */
|
||||
|
||||
infrom6->sin6_family = AF_INET6;
|
||||
infrom6->sin6_port = udp->srcport;
|
||||
*fromlen = sizeof(struct sockaddr_in6);
|
||||
|
||||
ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
|
||||
ip6_map_ipv4addr(ipv4addr, infrom6->sin6_addr.s6_addr16);
|
||||
}
|
||||
else
|
||||
infrom6->sin6_family = AF_INET6;
|
||||
infrom6->sin6_port = udp->srcport;
|
||||
fromlen = sizeof(struct sockaddr_in6);
|
||||
ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
|
||||
ip6_map_ipv4addr(ipv4addr, infrom6->sin6_addr.s6_addr16);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
FAR struct udp_hdr_s *udp = UDPIPv4BUF;
|
||||
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
|
||||
{
|
||||
FAR struct sockaddr_in *infrom = (FAR struct sockaddr_in *)srcaddr;
|
||||
FAR struct udp_hdr_s *udp = UDPIPv4BUF;
|
||||
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
|
||||
|
||||
infrom->sin_family = AF_INET;
|
||||
infrom->sin_port = udp->srcport;
|
||||
*fromlen = sizeof(struct sockaddr_in);
|
||||
infrom->sin_family = AF_INET;
|
||||
infrom->sin_port = udp->srcport;
|
||||
fromlen = sizeof(struct sockaddr_in);
|
||||
|
||||
net_ipv4addr_copy(infrom->sin_addr.s_addr,
|
||||
net_ip4addr_conv32(ipv4->srcipaddr));
|
||||
memset(infrom->sin_zero, 0, sizeof(infrom->sin_zero));
|
||||
}
|
||||
net_ipv4addr_copy(infrom->sin_addr.s_addr,
|
||||
net_ip4addr_conv32(ipv4->srcipaddr));
|
||||
memset(infrom->sin_zero, 0, sizeof(infrom->sin_zero));
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
if (pstate->ir_msg->msg_name)
|
||||
{
|
||||
pstate->ir_msg->msg_namelen = fromlen > pstate->ir_msg->msg_namelen ?
|
||||
pstate->ir_msg->msg_namelen : fromlen;
|
||||
memcpy(pstate->ir_msg->msg_name, srcaddr, pstate->ir_msg->msg_namelen);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETDEV_IFINDEX
|
||||
udp_recvpktinfo(pstate, srcaddr, dev->d_ifindex);
|
||||
#else
|
||||
udp_recvpktinfo(pstate, srcaddr, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -387,13 +468,13 @@ static void udp_terminate(FAR struct udp_recvfrom_s *pstate, int result)
|
|||
{
|
||||
/* Don't allow any further UDP call backs. */
|
||||
|
||||
pstate->ir_cb->flags = 0;
|
||||
pstate->ir_cb->priv = NULL;
|
||||
pstate->ir_cb->event = NULL;
|
||||
pstate->ir_cb->flags = 0;
|
||||
pstate->ir_cb->priv = NULL;
|
||||
pstate->ir_cb->event = NULL;
|
||||
|
||||
/* Save the result of the transfer */
|
||||
|
||||
pstate->ir_result = result;
|
||||
pstate->ir_result = result;
|
||||
|
||||
/* Wake up the waiting thread, returning the number of bytes
|
||||
* actually read.
|
||||
|
|
@ -482,8 +563,7 @@ static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
|
|||
*
|
||||
* Input Parameters:
|
||||
* conn The UDP connection of interest
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* msg Receive info and buffer for receive data
|
||||
* pstate A pointer to the state structure to be initialized
|
||||
*
|
||||
* Returned Value:
|
||||
|
|
@ -494,9 +574,7 @@ static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
|
|||
****************************************************************************/
|
||||
|
||||
static void udp_recvfrom_initialize(FAR struct udp_conn_s *conn,
|
||||
FAR void *buf, size_t len,
|
||||
FAR struct sockaddr *infrom,
|
||||
FAR socklen_t *fromlen,
|
||||
FAR struct msghdr *msg,
|
||||
FAR struct udp_recvfrom_s *pstate)
|
||||
{
|
||||
/* Initialize the state structure. */
|
||||
|
|
@ -510,14 +588,11 @@ static void udp_recvfrom_initialize(FAR struct udp_conn_s *conn,
|
|||
nxsem_init(&pstate->ir_sem, 0, 0); /* Doesn't really fail */
|
||||
nxsem_set_protocol(&pstate->ir_sem, SEM_PRIO_NONE);
|
||||
|
||||
pstate->ir_buflen = len;
|
||||
pstate->ir_buffer = buf;
|
||||
pstate->ir_from = infrom;
|
||||
pstate->ir_fromlen = fromlen;
|
||||
pstate->ir_msg = msg;
|
||||
|
||||
/* Set up the start time for the timeout */
|
||||
|
||||
pstate->ir_conn = conn;
|
||||
pstate->ir_conn = conn;
|
||||
}
|
||||
|
||||
/* The only un-initialization that has to be performed is destroying the
|
||||
|
|
@ -583,9 +658,7 @@ static ssize_t udp_recvfrom_result(int result, struct udp_recvfrom_s *pstate)
|
|||
*
|
||||
* Input Parameters:
|
||||
* psock Pointer to the socket structure for the SOCK_DRAM socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* from INET address of source (may be NULL)
|
||||
* msg Receive info and buffer for receive data
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. On error,
|
||||
|
|
@ -595,9 +668,8 @@ static ssize_t udp_recvfrom_result(int result, struct udp_recvfrom_s *pstate)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen)
|
||||
ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
int flags)
|
||||
{
|
||||
FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)psock->s_conn;
|
||||
FAR struct net_driver_s *dev;
|
||||
|
|
@ -611,7 +683,7 @@ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
|
|||
*/
|
||||
|
||||
net_lock();
|
||||
udp_recvfrom_initialize(conn, buf, len, from, fromlen, &state);
|
||||
udp_recvfrom_initialize(conn, msg, &state);
|
||||
|
||||
/* Copy the read-ahead data from the packet */
|
||||
|
||||
|
|
@ -665,9 +737,9 @@ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
|
|||
{
|
||||
/* Set up the callback in the connection */
|
||||
|
||||
state.ir_cb->flags = (UDP_NEWDATA | NETDEV_DOWN);
|
||||
state.ir_cb->priv = (FAR void *)&state;
|
||||
state.ir_cb->event = udp_eventhandler;
|
||||
state.ir_cb->flags = (UDP_NEWDATA | NETDEV_DOWN);
|
||||
state.ir_cb->priv = (FAR void *)&state;
|
||||
state.ir_cb->event = udp_eventhandler;
|
||||
|
||||
/* Wait for either the receive to complete or for an error/timeout
|
||||
* to occur. net_timedwait will also terminate if a signal is
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue