icmpv6: add SOCK_RAW type support

The third-party library we are porting will send and receive ICMPV6 messages
(router_advert / router_solicit / neighbor_advert / neighbor_solicit etc.)
from the user mode itself, so we added the SOCK_RAW related implementation
for ICMPV6.

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2023-04-23 11:25:28 +08:00 committed by Xiang Xiao
parent 6bf989159e
commit 35dee8fdd2
7 changed files with 406 additions and 152 deletions

View File

@ -30,6 +30,7 @@
#include <sys/types.h>
#include <stdint.h>
#include <assert.h>
#include <netinet/icmp6.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/ip.h>
@ -84,7 +85,6 @@ struct icmpv6_conn_s
/* ICMPv6-specific content follows */
uint16_t id; /* ICMPv6 ECHO request ID */
uint8_t nreqs; /* Number of requests with no response received */
uint8_t crefs; /* Reference counts on this instance */
/* The device that the ICMPv6 request was sent on */
@ -97,6 +97,7 @@ struct icmpv6_conn_s
*/
struct iob_queue_s readahead; /* Read-ahead buffering */
struct icmp6_filter filter; /* ICMP6 type filter */
/* The following is a list of poll structures of threads waiting for
* socket events.
@ -104,6 +105,11 @@ struct icmpv6_conn_s
struct icmpv6_poll_s pollinfo[CONFIG_NET_ICMPv6_NPOLLWAITERS];
};
/* Callback from icmpv6_foreach() */
typedef int (*icmpv6_callback_t)(FAR struct icmpv6_conn_s *conn,
FAR void *arg);
#endif
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
@ -596,11 +602,12 @@ FAR struct icmpv6_conn_s *icmpv6_nextconn(FAR struct icmpv6_conn_s *conn);
#endif
/****************************************************************************
* Name: icmpv6_findconn
* Name: icmpv6_foreach
*
* Description:
* Find an ICMPv6 connection structure that is expecting a ICMPv6 ECHO
* response with this ID from this device
* Enumerate each ICMPv6 connection structure. This function will terminate
* when either (1) all connection have been enumerated or (2) when a
* callback returns any non-zero value.
*
* Assumptions:
* This function is called from network logic at with the network locked.
@ -608,8 +615,7 @@ FAR struct icmpv6_conn_s *icmpv6_nextconn(FAR struct icmpv6_conn_s *conn);
****************************************************************************/
#ifdef CONFIG_NET_ICMPv6_SOCKET
FAR struct icmpv6_conn_s *icmpv6_findconn(FAR struct net_driver_s *dev,
uint16_t id);
int icmpv6_foreach(icmpv6_callback_t callback, FAR void *arg);
#endif
/****************************************************************************

View File

@ -252,31 +252,36 @@ FAR struct icmpv6_conn_s *icmpv6_nextconn(FAR struct icmpv6_conn_s *conn)
}
/****************************************************************************
* Name: icmpv6_findconn
* Name: icmpv6_foreach
*
* Description:
* Find an ICMPv6 connection structure that is expecting a ICMPv6 ECHO
* response with this ID from this device
* Enumerate each ICMPv6 connection structure. This function will terminate
* when either (1) all connection have been enumerated or (2) when a
* callback returns any non-zero value.
*
* Assumptions:
* This function is called from network logic at with the network locked.
*
****************************************************************************/
FAR struct icmpv6_conn_s *icmpv6_findconn(FAR struct net_driver_s *dev,
uint16_t id)
int icmpv6_foreach(icmpv6_callback_t callback, FAR void *arg)
{
FAR struct icmpv6_conn_s *conn;
int ret = 0;
for (conn = icmpv6_nextconn(NULL); conn != NULL;
conn = icmpv6_nextconn(conn))
if (callback != NULL)
{
if (conn->id == id && conn->dev == dev && conn->nreqs > 0)
for (conn = icmpv6_nextconn(NULL); conn != NULL;
conn = icmpv6_nextconn(conn))
{
return conn;
ret = callback(conn, arg);
if (ret != 0)
{
break;
}
}
}
return conn;
return ret;
}
#endif /* CONFIG_NET_ICMP */

