in.h: add SOL_IPV6 protocol-level socket option IPV6_RECVHOPLIMIT

added IPV6_RECVHOPLIMIT support so that fd of SOCK_RAW ICMPV6 can obtain ttl
information, some network related tools use this feature.

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2023-04-14 18:11:12 +08:00 committed by Xiang Xiao
parent 7ab42f115e
commit e0816ff050
5 changed files with 49 additions and 17 deletions

View File

@ -132,6 +132,8 @@
* the incoming packet */ * the incoming packet */
#define IPV6_TCLASS (__SO_PROTOCOL + 10) /* Access the Traffic Class #define IPV6_TCLASS (__SO_PROTOCOL + 10) /* Access the Traffic Class
* field */ * field */
#define IPV6_RECVHOPLIMIT (__SO_PROTOCOL + 11) /* Access the hop limit field */
#define IPV6_HOPLIMIT (__SO_PROTOCOL + 12) /* Hop limit */
/* Values used with SIOCSIFMCFILTER and SIOCGIFMCFILTER ioctl's */ /* Values used with SIOCSIFMCFILTER and SIOCGIFMCFILTER ioctl's */

View File

@ -651,7 +651,7 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
* Description: * Description:
* Implements the socket recvfrom interface for the case of the AF_INET * Implements the socket recvfrom interface for the case of the AF_INET
* data gram socket with the IPPROTO_ICMP6 protocol. icmpv6_recvmsg() * data gram socket with the IPPROTO_ICMP6 protocol. icmpv6_recvmsg()
* receives ICMPv6 ECHO replies for the a socket. * receives ICMPv6 message for the a socket.
* *
* If msg_name is not NULL, and the underlying protocol provides the source * If msg_name is not NULL, and the underlying protocol provides the source
* address, this source address is filled in. The argument 'msg_namelen' is * address, this source address is filled in. The argument 'msg_namelen' is

View File

@ -111,6 +111,7 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
FAR struct ipv6_hdr_s *ipv6; FAR struct ipv6_hdr_s *ipv6;
struct sockaddr_in6 inaddr; struct sockaddr_in6 inaddr;
FAR struct iob_s *iob; FAR struct iob_s *iob;
unsigned int offset;
uint16_t buflen; uint16_t buflen;
int ret; int ret;
@ -132,8 +133,11 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
*/ */
memcpy(iob->io_data, &inaddr, sizeof(struct sockaddr_in6)); memcpy(iob->io_data, &inaddr, sizeof(struct sockaddr_in6));
offset = sizeof(struct sockaddr_in6);
iob_reserve(iob, sizeof(struct sockaddr_in6)); iob->io_data[offset++] = ipv6->ttl;
iob_reserve(iob, offset);
/* Copy the ICMPv6 message into the I/O buffer chain (without waiting) */ /* Copy the ICMPv6 message into the I/O buffer chain (without waiting) */

View File

