diff --git a/include/netinet/in.h b/include/netinet/in.h index 867095fcfa..3affebaa9b 100644 --- a/include/netinet/in.h +++ b/include/netinet/in.h @@ -132,6 +132,8 @@ * the incoming packet */ #define IPV6_TCLASS (__SO_PROTOCOL + 10) /* Access the Traffic Class * 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 */ diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h index 259a873bce..d930ca00d0 100644 --- a/net/icmpv6/icmpv6.h +++ b/net/icmpv6/icmpv6.h @@ -651,7 +651,7 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, * Description: * Implements the socket recvfrom interface for the case of the AF_INET * 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 * address, this source address is filled in. The argument 'msg_namelen' is diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c index 16378a7bdf..ec53103986 100644 --- a/net/icmpv6/icmpv6_input.c +++ b/net/icmpv6/icmpv6_input.c @@ -111,6 +111,7 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev, FAR struct ipv6_hdr_s *ipv6; struct sockaddr_in6 inaddr; FAR struct iob_s *iob; + unsigned int offset; uint16_t buflen; 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)); + 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) */ diff --git a/net/icmpv6/icmpv6_recvmsg.c b/net/icmpv6/icmpv6_recvmsg.c index ffffd2a23a..56e02bd3aa 100644 --- a/net/icmpv6/icmpv6_recvmsg.c +++ b/net/icmpv6/icmpv6_recvmsg.c @@ -36,6 +36,7 @@ #include "devif/devif.h" #include "socket/socket.h" #include "icmpv6/icmpv6.h" +#include "utils/utils.h" #ifdef CONFIG_NET_ICMPv6_SOCKET @@ -60,6 +61,7 @@ struct icmpv6_recvfrom_s * from */ FAR uint8_t *recv_buf; /* Location to return 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; * <0: negated errno on fail */ }; @@ -73,8 +75,8 @@ struct icmpv6_recvfrom_s * * Description: * 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 - * interfacing layer. + * ICMPv6 message actions when polled by the lower, device interfacing + * layer. * * Input Parameters: * 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; 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 */ { +#ifdef CONFIG_NET_SOCKOPTS + FAR struct icmpv6_conn_s *conn = psock->s_conn; +#endif 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 * out? */ @@ -132,7 +137,7 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev, 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? */ @@ -150,7 +155,17 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev, /* 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; goto end_wait; } @@ -196,9 +211,8 @@ end_wait: ****************************************************************************/ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn, - FAR void *buf, size_t buflen, - FAR struct sockaddr_in6 *from, - FAR socklen_t *fromlen) + FAR void *buf, size_t buflen, + FAR struct msghdr *msg) { FAR struct iob_s *iob; ssize_t ret = -ENODATA; @@ -213,11 +227,22 @@ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn, /* 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 */ ret = iob_copyout(buf, iob, buflen, 0); @@ -248,7 +273,7 @@ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn, * Description: * Implements the socket recvfrom interface for the case of the AF_INET * 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 * 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)) { - ret = icmpv6_readahead(conn, buf, len, - (FAR struct sockaddr_in6 *)from, fromlen); + ret = icmpv6_readahead(conn, buf, len, msg); } else if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (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_buf = buf; /* Location to return the response */ state.recv_buflen = len; /* Size of the response */ + state.msg = msg; /* Input message header */ /* Set up the callback */ diff --git a/net/inet/ipv6_setsockopt.c b/net/inet/ipv6_setsockopt.c index 0dc425f9ec..69692a6da1 100644 --- a/net/inet/ipv6_setsockopt.c +++ b/net/inet/ipv6_setsockopt.c @@ -128,6 +128,7 @@ int ipv6_setsockopt(FAR struct socket *psock, int option, break; case IPV6_RECVPKTINFO: + case IPV6_RECVHOPLIMIT: { FAR struct socket_conn_s *conn; int enable;