View File

@ -59,10 +59,32 @@
#define MLDREPORT_V2 ((FAR struct mld_mcast_listen_report_v2_s *)icmpv6)
#define MLDDONE ((FAR struct mld_mcast_listen_done_s *)icmpv6)
#ifdef CONFIG_NET_ICMPv6_SOCKET
/****************************************************************************
* Private Types
****************************************************************************/
struct icmpv6_deliver_s
{
FAR struct net_driver_s *dev; /* Current network device */
unsigned int iplen; /* The size of the IPv6 header */
bool delivered; /* Whether the message is delivered */
};
/****************************************************************************
* Private Functions
****************************************************************************/
static bool icmpv6_filter(FAR const uint32_t *data, uint8_t type)
{
/* We require only the four bytes of the ICMPv6 header. */
DEBUGASSERT(data != NULL);
return (data[type >> 5] & (1u << (type & 31))) != 0;
}
/****************************************************************************
* Name: icmpv6_datahandler
*
@ -82,7 +104,6 @@
*
****************************************************************************/
#ifdef CONFIG_NET_ICMPv6_SOCKET
static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
FAR struct icmpv6_conn_s *conn,
unsigned int iplen)
@ -93,9 +114,14 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
uint16_t buflen;
int ret;
iob = iob_tryalloc(false);
if (iob == NULL)
{
return -ENOMEM;
}
/* Put the IPv6 address at the beginning of the read-ahead buffer */
iob = dev->d_iob;
ipv6 = IPv6BUF;
inaddr.sin6_family = AF_INET6;
inaddr.sin6_port = 0;
@ -107,14 +133,20 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
memcpy(iob->io_data, &inaddr, sizeof(struct sockaddr_in6));
/* Copy the new ICMPv6 reply into the I/O buffer chain (without waiting) */
iob_reserve(iob, sizeof(struct sockaddr_in6));
/* Copy the ICMPv6 message into the I/O buffer chain (without waiting) */
ret = iob_clone_partial(dev->d_iob, dev->d_iob->io_pktlen,
iplen, iob, 0, true, false);
if (ret < 0)
{
iob_free_chain(iob);
return ret;
}
buflen = ICMPv6SIZE;
/* Trim l3 header */
iob = iob_trimhead(iob, iplen);
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
* without waiting).
*/
@ -130,12 +162,81 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
ninfo("Buffered %d bytes\n", buflen);
}
/* Device buffer must be enqueue or freed, clear the handle */
netdev_iob_clear(dev);
return buflen;
}
#endif
/****************************************************************************
* Name: icmpv6_delivery_callback
*
* Description:
* Copy the icmpv6 package to the application according to the filter
* conditions, but ICMPv6_ECHO_REPLY is a special message type, if there
* is an application waiting, it will also copy.
*
* Input Parameters:
* conn - A pointer to the ICMPv6 connection structure.
* arg - The context information
*
****************************************************************************/
static int icmpv6_delivery_callback(FAR struct icmpv6_conn_s *conn,
FAR void *arg)
{
FAR struct icmpv6_deliver_s *info = arg;
FAR struct net_driver_s *dev = info->dev;
FAR struct icmpv6_hdr_s *icmpv6 = IPBUF(info->iplen);
if (icmpv6_filter(conn->filter.icmp6_filt, icmpv6->type) &&
(icmpv6->type != ICMPv6_ECHO_REPLY || conn->id != ICMPv6REPLY->id ||
conn->dev != dev))
{
return 0;
}
info->delivered = true;
if (devif_conn_event(dev, ICMPv6_NEWDATA, conn->sconn.list) !=
ICMPv6_NEWDATA)
{
dev->d_len = dev->d_iob->io_pktlen;
}
else
{
icmpv6_datahandler(dev, conn, info->iplen);
}
return 0;
}
/****************************************************************************
* Name: icmpv6_deliver
*
* Description:
* Copy the icmpv6 package to the application according to the filter
* conditions, but ICMPv6_ECHO_REPLY is a special message type, if there
* is an application waiting, it will also copy.
*
* Input Parameters:
* dev - Reference to a device driver structure.
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
****************************************************************************/
static bool icmpv6_deliver(FAR struct net_driver_s *dev, unsigned int iplen)
{
struct icmpv6_deliver_s info;
info.dev = dev;
info.iplen = iplen;
info.delivered = false;
icmpv6_foreach(icmpv6_delivery_callback, &info);
return info.delivered;
}
#endif /* CONFIG_NET_ICMPv6_SOCKET */
/****************************************************************************
* Public Functions
@ -166,6 +267,9 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
FAR struct icmpv6_hdr_s *icmpv6 = IPBUF(iplen);
#ifdef CONFIG_NET_ICMPv6_SOCKET
bool delivered = icmpv6_deliver(dev, iplen);
#endif
#ifdef CONFIG_NET_STATISTICS
g_netstats.icmpv6.recv++;
@ -443,61 +547,6 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
}
break;
#ifdef CONFIG_NET_ICMPv6_SOCKET
/* If an ICMPv6 echo reply is received then there should also be
* a thread waiting to received the echo response.
*/
case ICMPv6_ECHO_REPLY:
{
FAR struct icmpv6_echo_reply_s *reply;
FAR struct icmpv6_conn_s *conn;
uint16_t flags = ICMPv6_NEWDATA;
/* Nothing consumed the ICMP reply. That might be because this is
* an old, invalid reply or simply because the ping application
* has not yet put its poll or recv in place.
*/
/* Is there any connection that might expect this reply? */
reply = ICMPv6REPLY;
conn = icmpv6_findconn(dev, reply->id);
if (conn == NULL)
{
/* No.. drop the packet */
goto icmpv6_drop_packet;
}
/* Dispatch the ECHO reply to the waiting thread */
flags = devif_conn_event(dev, flags, conn->sconn.list);
/* Was the ECHO reply consumed by any waiting thread? */
if ((flags & ICMPv6_NEWDATA) != 0)
{
uint16_t nbuffered;
/* Yes.. Add the ICMP echo reply to the IPPROTO_ICMP socket read
* ahead buffer.
*/
nbuffered = icmpv6_datahandler(dev, conn, iplen);
if (nbuffered == 0)
{
/* Could not buffer the data.. drop the packet */
goto icmpv6_drop_packet;
}
}
goto icmpv6_send_nothing;
}
break;
#endif
#ifdef CONFIG_NET_MLD
/* Dispatch received Multicast Listener Discovery (MLD) packets. */
@ -556,6 +605,13 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
default:
{
#ifdef CONFIG_NET_ICMPv6_SOCKET
if (delivered)
{
goto icmpv6_send_nothing;
}
#endif
nwarn("WARNING: Unknown ICMPv6 type: %d\n", icmpv6->type);
goto icmpv6_type_error;
}