@ -36,6 +36,7 @@
#include "devif/devif.h" #include "devif/devif.h"
#include "socket/socket.h" #include "socket/socket.h"
#include "icmpv6/icmpv6.h" #include "icmpv6/icmpv6.h"
#include "utils/utils.h"
#ifdef CONFIG_NET_ICMPv6_SOCKET #ifdef CONFIG_NET_ICMPv6_SOCKET
@ -60,6 +61,7 @@ struct icmpv6_recvfrom_s
* from */ * from */
FAR uint8_t *recv_buf; /* Location to return the response */ FAR uint8_t *recv_buf; /* Location to return the response */
uint16_t recv_buflen; /* Size of the response */ uint16_t recv_buflen; /* Size of the response */
FAR struct msghdr *msg; /* Input message header */
int16_t recv_result; /* >=0: receive size on success; int16_t recv_result; /* >=0: receive size on success;
* <0: negated errno on fail */ * <0: negated errno on fail */
}; };
@ -73,8 +75,8 @@ struct icmpv6_recvfrom_s
* *
* Description: * Description:
* This function is called with the network locked to perform the actual * This function is called with the network locked to perform the actual
* ECHO request and/or ECHO reply actions when polled by the lower, device * ICMPv6 message actions when polled by the lower, device interfacing
* interfacing layer. * layer.
* *
* Input Parameters: * Input Parameters:
* dev The structure of the network driver that generated the * dev The structure of the network driver that generated the
@ -113,15 +115,18 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
psock = pstate->recv_sock; psock = pstate->recv_sock;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL); DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
/* Check if we have just received a ICMPv6 ECHO reply. */ /* Check if we have just received a ICMPv6 message. */
if ((flags & ICMPv6_NEWDATA) != 0) /* No incoming data */ if ((flags & ICMPv6_NEWDATA) != 0) /* No incoming data */
{ {
#ifdef CONFIG_NET_SOCKOPTS
FAR struct icmpv6_conn_s *conn = psock->s_conn;
#endif
unsigned int recvsize; unsigned int recvsize;
ninfo("Received ICMPv6 reply\n"); ninfo("Received ICMPv6 message\n");
/* What should we do if the received reply is larger that the /* What should we do if the received message is larger that the
* buffer that the caller of sendto provided? Truncate? Error * buffer that the caller of sendto provided? Truncate? Error
* out? * out?
*/ */
@ -132,7 +137,7 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
recvsize = pstate->recv_buflen; recvsize = pstate->recv_buflen;
} }
/* Copy the ICMPv6 ECHO reply to the user provided buffer /* Copy the ICMPv6 message to the user provided buffer
* REVISIT: What if there are IPv6 extension headers present? * REVISIT: What if there are IPv6 extension headers present?
*/ */
@ -150,7 +155,17 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
/* Indicate that the data has been consumed */ /* Indicate that the data has been consumed */
flags &= ~ICMPv6_NEWDATA; flags &= ~ICMPv6_NEWDATA;
#ifdef CONFIG_NET_SOCKOPTS
if (_SO_GETOPT(conn->sconn.s_options, IPV6_RECVHOPLIMIT))
{
int hoplimit = ipv6->ttl;
cmsg_append(pstate->msg, SOL_IPV6, IPV6_HOPLIMIT,
&hoplimit, sizeof(hoplimit));
}
#endif
dev->d_len = 0; dev->d_len = 0;
goto end_wait; goto end_wait;
} }
@ -196,9 +211,8 @@ end_wait:
****************************************************************************/ ****************************************************************************/
static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn, static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn,
FAR void *buf, size_t buflen, FAR void *buf, size_t buflen,
FAR struct sockaddr_in6 *from, FAR struct msghdr *msg)
FAR socklen_t *fromlen)
{ {
FAR struct iob_s *iob; FAR struct iob_s *iob;
ssize_t ret = -ENODATA; ssize_t ret = -ENODATA;
@ -213,11 +227,22 @@ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn,
/* Then get address */ /* Then get address */
if (from != NULL) if (msg->msg_name != NULL)
{ {
memcpy(from, iob->io_data, sizeof(struct sockaddr_in6)); memcpy(msg->msg_name, iob->io_data, sizeof(struct sockaddr_in6));
} }
#ifdef CONFIG_NET_SOCKOPTS
if (_SO_GETOPT(conn->sconn.s_options, IPV6_RECVHOPLIMIT))
{
int hoplimit;
hoplimit = iob->io_data[sizeof(struct sockaddr_in6)];
cmsg_append(msg, SOL_IPV6, IPV6_HOPLIMIT,
&hoplimit, sizeof(hoplimit));
}
#endif
/* Copy to user */ /* Copy to user */
ret = iob_copyout(buf, iob, buflen, 0); ret = iob_copyout(buf, iob, buflen, 0);
@ -248,7 +273,7 @@ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn,
* Description: * Description:
* Implements the socket recvfrom interface for the case of the AF_INET * Implements the socket recvfrom interface for the case of the AF_INET
* data gram socket with the IPPROTO_ICMP6 protocol. icmpv6_recvmsg() * data gram socket with the IPPROTO_ICMP6 protocol. icmpv6_recvmsg()
* receives ICMPv6 ECHO replies for the a socket. * receives ICMPv6 message for the a socket.
* *
* If msg_name is not NULL, and the underlying protocol provides the source * If msg_name is not NULL, and the underlying protocol provides the source
* address, this source address is filled in. The argument 'msg_namelen' is * address, this source address is filled in. The argument 'msg_namelen' is
@ -325,8 +350,7 @@ ssize_t icmpv6_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
if (!IOB_QEMPTY(&conn->readahead)) if (!IOB_QEMPTY(&conn->readahead))
{ {
ret = icmpv6_readahead(conn, buf, len, ret = icmpv6_readahead(conn, buf, len, msg);
(FAR struct sockaddr_in6 *)from, fromlen);
} }
else if (_SS_ISNONBLOCK(conn->sconn.s_flags) || else if (_SS_ISNONBLOCK(conn->sconn.s_flags) ||
(flags & MSG_DONTWAIT) != 0) (flags & MSG_DONTWAIT) != 0)
@ -346,6 +370,7 @@ ssize_t icmpv6_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
state.recv_result = -ENOMEM; /* Assume allocation failure */ state.recv_result = -ENOMEM; /* Assume allocation failure */
state.recv_buf = buf; /* Location to return the response */ state.recv_buf = buf; /* Location to return the response */
state.recv_buflen = len; /* Size of the response */ state.recv_buflen = len; /* Size of the response */
state.msg = msg; /* Input message header */
/* Set up the callback */ /* Set up the callback */

View File

@ -128,6 +128,7 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
break; break;
case IPV6_RECVPKTINFO: case IPV6_RECVPKTINFO:
case IPV6_RECVHOPLIMIT:
{ {
FAR struct socket_conn_s *conn; FAR struct socket_conn_s *conn;
int enable; int enable;