View File

@ -95,9 +95,7 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
{
FAR struct icmpv6_recvfrom_s *pstate = pvpriv;
FAR struct socket *psock;
FAR struct icmpv6_conn_s *conn;
FAR struct ipv6_hdr_s *ipv6;
FAR struct icmpv6_echo_reply_s *icmpv6;
ninfo("flags: %04x\n", flags);
@ -112,18 +110,8 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
goto end_wait;
}
/* Is this a response on the same device that we sent the request out
* on?
*/
psock = pstate->recv_sock;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
conn = psock->s_conn;
if (dev != conn->dev)
{
ninfo("Wrong device\n");
return flags;
}
/* Check if we have just received a ICMPv6 ECHO reply. */
@ -131,17 +119,6 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
{
unsigned int recvsize;
/* Check if it is for us.
* REVISIT: What if there are IPv6 extension headers present?
*/
icmpv6 = IPBUF(IPv6_HDRLEN);
if (conn->id != icmpv6->id)
{
ninfo("Wrong ID: %u vs %u\n", icmpv6->id, conn->id);
return flags;
}
ninfo("Received ICMPv6 reply\n");
/* What should we do if the received reply is larger that the
@ -171,15 +148,6 @@ static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
ipv6 = IPBUF(0);
net_ipv6addr_hdrcopy(&pstate->recv_from, ipv6->srcipaddr);
/* Decrement the count of outstanding requests. I suppose this
* could have already been decremented of there were multiple
* threads calling sendto() or recvfrom(). If there finds, we
* may have to beef up the design.
*/
DEBUGASSERT(conn->nreqs > 0);
conn->nreqs--;
/* Indicate that the data has been consumed */
flags &= ~ICMPv6_NEWDATA;
@ -310,7 +278,7 @@ ssize_t icmpv6_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
FAR socklen_t *fromlen = &msg->msg_namelen;
FAR struct sockaddr_in6 *inaddr;
FAR struct icmpv6_conn_s *conn;
FAR struct net_driver_s *dev;
FAR struct net_driver_s *dev = NULL;
struct icmpv6_recvfrom_s state;
ssize_t ret;
@ -337,25 +305,18 @@ ssize_t icmpv6_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
net_lock();
/* We cannot receive a response from a device until a request has been
* sent to the devivce.
*/
conn = psock->s_conn;
if (conn->nreqs < 1)
if (psock->s_type != SOCK_RAW)
{
ret = -EPROTO;
goto errout;
}
/* Get the device that was used to send the ICMPv6 request. */
/* Get the device that was used to send the ICMPv6 request. */
dev = conn->dev;
DEBUGASSERT(dev != NULL);
if (dev == NULL)
{
ret = -EPROTO;
goto errout;
dev = conn->dev;
DEBUGASSERT(dev != NULL);
if (dev == NULL)
{
ret = -EPROTO;
goto errout;
}
}
/* Check if there is buffered read-ahead data for this socket. We may have
@ -442,11 +403,10 @@ ssize_t icmpv6_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
*/
errout:
if (conn->nreqs < 1)
if (ret < 0)
{
conn->id = 0;
conn->nreqs = 0;
conn->dev = NULL;
conn->id = 0;
conn->dev = NULL;
iob_free_queue(&conn->readahead);
}

View File

@ -326,12 +326,11 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
*/
icmpv6 = (FAR struct icmpv6_echo_request_s *)buf;
if (icmpv6->type != ICMPv6_ECHO_REQUEST || icmpv6->id != conn->id ||
dev != conn->dev)
if (psock->s_type != SOCK_RAW && (icmpv6->type != ICMPv6_ECHO_REQUEST ||
icmpv6->id != conn->id || dev != conn->dev))
{
conn->id = 0;
conn->nreqs = 0;
conn->dev = NULL;
conn->id = 0;
conn->dev = NULL;
iob_free_queue(&conn->readahead);
}
@ -372,13 +371,12 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
/* Setup to receive ICMPv6 ECHO replies */
if (icmpv6->type == ICMPv6_ECHO_REQUEST)
if (psock->s_type != SOCK_RAW && icmpv6->type == ICMPv6_ECHO_REQUEST)
{
conn->id = icmpv6->id;
conn->nreqs = 1;
conn->id = icmpv6->id;
}
conn->dev = dev;
conn->dev = dev;
/* Notify the device driver of the availability of TX data */
@ -439,9 +437,8 @@ ssize_t icmpv6_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
return len;
errout:
conn->id = 0;
conn->nreqs = 0;
conn->dev = NULL;
conn->id = 0;
conn->dev = NULL;
iob_free_queue(&conn->readahead);
return ret;

View File

@ -37,6 +37,7 @@
#include <socket/socket.h>
#include "icmpv6/icmpv6.h"
#include "inet/inet.h"
#ifdef CONFIG_NET_ICMPv6_SOCKET
@ -50,6 +51,12 @@ static void icmpv6_addref(FAR struct socket *psock);
static int icmpv6_netpoll(FAR struct socket *psock,
FAR struct pollfd *fds, bool setup);
static int icmpv6_close(FAR struct socket *psock);
#ifdef CONFIG_NET_SOCKOPTS
static int icmpv6_getsockopt(FAR struct socket *psock, int level,
int option, FAR void *value, FAR socklen_t *value_len);
static int icmpv6_setsockopt(FAR struct socket *psock, int level,
int option, FAR const void *value, socklen_t value_len);
#endif
/****************************************************************************
* Public Data
@ -70,7 +77,13 @@ const struct sock_intf_s g_icmpv6_sockif =
icmpv6_sendmsg, /* si_sendmsg */
icmpv6_recvmsg, /* si_recvmsg */
icmpv6_close, /* si_close */
icmpv6_ioctl /* si_ioctl */
icmpv6_ioctl, /* si_ioctl */
NULL, /* si_socketpair */
NULL /* si_shutdown */
#ifdef CONFIG_NET_SOCKOPTS
, icmpv6_getsockopt /* si_getsockopt */
, icmpv6_setsockopt /* si_setsockopt */
#endif
};
/****************************************************************************
@ -99,8 +112,8 @@ static int icmpv6_setup(FAR struct socket *psock)
{
/* SOCK_DGRAM or SOCK_CTRL and IPPROTO_ICMP6 are supported */
if ((psock->s_type == SOCK_DGRAM || psock->s_type == SOCK_CTRL) &&
psock->s_proto == IPPROTO_ICMP6)
if ((psock->s_type == SOCK_DGRAM || psock->s_type == SOCK_CTRL ||
psock->s_type == SOCK_RAW) && psock->s_proto == IPPROTO_ICMP6)
{
/* Allocate the IPPROTO_ICMP6 socket connection structure and save in
* the new socket instance.
@ -121,6 +134,10 @@ static int icmpv6_setup(FAR struct socket *psock)
DEBUGASSERT(conn->crefs == 0);
conn->crefs = 1;
if (psock->s_type != SOCK_RAW)
{
memset(&conn->filter, 0xff, sizeof(conn->filter));
}
/* Save the pre-allocated connection in the socket structure */
@ -266,6 +283,219 @@ static int icmpv6_close(FAR struct socket *psock)
return OK;
}
#ifdef CONFIG_NET_SOCKOPTS
/****************************************************************************
* Name: icmpv6_getsockopt_internal
*
* Description:
* icmpv6_getsockopt_internal() sets the ICMPV6-protocol socket option
* specified by the 'option' argument to the value pointed to by the
* 'value' argument for the socket specified by the 'psock' argument.
*
* See <netinet/in.h> for the a complete list of values of ICMPV6 protocol
* socket options.
*
* Input Parameters:
* psock Socket structure of socket to operate on
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error.
*
****************************************************************************/
static int icmpv6_getsockopt_internal(FAR struct socket *psock, int option,
FAR void *value,
FAR socklen_t *value_len)
{
int ret;
ninfo("option: %d\n", option);
if (psock->s_type != SOCK_RAW)
{
return ENOPROTOOPT;
}
net_lock();
switch (option)
{
case ICMP6_FILTER:
{
FAR struct icmpv6_conn_s *conn = psock->s_conn;
if (*value_len > sizeof(struct icmp6_filter))
{
*value_len = sizeof(struct icmp6_filter);
}
memcpy(value, &conn->filter, *value_len);
ret = OK;
}
break;
default:
nerr("ERROR: Unrecognized ICMPV6 option: %d\n", option);
ret = -ENOPROTOOPT;
break;
}
net_unlock();
return ret;
}
/****************************************************************************
* Name: icmpv6_getsockopt
*
* Description:
* icmpv6_getsockopt() retrieve the value for the option specified by the
* 'option' argument at the protocol level specified by the 'level'
* argument. If the size of the option value is greater than 'value_len',
* the value stored in the object pointed to by the 'value' argument will
* be silently truncated. Otherwise, the length pointed to by the
* 'value_len' argument will be modified to indicate the actual length
* of the 'value'.
*
* The 'level' argument specifies the protocol level of the option. To
* retrieve options at the socket level, specify the level argument as
* SOL_SOCKET.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
*
* Input Parameters:
* psock Socket structure of the socket to query
* level Protocol level to set the option
* option identifies the option to get
* value Points to the argument value
* value_len The length of the argument value
*
****************************************************************************/
static int icmpv6_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len)
{
switch (level)
{
case IPPROTO_IPV6:
return ipv6_getsockopt(psock, option, value, value_len);
case IPPROTO_ICMPV6:
return icmpv6_getsockopt_internal(psock, option, value, value_len);
default:
nerr("ERROR: Unrecognized ICMPV6 option: %d\n", option);
return -ENOPROTOOPT;
}
}
/****************************************************************************
* Name: icmpv6_setsockopt_internal
*
* Description:
* icmpv6_setsockopt_internal() sets the ICMPV6-protocol socket option
* specified by the 'option' argument to the value pointed to by the
* 'value' argument for the socket specified by the 'psock' argument.
*
* See <netinet/in.h> for the a complete list of values of ICMPV6 protocol
* socket options.
*
* Input Parameters:
* psock Socket structure of socket to operate on
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error. See psock_setcockopt() for
* the list of possible error values.
*
****************************************************************************/
static int icmpv6_setsockopt_internal(FAR struct socket *psock, int option,
FAR const void *value,
socklen_t value_len)
{
int ret;
ninfo("option: %d\n", option);
if (psock->s_type != SOCK_RAW)
{
return ENOPROTOOPT;
}
net_lock();
switch (option)
{
case ICMP6_FILTER:
{
FAR struct icmpv6_conn_s *conn = psock->s_conn;
if (value_len > sizeof(struct icmp6_filter))
{
value_len = sizeof(struct icmp6_filter);
}
memcpy(&conn->filter, value, value_len);
ret = OK;
}
break;
default:
nerr("ERROR: Unrecognized ICMP6 option: %d\n", option);
ret = -ENOPROTOOPT;
break;
}
net_unlock();
return ret;
}
/****************************************************************************
* Name: icmpv6_setsockopt
*
* Description:
* icmpv6_setsockopt() sets the option specified by the 'option' argument,
* at the protocol level specified by the 'level' argument, to the value
* pointed to by the 'value' argument for the connection.
*
* The 'level' argument specifies the protocol level of the option. To set
* options at the socket level, specify the level argument as SOL_SOCKET.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
*
* Input Parameters:
* psock Socket structure of the socket to query
* level Protocol level to set the option
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
****************************************************************************/
static int icmpv6_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len)
{
switch (level)
{
case IPPROTO_IPV6:
return ipv6_setsockopt(psock, option, value, value_len);
case IPPROTO_ICMPV6:
return icmpv6_setsockopt_internal(psock, option, value, value_len);
default:
nerr("ERROR: Unrecognized ICMPV6 option: %d\n", option);
return -ENOPROTOOPT;
}
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/

View File

@ -2410,8 +2410,8 @@ inet_sockif(sa_family_t family, int type, int protocol)
#if defined(HAVE_PFINET6_SOCKETS) && defined(CONFIG_NET_ICMPv6_SOCKET)
/* PF_INET, ICMP data gram sockets are a special case of raw sockets */
if (family == PF_INET6 && (type == SOCK_DGRAM || type == SOCK_CTRL) &&
protocol == IPPROTO_ICMP6)
if (family == PF_INET6 && (type == SOCK_DGRAM || type == SOCK_CTRL ||
type == SOCK_RAW) && protocol == IPPROTO_ICMPV6)
{
return &g_icmpv6_sockif;
}