From 70c59a9d912f76316c944c383512734213846cda Mon Sep 17 00:00:00 2001
From: Gregory Nutt
Date: Tue, 24 Oct 2017 11:23:08 -0600
Subject: [PATCH] This commit adds support for semi-standard IPPROTO_ICMP6
sockets. This is a replacement for the non-standard ICMPv6 ping support that
violated the portable POSIX OS interface.
Squashed commit of the following:
net/icmpv6: IPPROT_ICMP6 socket logic now builds without error.
net/icmpv6: Add support for read-ahead and poll(). Initial commit is just cloned from ICMP with the appropriate name changes.
configs/: All defconfig filess that include CONFIG_NET_ICMPv6_SOCKET=y need to select CONFIG_SYSTEM_PING6=y and deselect CONFIG_DISABLE_POLL.
Update NSH documention to show that ping6 is now a built in command.
net/icmpv6: Add icmpv6_sendto.c and icmpv6_recvfrom.c. Initial versions are just clones from icmp/ with appropriate name changes.
net/icmpv6: Clone some ICMP socket logic as the beginning of support for ICMPv6 socket support.
Rename CONFIG_NET_ICMPv6_PING to CONFIG_NET_ICMPv6_SOCKET. Move prototype for icmpv6_ping from include/nuttx/net/icmpv6 to net/icmpv6/icmpv6.h
---
Documentation/NuttShell.html | 148 ++---
TODO | 1 -
configs/dk-tm4c129x/ipv6/defconfig | 4 +-
configs/sama5d4-ek/ipv6/defconfig | 3 +-
.../mrf24j40-starhub/defconfig | 3 +-
.../samv71-xult/mrf24j40-starhub/defconfig | 4 +-
configs/sim/README.txt | 2 +-
configs/stm32f4discovery/ipv6/defconfig | 4 +-
configs/tm4c1294-launchpad/ipv6/defconfig | 4 +-
drivers/net/loopback.c | 2 +-
include/netinet/in.h | 4 +-
include/nuttx/net/icmpv6.h | 30 -
net/devif/devif_poll.c | 8 +-
net/icmp/Kconfig | 4 +-
net/icmp/icmp.h | 6 +-
net/icmp/icmp_input.c | 8 +-
net/icmp/icmp_netpoll.c | 8 +-
net/icmp/icmp_recvfrom.c | 2 +-
net/icmp/icmp_sendto.c | 7 +-
net/icmpv6/Kconfig | 24 +-
net/icmpv6/Make.defs | 16 +-
net/icmpv6/icmpv6.h | 277 ++++++++-
net/icmpv6/icmpv6_conn.c | 286 +++++++++
net/icmpv6/icmpv6_input.c | 205 ++++++-
net/icmpv6/icmpv6_netpoll.c | 311 ++++++++++
net/icmpv6/icmpv6_ping.c | 502 ----------------
net/icmpv6/icmpv6_poll.c | 4 +-
net/icmpv6/icmpv6_recvfrom.c | 556 ++++++++++++++++++
net/icmpv6/icmpv6_sendto.c | 509 ++++++++++++++++
net/icmpv6/icmpv6_sockif.c | 520 ++++++++++++++++
net/inet/inet_sockif.c | 10 +
net/net_initialize.c | 7 +
32 files changed, 2775 insertions(+), 704 deletions(-)
create mode 100644 net/icmpv6/icmpv6_conn.c
create mode 100644 net/icmpv6/icmpv6_netpoll.c
delete mode 100644 net/icmpv6/icmpv6_ping.c
create mode 100644 net/icmpv6/icmpv6_recvfrom.c
create mode 100644 net/icmpv6/icmpv6_sendto.c
create mode 100644 net/icmpv6/icmpv6_sockif.c
diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html
index a51dd516b1..a4056e6d66 100644
--- a/Documentation/NuttShell.html
+++ b/Documentation/NuttShell.html
@@ -8,7 +8,7 @@
NuttShell (NSH)
- Last Updated: October 23, 2017
+ Last Updated: October 24, 2017
|
@@ -353,157 +353,151 @@
|
- 2.45 Check Network Peer (ping6)
+ 2.45 Shut the system down (poweroff)
|
|
- 2.46 Shut the system down (poweroff)
+ 2.46 Send File Via TFTP (put)
|
|
- 2.47 Send File Via TFTP (put)
+ 2.47 Show Current Working Directory (pwd)
|
|
- 2.48 Show Current Working Directory (pwd)
+ 2.48 Show target of a link (readlink)
|
|
- 2.49 Show target of a link (readlink)
+ 2.49 Reset and reboot the system (reboot)
|
|
- 2.50 Reset and reboot the system (reboot)
+ 2.50 Remove a File (rm)
|
|
- 2.51 Remove a File (rm)
+ 2.51 Remove a Directory (rmdir)
|
|
- 2.52 Remove a Directory (rmdir)
+ 2.52 Remove on OS Module (rmmod)
|
|
- 2.53 Remove on OS Module (rmmod)
+ 2.53 Show routing table (route)
|
|
- 2.54 Show routing table (route)
+ 2.54 Set an Environment Variable (set)
|
|
- 2.55 Set an Environment Variable (set)
+ 2.55 Execute an NSH Script (sh)
|
|
- 2.56 Execute an NSH Script (sh)
+ 2.56 Shut the system down (shutdown)
|
|
- 2.57 Shut the system down (shutdown)
+ 2.57 Wait for Seconds (sleep)
|
|
- 2.58 Wait for Seconds (sleep)
+ 2.58 Start the Telnet Daemon (telnetd)
|
|
- 2.59 Start the Telnet Daemon (telnetd)
+ 2.59 Time execution of another command (time)
|
|
- 2.60 Time execution of another command (time)
+ 2.60 Unmount a File System (umount)
|
|
- 2.61 Unmount a File System (umount)
+ 2.61 Print system information (uname)
|
|
- 2.62 Print system information (uname)
+ 2.62 Unset an Environment Variable (unset)
|
|
- 2.63 Unset an Environment Variable (unset)
+ 2.63 URL Decode (urldecode)
|
|
- 2.64 URL Decode (urldecode)
+ 2.64 URL Encode (urlencode)
|
|
- 2.65 URL Encode (urlencode)
+ 2.65 Add a New User (useradd)
|
|
- 2.66 Add a New User (useradd)
+ 2.66 Delete a user (userdel)
|
|
- 2.67 Delete a user (userdel)
+ 2.67 Wait for Microseconds (usleep)
|
|
- 2.68 Wait for Microseconds (usleep)
+ 2.68 Get File Via HTTP (wget)
|
|
- 2.69 Get File Via HTTP (wget)
- |
-
-
-
|
-
- 2.70 Hexadecimal Dump of Memory (xd)
+ 2.69 Hexadecimal Dump of Memory (xd)
|
@@ -515,7 +509,7 @@
|
- 3.1 Check Network Peer (ping)
+ 3.1 Check Network Peer (ping/pin6)
|
@@ -2532,26 +2526,7 @@ passwd <username> <password>
-
-Command Syntax:
-
-ping6 [-c <count>] [-i <interval>] <ip-address>
-
-
- Synopsis.
- Test the network communication with a remote peer.
-
- ping6
differs from ping
in that it uses IPv6 addressing.
-
-
-
@@ -2573,7 +2548,7 @@ poweroff
@@ -2608,7 +2583,7 @@ put [-b|-n] [-f <remote-path>] -h <ip-address> <local-path>
@@ -2638,7 +2613,7 @@ nsh>
@@ -2655,7 +2630,7 @@ readlink <link>
@@ -2676,7 +2651,7 @@ reboot
@@ -2710,7 +2685,7 @@ nsh>
@@ -2745,7 +2720,7 @@ nsh>
@@ -2773,7 +2748,7 @@ nsh>
@@ -2793,7 +2768,7 @@ route ipv4|ipv6
@@ -2862,7 +2837,7 @@ nsh>
@@ -2880,7 +2855,7 @@ sh <script-path>
@@ -2901,7 +2876,7 @@ shutdown [--reboot]
@@ -2918,7 +2893,7 @@ sleep <sec>
@@ -2944,7 +2919,7 @@ telnetd
@@ -3002,7 +2977,7 @@ nsh>
@@ -3032,7 +3007,7 @@ nsh>
@@ -3099,7 +3074,7 @@ uname [-a | -imnoprsv]
@@ -3125,7 +3100,7 @@ nsh>
@@ -3142,7 +3117,7 @@ urldecode [-f] <string or filepath>
@@ -3159,7 +3134,7 @@ urlencode [-f] <string or filepath>
@@ -3176,7 +3151,7 @@ useradd <username> <password>
@@ -3193,7 +3168,7 @@ userdel <username>
@@ -3210,7 +3185,7 @@ usleep <usec>
@@ -3237,7 +3212,7 @@ wget [-o <local-path>] <url>
@@ -3285,7 +3260,7 @@ nsh>
@@ -3293,6 +3268,7 @@ nsh>
Command Syntax:
ping [-c <count>] [-i <interval>] <ip-address>
+ping6 [-c <count>] [-i <interval>] <ip-address>
Synopsis.
@@ -3314,6 +3290,9 @@ PING 10.0.0.1 56 bytes of data
10 packets transmitted, 10 received, 0% packet loss, time 10190 ms
nsh>
+
+ ping6
differs from ping
in that it uses IPv6 addressing.
+
@@ -3574,12 +3553,6 @@ nsh>
!CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE && CONFIG_NSH_LOGIN_PASSWD |
CONFIG_NSH_DISABLE_PASSWD |
-
- ping6 |
- CONFIG_NET && CONFIG_NET_ICMPv6 &&
- CONFIG_NET_ICMPv6_PING && !CONFIG_DISABLE_SIGNALS |
- CONFIG_NSH_DISABLE_PING6 |
-
poweroff |
CONFIG_BOARDCTL_POWEROFF |
@@ -3761,6 +3734,11 @@ nsh>
CONFIG_NET && CONFIG_NET_ICMP &&
CONFIG_NET_ICMP_SOCKET && CONFIG_SYSTEM_PING && !CONFIG_DISABLE_SIGNALS && !CONFIG_DISABLE_POLL |
+
+ ping6 |
+ CONFIG_NET && CONFIG_NET_ICMPv6 &&
+ CONFIG_NET_ICMPv6_SOCKET && CONFIG_SYSTEM_PING6 && !CONFIG_DISABLE_SIGNALS && !CONFIG_DISABLE_POLL |
+
@@ -5556,7 +5534,7 @@ xxd -i romfs_img >nsh_romfsimg.h
Password File
Password File, ROMFS
ping
- ping6
+ ping6
poweroff
Prompt
ps
diff --git a/TODO b/TODO
index 4665a9d244..d75df2b1d4 100644
--- a/TODO
+++ b/TODO
@@ -646,7 +646,6 @@ o Kernel/Protected Build
COMMAND KERNEL INTERFACE(s)
-------- ----------------------------------------------
mkrd ramdisk_register()
- ping6 icmpv6_ping()
mount foreach_mountpoint()
Status: Open
diff --git a/configs/dk-tm4c129x/ipv6/defconfig b/configs/dk-tm4c129x/ipv6/defconfig
index e318c48602..c7b6179b4f 100644
--- a/configs/dk-tm4c129x/ipv6/defconfig
+++ b/configs/dk-tm4c129x/ipv6/defconfig
@@ -16,7 +16,6 @@ CONFIG_ARCH="arm"
CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYW=y
CONFIG_BOARD_LOOPSPERMSEC=11401
CONFIG_BUILTIN=y
-CONFIG_DISABLE_POLL=y
CONFIG_EXAMPLES_NSH=y
CONFIG_HOST_WINDOWS=y
CONFIG_I2CTOOL_MAXBUS=6
@@ -30,7 +29,7 @@ CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_MTU=590
CONFIG_NET_ETH_TCP_RECVWNDO=536
CONFIG_NET_ICMPv6_NEIGHBOR=y
-CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ICMPv6_SOCKET=y
CONFIG_NET_ICMPv6=y
CONFIG_NET_IPv6=y
CONFIG_NET_SOCKOPTS=y
@@ -66,6 +65,7 @@ CONFIG_START_MONTH=3
CONFIG_START_YEAR=2013
CONFIG_SYSTEM_I2CTOOL=y
CONFIG_SYSTEM_LM75=y
+CONFIG_SYSTEM_PING6=y
CONFIG_TIVA_BOARDMAC=y
CONFIG_TIVA_ETHERNET=y
CONFIG_TIVA_GPIOP_IRQS=y
diff --git a/configs/sama5d4-ek/ipv6/defconfig b/configs/sama5d4-ek/ipv6/defconfig
index efc9a68def..f3ac2b21f7 100644
--- a/configs/sama5d4-ek/ipv6/defconfig
+++ b/configs/sama5d4-ek/ipv6/defconfig
@@ -58,7 +58,7 @@ CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_MTU=590
CONFIG_NET_ETH_TCP_RECVWNDO=562
CONFIG_NET_ICMPv6_NEIGHBOR=y
-CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ICMPv6_SOCKET=y
CONFIG_NET_ICMPv6=y
CONFIG_NET_IPv6=y
CONFIG_NET_SOCKOPTS=y
@@ -148,6 +148,7 @@ CONFIG_SDIO_BLOCKSETUP=y
CONFIG_SYMTAB_ORDEREDBYNAME=y
CONFIG_SYSTEM_I2CTOOL=y
CONFIG_SYSTEM_NXPLAYER=y
+CONFIG_SYSTEM_PING6=y
CONFIG_USART3_SERIAL_CONSOLE=y
CONFIG_USBHOST_HIDKBD=y
CONFIG_USBHOST_ISOC_DISABLE=y
diff --git a/configs/same70-xplained/mrf24j40-starhub/defconfig b/configs/same70-xplained/mrf24j40-starhub/defconfig
index 501b38fa01..58ec4415ca 100644
--- a/configs/same70-xplained/mrf24j40-starhub/defconfig
+++ b/configs/same70-xplained/mrf24j40-starhub/defconfig
@@ -59,7 +59,7 @@ CONFIG_NET_ETH_MTU=590
CONFIG_NET_ETH_TCP_RECVWNDO=536
CONFIG_NET_HOSTNAME="MRF24J40-Hub"
CONFIG_NET_ICMPv6_NEIGHBOR=y
-CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ICMPv6_SOCKET=y
CONFIG_NET_ICMPv6=y
CONFIG_NET_IPv6=y
CONFIG_NET_SOCKOPTS=y
@@ -123,6 +123,7 @@ CONFIG_START_DAY=16
CONFIG_START_MONTH=8
CONFIG_SYSLOG_BUFFER=y
CONFIG_SYSLOG_INTBUFFER=y
+CONFIG_SYSTEM_PING6=y
CONFIG_SYSTEM_TELNET_CLIENT=y
CONFIG_UART3_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/configs/samv71-xult/mrf24j40-starhub/defconfig b/configs/samv71-xult/mrf24j40-starhub/defconfig
index bbb7e5deb9..44a209cba9 100644
--- a/configs/samv71-xult/mrf24j40-starhub/defconfig
+++ b/configs/samv71-xult/mrf24j40-starhub/defconfig
@@ -23,7 +23,6 @@ CONFIG_AT24XX_EXTSIZE=160
CONFIG_AT24XX_SIZE=2
CONFIG_BOARD_LOOPSPERMSEC=51262
CONFIG_BUILTIN=y
-CONFIG_DISABLE_POLL=y
CONFIG_DRIVERS_IEEE802154=y
CONFIG_DRIVERS_WIRELESS=y
CONFIG_ETH0_PHY_KSZ8061=y
@@ -61,7 +60,7 @@ CONFIG_NET_ETH_MTU=590
CONFIG_NET_ETH_TCP_RECVWNDO=536
CONFIG_NET_HOSTNAME="MRF24J40-Hub"
CONFIG_NET_ICMPv6_NEIGHBOR=y
-CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ICMPv6_SOCKET=y
CONFIG_NET_ICMPv6=y
CONFIG_NET_IPv6=y
CONFIG_NET_SOCKOPTS=y
@@ -130,6 +129,7 @@ CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
CONFIG_SDIO_BLOCKSETUP=y
CONFIG_START_MONTH=7
+CONFIG_SYSTEM_PING6=y
CONFIG_UART3_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_WIRELESS_IEEE802154=y
diff --git a/configs/sim/README.txt b/configs/sim/README.txt
index 6c826bc1d3..2d6ed00f91 100644
--- a/configs/sim/README.txt
+++ b/configs/sim/README.txt
@@ -550,7 +550,7 @@ ipforward
+CONFIG_EXAMPLES_IPFORWARD_ICMPv6=y
+CONFIG_NET_ICMPv6=y
- +CONFIG_NET_ICMPv6_PING=y
+ +CONFIG_NET_ICMPv6_SOCKET=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_IPFORWARD_BROADCAST=y
diff --git a/configs/stm32f4discovery/ipv6/defconfig b/configs/stm32f4discovery/ipv6/defconfig
index 32caa39982..9d81a71f6e 100644
--- a/configs/stm32f4discovery/ipv6/defconfig
+++ b/configs/stm32f4discovery/ipv6/defconfig
@@ -16,7 +16,6 @@ CONFIG_ARCH="arm"
CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYW=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
-CONFIG_DISABLE_POLL=y
CONFIG_ETH0_PHY_LAN8720=y
CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y
CONFIG_EXAMPLES_NSH=y
@@ -38,7 +37,7 @@ CONFIG_NET_ETH_MTU=590
CONFIG_NET_ETH_TCP_RECVWNDO=536
CONFIG_NET_HOSTNAME="STM32F4-Discovery"
CONFIG_NET_ICMPv6_NEIGHBOR=y
-CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ICMPv6_SOCKET=y
CONFIG_NET_ICMPv6=y
CONFIG_NET_IPv6=y
CONFIG_NET_SOCKOPTS=y
@@ -89,6 +88,7 @@ CONFIG_STM32_SDIO=y
CONFIG_STM32_SPI1=y
CONFIG_STM32_USART6=y
CONFIG_STM32F4DISBB=y
+CONFIG_SYSTEM_PING6=y
CONFIG_USART6_RXBUFSIZE=64
CONFIG_USART6_SERIAL_CONSOLE=y
CONFIG_USART6_TXBUFSIZE=64
diff --git a/configs/tm4c1294-launchpad/ipv6/defconfig b/configs/tm4c1294-launchpad/ipv6/defconfig
index fcf6fab923..6587cc6ba7 100644
--- a/configs/tm4c1294-launchpad/ipv6/defconfig
+++ b/configs/tm4c1294-launchpad/ipv6/defconfig
@@ -13,7 +13,6 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH="arm"
CONFIG_BOARD_LOOPSPERMSEC=11401
CONFIG_BUILTIN=y
-CONFIG_DISABLE_POLL=y
CONFIG_EXAMPLES_NSH=y
CONFIG_I2C=y
CONFIG_I2CTOOL_MAXBUS=6
@@ -25,7 +24,7 @@ CONFIG_MAX_WDOGPARMS=2
CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_MTU=590
CONFIG_NET_ETH_TCP_RECVWNDO=536
-CONFIG_NET_ICMPv6_PING=y
+CONFIG_NET_ICMPv6_SOCKET=y
CONFIG_NET_ICMPv6=y
CONFIG_NET_IPv6=y
CONFIG_NET_SOCKOPTS=y
@@ -60,6 +59,7 @@ CONFIG_START_DAY=24
CONFIG_START_MONTH=3
CONFIG_START_YEAR=2013
CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_SYSTEM_PING6=y
CONFIG_TIVA_BOARDMAC=y
CONFIG_TIVA_ETHERNET=y
CONFIG_TIVA_I2C6=y
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 8b48a45056..10e2408d09 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -204,7 +204,7 @@ static int lo_txpoll(FAR struct net_driver_s *dev)
else
#endif
{
- nwarn("WARNING: Unrecognized packet type dropped: %02x\n", IPv4BUF->vhl);
+ nwarn("WARNING: Unrecognized IP version\n");
NETDEV_RXDROPPED(&priv->lo_dev);
priv->lo_dev.d_len = 0;
}
diff --git a/include/netinet/in.h b/include/netinet/in.h
index c2d2244c7a..a9bc1c0689 100644
--- a/include/netinet/in.h
+++ b/include/netinet/in.h
@@ -51,7 +51,7 @@
/* Values for protocol argument to socket() */
-#define IPPROTO_IP 0 /* Dummy protocol for TCP */
+#define IPPROTO_IP 0 /* Default protocol */
#define IPPROTO_HOPOPTS 0 /* IPv6 Hop-by-Hop options. */
#define IPPROTO_ICMP 1 /* Internet Control Message Protocol */
#define IPPROTO_IGMP 2 /* Internet Group Management Protocol */
@@ -70,7 +70,7 @@
#define IPPROTO_GRE 47 /* General Routing Encapsulation. */
#define IPPROTO_ESP 50 /* Encapsulation Security Payload protocol */
#define IPPROTO_AH 51 /* Authentication Header protocol */
-#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_ICMP6 58 /* Internal Control Message Protocol v6 */
#define IPPROTO_NONE 59 /* IPv6 no next header. */
#define IPPROTO_DSTOPTS 60 /* IPv6 destination options. */
#define IPPROTO_MTP 92 /* Multicast Transport Protocol. */
diff --git a/include/nuttx/net/icmpv6.h b/include/nuttx/net/icmpv6.h
index 9d4417980b..b840d75357 100644
--- a/include/nuttx/net/icmpv6.h
+++ b/include/nuttx/net/icmpv6.h
@@ -363,36 +363,6 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
-/****************************************************************************
- * Name: imcp_ping
- *
- * Description:
- * Send a ECHO request and wait for the ECHO response
- *
- * Parameters:
- * addr - The IP address of the peer to send the ICMP ECHO request to
- * in network order.
- * id - The ID to use in the ICMP ECHO request. This number should be
- * unique; only ECHO responses with this matching ID will be
- * processed (host order)
- * seqno - The sequence number used in the ICMP ECHO request. NOT used
- * to match responses (host order)
- * dsecs - Wait up to this many deci-seconds for the ECHO response to be
- * returned (host order).
- *
- * Return:
- * seqno of received ICMP ECHO with matching ID (may be different
- * from the seqno argument (may be a delayed response from an earlier
- * ping with the same ID). Or a negated errno on any failure.
- *
- * Assumptions:
- * Called from the user level with interrupts enabled.
- *
- ****************************************************************************/
-
-int icmpv6_ping(net_ipv6addr_t addr, uint16_t id, uint16_t seqno,
- uint16_t datalen, int dsecs);
-
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c
index 1ebddbb6f2..5a3f555635 100644
--- a/net/devif/devif_poll.c
+++ b/net/devif/devif_poll.c
@@ -308,7 +308,7 @@ static inline int devif_poll_icmp(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#if defined(CONFIG_NET_ICMPv6_PING) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
+#if defined(CONFIG_NET_ICMPv6_SOCKET) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
static inline int devif_poll_icmpv6(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
@@ -324,7 +324,7 @@ static inline int devif_poll_icmpv6(FAR struct net_driver_s *dev,
return callback(dev);
}
-#endif /* CONFIG_NET_ICMPv6_PING || CONFIG_NET_ICMPv6_NEIGHBOR*/
+#endif /* CONFIG_NET_ICMPv6_SOCKET || CONFIG_NET_ICMPv6_NEIGHBOR*/
/****************************************************************************
* Name: devif_poll_forward
@@ -351,7 +351,7 @@ static inline int devif_poll_forward(FAR struct net_driver_s *dev,
return callback(dev);
}
-#endif /* CONFIG_NET_ICMPv6_PING || CONFIG_NET_ICMPv6_NEIGHBOR*/
+#endif /* CONFIG_NET_ICMPv6_SOCKET || CONFIG_NET_ICMPv6_NEIGHBOR*/
/****************************************************************************
* Name: devif_poll_igmp
@@ -610,7 +610,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
if (!bstop)
#endif
-#if defined(CONFIG_NET_ICMPv6_PING) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
+#if defined(CONFIG_NET_ICMPv6_SOCKET) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
{
/* Traverse all of the tasks waiting to send an ICMPv6 ECHO request. */
diff --git a/net/icmp/Kconfig b/net/icmp/Kconfig
index 7ed2ecd05b..9e541f7f5f 100644
--- a/net/icmp/Kconfig
+++ b/net/icmp/Kconfig
@@ -20,8 +20,8 @@ config NET_ICMP_SOCKET
default n
---help---
Enable support for IPPROTO_ICMP sockets. These sockets are needed
- for application level support application for sending ECHO (ping)
- requests and associated ECHO replies.
+ for application level support for sending ECHO (ping) requests and
+ receiving associated ECHO replies.
if NET_ICMP_SOCKET
diff --git a/net/icmp/icmp.h b/net/icmp/icmp.h
index a7c734caa8..ebb2a23d9a 100644
--- a/net/icmp/icmp.h
+++ b/net/icmp/icmp.h
@@ -321,10 +321,10 @@ ssize_t icmp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
* Name: icmp_pollsetup
*
* Description:
- * Setup to monitor events on one UDP/IP socket
+ * Setup to monitor events on one ICMP socket
*
* Input Parameters:
- * psock - The UDP/IP socket of interest
+ * psock - The IPPROTO_ICMP socket of interest
* fds - The structure describing the events to be monitored, OR NULL if
* this is a request to stop monitoring events.
*
@@ -341,7 +341,7 @@ int icmp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
* Name: icmp_pollteardown
*
* Description:
- * Teardown monitoring of events on an UDP/IP socket
+ * Teardown monitoring of events on an ICMP socket
*
* Input Parameters:
* psock - The IPPROTO_ICMP socket of interest
diff --git a/net/icmp/icmp_input.c b/net/icmp/icmp_input.c
index 0d993504dd..8e9c289a49 100644
--- a/net/icmp/icmp_input.c
+++ b/net/icmp/icmp_input.c
@@ -72,7 +72,7 @@
#define ICMPSIZE ((dev)->d_len - IPv4_HDRLEN)
/****************************************************************************
- * Public Functions
+ * Private Functions
****************************************************************************/
/****************************************************************************
@@ -95,8 +95,8 @@
****************************************************************************/
#ifdef CONFIG_NET_ICMP_SOCKET
-uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
- FAR struct icmp_conn_s *conn)
+static uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
+ FAR struct icmp_conn_s *conn)
{
FAR struct ipv4_hdr_s *ipv4;
struct sockaddr_in inaddr;
@@ -123,7 +123,7 @@ uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
ipv4 = IPv4BUF;
inaddr.sin_family = AF_INET;
- inaddr.sin_port = INADDR_ANY;
+ inaddr.sin_port = 0;
net_ipv4addr_copy(inaddr.sin_addr.s_addr,
net_ip4addr_conv32(ipv4->srcipaddr));
diff --git a/net/icmp/icmp_netpoll.c b/net/icmp/icmp_netpoll.c
index 07eb229c8a..aad9f8f33d 100644
--- a/net/icmp/icmp_netpoll.c
+++ b/net/icmp/icmp_netpoll.c
@@ -116,7 +116,7 @@ static uint16_t icmp_poll_eventhandler(FAR struct net_driver_s *dev,
/* ICMP_POLL is a sign that we are free to send data. */
- if ((flags & ICMP_POLL) != 0)
+ if ((flags & DEVPOLL_MASK) == ICMP_POLL)
{
eventset |= (POLLOUT & info->fds->events);
}
@@ -148,10 +148,10 @@ static uint16_t icmp_poll_eventhandler(FAR struct net_driver_s *dev,
* Name: icmp_pollsetup
*
* Description:
- * Setup to monitor events on one UDP/IP socket
+ * Setup to monitor events on one ICMP socket
*
* Input Parameters:
- * psock - The UDP/IP socket of interest
+ * psock - The IPPROTO_ICMP socket of interest
* fds - The structure describing the events to be monitored, OR NULL if
* this is a request to stop monitoring events.
*
@@ -261,7 +261,7 @@ errout_with_lock:
* Name: icmp_pollteardown
*
* Description:
- * Teardown monitoring of events on an UDP/IP socket
+ * Teardown monitoring of events on an ICMP socket
*
* Input Parameters:
* psock - The IPPROTO_ICMP socket of interest
diff --git a/net/icmp/icmp_recvfrom.c b/net/icmp/icmp_recvfrom.c
index 0559f37cf4..b9cccd546f 100644
--- a/net/icmp/icmp_recvfrom.c
+++ b/net/icmp/icmp_recvfrom.c
@@ -525,7 +525,7 @@ ssize_t icmp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
{
inaddr = (FAR struct sockaddr_in *)from;
inaddr->sin_family = AF_INET;
- inaddr->sin_port = INADDR_ANY;
+ inaddr->sin_port = 0;
net_ipv4addr_copy(inaddr->sin_addr.s_addr, state.recv_from);
}
diff --git a/net/icmp/icmp_sendto.c b/net/icmp/icmp_sendto.c
index 951d7e6666..9ee74e000e 100644
--- a/net/icmp/icmp_sendto.c
+++ b/net/icmp/icmp_sendto.c
@@ -75,9 +75,10 @@
* Pre-processor Definitions
****************************************************************************/
-#define IPv4BUF ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
-#define ICMPBUF ((struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN])
-#define ICMPDAT (&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN + ICMP_DHRLEN])
+#define IPv4BUF \
+ ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define ICMPBUF \
+ ((struct icmp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN])
/****************************************************************************
* Private Types
diff --git a/net/icmpv6/Kconfig b/net/icmpv6/Kconfig
index 62f4ca8943..f78793e8b1 100644
--- a/net/icmpv6/Kconfig
+++ b/net/icmpv6/Kconfig
@@ -16,17 +16,13 @@ config NET_ICMPv6
if NET_ICMPv6
-config NET_ICMPv6_PING
- bool "ICMPv6 ping interfaces"
+config NET_ICMPv6_SOCKET
+ bool "IPPROTO_ICMP6 socket support"
default n
- depends on BUILD_FLAT
---help---
- Provide interfaces to support application level support for
- for sending ECHO (ping) requests and associating ECHO replies.
-
- NOTE: Calling these interfaces from application space is a
- violation of the OS/application interface but for historical
- reasons, is permitted in the flat build.
+ Enable support for IPPROTO_ICMP6 sockets. These sockets are needed
+ for application level support for sending ICMPv7 ECHO requests and
+ receiving associated ICMPv6 ECHO replies.
config NET_ICMPv6_NEIGHBOR
bool "Solicit destination addresses"
@@ -183,6 +179,16 @@ config NET_ICMPv6_PREFIX_8
default for all eight values is fc00::0.
endif # NET_ICMPv6_ROUTER
+
+if NET_ICMPv6_SOCKET
+
+config NET_ICMPv6_NCONNS
+ int "Max ICMPv6 packet sockets"
+ default 4
+ depends on MM_IOB
+
+endif # NET_ICMPv6_SOCKET
+
endif # NET_ICMPv6
endmenu # ICMPv6 Networking Support
endif # NET_IPv6
diff --git a/net/icmpv6/Make.defs b/net/icmpv6/Make.defs
index 6c9b70aee7..b25acbe350 100644
--- a/net/icmpv6/Make.defs
+++ b/net/icmpv6/Make.defs
@@ -39,20 +39,22 @@ ifeq ($(CONFIG_NET_ICMPv6),y)
NET_CSRCS += icmpv6_input.c icmpv6_solicit.c icmpv6_advertise.c
-ifeq ($(CONFIG_NET_ICMPv6_PING),y)
-NET_CSRCS += icmpv6_ping.c
+ifeq ($(CONFIG_NET_ICMPv6_SOCKET),y)
+SOCK_CSRCS += icmpv6_sockif.c icmpv6_conn.c icmpv6_sendto.c
+SOCK_CSRCS += icmpv6_recvfrom.c
+ifeq ($(CONFIG_MM_IOB),y)
+SOCK_CSRCS += icmpv6_netpoll.c
+endif
endif
ifeq ($(CONFIG_NET_ICMPv6_NEIGHBOR),y)
NET_CSRCS += icmpv6_neighbor.c icmpv6_notify.c
endif
-ifeq ($(CONFIG_NET_ICMPv6_PING),y)
+ifeq ($(CONFIG_NET_ICMPv6_SOCKET),y)
+SOCK_CSRCS += icmpv6_poll.c
+else ifeq ($(CONFIG_NET_ICMPv6_NEIGHBOR),y)
NET_CSRCS += icmpv6_poll.c
-else
-ifeq ($(CONFIG_NET_ICMPv6_NEIGHBOR),y)
-NET_CSRCS += icmpv6_poll.c
-endif
endif
ifeq ($(CONFIG_NET_ICMPv6_AUTOCONF),y)
diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h
index 2b2c2380db..01859607a3 100644
--- a/net/icmpv6/icmpv6.h
+++ b/net/icmpv6/icmpv6.h
@@ -1,7 +1,7 @@
/****************************************************************************
* net/icmpv6/icmpv6.h
*
- * Copyright (C) 2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -43,9 +43,14 @@
#include
#include
+#include
#include
+#include
+#include
+#include
#include
+#include
#ifdef CONFIG_NET_ICMPv6
@@ -64,15 +69,34 @@
* Public Type Definitions
****************************************************************************/
-#if defined(CONFIG_NET_ICMPv6_PING) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) || \
- defined(CONFIG_NET_ICMPv6_AUTOCONF)
-/* For symmetry with other protocols, a "connection" structure is
- * provided. But, in this case, it is a singleton.
- */
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+/* Representation of a IPPROTO_ICMP socket connection */
+
+struct devif_callback_s; /* Forward reference */
struct icmpv6_conn_s
{
- FAR struct devif_callback_s *list; /* Neighbor discovery callbacks */
+ dq_entry_t node; /* Supports a double linked list */
+ 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 */
+
+ FAR struct net_driver_s *dev; /* Needed to free the callback structure */
+
+#ifdef CONFIG_MM_IOB
+ /* ICMPv6 response read-ahead list. A singly linked list of type struct
+ * iob_qentry_s where the ICMPv6 read-ahead data for the current ID is
+ * retained.
+ */
+
+ struct iob_queue_s readahead; /* Read-ahead buffering */
+#endif
+
+ /* Defines the list of IPPROTO_ICMP callbacks */
+
+ struct devif_callback_s *list;
};
#endif
@@ -112,12 +136,21 @@ extern "C"
# define EXTERN extern
#endif
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+/* PF_INET6 socket address family, IPPROTO_ICMP6 protocol interface */
+
+EXTERN const struct sock_intf_s g_icmpv6_sockif;
+#endif
+
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct timespec; /* Forward reference */
struct net_driver_s; /* Forward reference */
+struct socket; /* Forward reference */
+struct sockaddr; /* Forward reference */
+struct pollfd; /* Forward reference */
/****************************************************************************
* Name: icmpv6_input
@@ -180,7 +213,7 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr);
* Name: icmpv6_poll
*
* Description:
- * Poll a UDP "connection" structure for availability of TX data
+ * Poll a UDP "connection" structure for availability of ICMPv6 TX data
*
* Parameters:
* dev - The device driver structure to use in the send operation
@@ -193,7 +226,7 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr);
*
****************************************************************************/
-#if defined(CONFIG_NET_ICMPv6_PING) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
+#if defined(CONFIG_NET_ICMPv6_SOCKET) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
void icmpv6_poll(FAR struct net_driver_s *dev);
#endif
@@ -475,6 +508,232 @@ void icmpv6_rnotify(FAR struct net_driver_s *dev, const net_ipv6addr_t draddr,
# define icmpv6_rnotify(d,p,l)
#endif
+/****************************************************************************
+ * Name: imcp_ping
+ *
+ * Description:
+ * Send a ECHO request and wait for the ECHO response
+ *
+ * Parameters:
+ * addr - The IP address of the peer to send the ICMPv6 ECHO request to
+ * in network order.
+ * id - The ID to use in the ICMPv6 ECHO request. This number should be
+ * unique; only ECHO responses with this matching ID will be
+ * processed (host order)
+ * seqno - The sequence number used in the ICMPv6 ECHO request. NOT used
+ * to match responses (host order)
+ * dsecs - Wait up to this many deci-seconds for the ECHO response to be
+ * returned (host order).
+ *
+ * Return:
+ * seqno of received ICMPv6 ECHO with matching ID (may be different
+ * from the seqno argument (may be a delayed response from an earlier
+ * ping with the same ID). Or a negated errno on any failure.
+ *
+ * Assumptions:
+ * Called from the user level with interrupts enabled.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+int icmpv6_ping(net_ipv6addr_t addr, uint16_t id, uint16_t seqno,
+ uint16_t datalen, int dsecs);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_sock_initialize
+ *
+ * Description:
+ * Initialize the IPPROTO_ICMP socket connection structures. Called once
+ * and only from the network initialization layer.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+void icmpv6_sock_initialize(void);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_alloc
+ *
+ * Description:
+ * Allocate a new, uninitialized IPPROTO_ICMP socket connection structure.
+ * This is normally something done by the implementation of the socket()
+ * interface.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+FAR struct icmpv6_conn_s *icmpv6_alloc(void);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_free
+ *
+ * Description:
+ * Free a IPPROTO_ICMP socket connection structure that is no longer in
+ * use. This should be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+void icmpv6_free(FAR struct icmpv6_conn_s *conn);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_active()
+ *
+ * Description:
+ * Find a connection structure that is the appropriate connection to be
+ * used with the provided ECHO request ID.
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+FAR struct icmpv6_conn_s *icmpv6_active(uint16_t id);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_nextconn
+ *
+ * Description:
+ * Traverse the list of allocated packet connections
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+FAR struct icmpv6_conn_s *icmpv6_nextconn(FAR struct icmpv6_conn_s *conn);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_findconn
+ *
+ * Description:
+ * Find an ICMPv6 connection structure that is expecting a ICMPv6 ECHO response
+ * with this ID from this device
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+FAR struct icmpv6_conn_s *icmpv6_findconn(FAR struct net_driver_s *dev,
+ uint8_t id);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_sendto
+ *
+ * Description:
+ * Implements the sendto() operation for the case of the IPPROTO_ICMP6
+ * socket. The 'buf' parameter points to a block of memory that includes
+ * an ICMPv6 request header, followed by any payload that accompanies the
+ * request. The 'len' parameter includes both the size of the ICMPv6
+ * header and the following payload.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Data to send
+ * len Length of data to send
+ * flags Send flags
+ * to Address of recipient
+ * tolen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error, a negated
+ * errno value is returned (see send_to() for the list of appropriate error
+ * values.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+ssize_t icmpv6_sendto(FAR struct socket *psock, FAR const void *buf, size_t len,
+ int flags, FAR const struct sockaddr *to, socklen_t tolen);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_recvfrom
+ *
+ * Description:
+ * Implements the socket recvfrom interface for the case of the AF_INET6
+ * data gram socket with the IPPROTO_ICMP6 protocol. icmpv6_recvfrom()
+ * receives ICMPv6 ECHO replies for the a socket.
+ *
+ * If 'from' is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument 'fromlen' is
+ * initialized to the size of the buffer associated with from, and
+ * modified on return to indicate the actual size of the address stored
+ * there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Buffer to receive data
+ * len Length of buffer
+ * flags Receive flags
+ * from Address of source (may be NULL)
+ * fromlen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * recv() will return 0. Otherwise, on errors, a negated errno value is
+ * returned (see recvfrom() for the list of appropriate error values).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+ssize_t icmpv6_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
+ int flags, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_pollsetup
+ *
+ * Description:
+ * Setup to monitor events on one ICMPv6 socket
+ *
+ * Input Parameters:
+ * psock - The IPPROTO_ICMP6 socket of interest
+ * fds - The structure describing the events to be monitored, OR NULL if
+ * this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ * 0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+int icmpv6_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
+#endif
+
+/****************************************************************************
+ * Name: icmpv6_pollteardown
+ *
+ * Description:
+ * Teardown monitoring of events on an ICMPv6 socket
+ *
+ * Input Parameters:
+ * psock - The IPPROTO_ICMP6 socket of interest
+ * fds - The structure describing the events to be monitored, OR NULL if
+ * this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ * 0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+int icmpv6_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
+#endif
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/net/icmpv6/icmpv6_conn.c b/net/icmpv6/icmpv6_conn.c
new file mode 100644
index 0000000000..614285f862
--- /dev/null
+++ b/net/icmpv6/icmpv6_conn.c
@@ -0,0 +1,286 @@
+/****************************************************************************
+ * net/icmp/icmpv6_conn.c
+ *
+ * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "devif/devif.h"
+#include "icmpv6/icmpv6.h"
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The array containing all IPPROTO_ICMP socket connections */
+
+static struct icmpv6_conn_s g_icmpv6_connections[CONFIG_NET_ICMPv6_NCONNS];
+
+/* A list of all free IPPROTO_ICMP socket connections */
+
+static dq_queue_t g_free_icmpv6_connections;
+static sem_t g_free_sem;
+
+/* A list of all allocated IPPROTO_ICMP socket connections */
+
+static dq_queue_t g_active_icmpv6_connections;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_sock_initialize
+ *
+ * Description:
+ * Initialize the IPPROTO_ICMP socket connection structures. Called once
+ * and only from the network initialization layer.
+ *
+ ****************************************************************************/
+
+void icmpv6_sock_initialize(void)
+{
+ int i;
+
+ /* Initialize the queues */
+
+ dq_init(&g_free_icmpv6_connections);
+ dq_init(&g_active_icmpv6_connections);
+ nxsem_init(&g_free_sem, 0, 1);
+
+ for (i = 0; i < CONFIG_NET_ICMPv6_NCONNS; i++)
+ {
+ /* Move the connection structure to the free list */
+
+ dq_addlast(&g_icmpv6_connections[i].node, &g_free_icmpv6_connections);
+ }
+}
+
+/****************************************************************************
+ * Name: icmpv6_alloc
+ *
+ * Description:
+ * Allocate a new, uninitialized IPPROTO_ICMP socket connection structure.
+ * This is normally something done by the implementation of the socket()
+ * interface.
+ *
+ ****************************************************************************/
+
+FAR struct icmpv6_conn_s *icmpv6_alloc(void)
+{
+ FAR struct icmpv6_conn_s *conn = NULL;
+ int ret;
+
+ /* The free list is only accessed from user, non-interrupt level and
+ * is protected by a semaphore (that behaves like a mutex).
+ */
+
+ ret = net_lockedwait(&g_free_sem);
+ if (ret >= 0)
+ {
+ conn = (FAR struct icmpv6_conn_s *)dq_remfirst(&g_free_icmpv6_connections);
+ if (conn != NULL)
+ {
+ /* Clear the connection structure */
+
+ memset(conn, 0, sizeof(struct icmpv6_conn_s));
+
+ /* Enqueue the connection into the active list */
+
+ dq_addlast(&conn->node, &g_active_icmpv6_connections);
+ }
+
+ nxsem_post(&g_free_sem);
+ }
+
+ return conn;
+}
+
+/****************************************************************************
+ * Name: icmpv6_free
+ *
+ * Description:
+ * Free a IPPROTO_ICMP socket connection structure that is no longer in
+ * use. This should be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void icmpv6_free(FAR struct icmpv6_conn_s *conn)
+{
+ int ret;
+
+ /* The free list is only accessed from user, non-interrupt level and
+ * is protected by a semaphore (that behaves like a mutex).
+ */
+
+ DEBUGASSERT(conn->crefs == 0);
+
+ /* Take the semaphore (perhaps waiting) */
+
+ while ((ret = net_lockedwait(&g_free_sem)) < 0)
+ {
+ /* The only case that an error should occur here is if
+ * the wait was awakened by a signal.
+ */
+
+ DEBUGASSERT(ret == -EINTR);
+ }
+
+ UNUSED(ret);
+
+ /* Is this the last reference on the connection? It might not be if the
+ * socket was cloned.
+ */
+
+ if (conn->crefs > 1)
+ {
+ /* No.. just decrement the reference count */
+
+ conn->crefs--;
+ }
+ else
+ {
+ /* Remove the connection from the active list */
+
+ dq_rem(&conn->node, &g_active_icmpv6_connections);
+
+ /* Free the connection */
+
+ dq_addlast(&conn->node, &g_free_icmpv6_connections);
+ nxsem_post(&g_free_sem);
+ }
+}
+
+/****************************************************************************
+ * Name: icmpv6_active()
+ *
+ * Description:
+ * Find a connection structure that is the appropriate connection to be
+ * used with the provided ECHO request ID.
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+FAR struct icmpv6_conn_s *icmpv6_active(uint16_t id)
+{
+ FAR struct icmpv6_conn_s *conn =
+ (FAR struct icmpv6_conn_s *)g_active_icmpv6_connections.head;
+
+ while (conn != NULL)
+ {
+ /* FIXME lmac in conn should have been set by icmpv6_bind() */
+
+ if (id == conn->id)
+ {
+ /* Matching connection found.. return a reference to it */
+
+ break;
+ }
+
+ /* Look at the next active connection */
+
+ conn = (FAR struct icmpv6_conn_s *)conn->node.flink;
+ }
+
+ return conn;
+}
+
+/****************************************************************************
+ * Name: icmpv6_nextconn
+ *
+ * Description:
+ * Traverse the list of allocated packet connections
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+FAR struct icmpv6_conn_s *icmpv6_nextconn(FAR struct icmpv6_conn_s *conn)
+{
+ if (conn == NULL)
+ {
+ return (FAR struct icmpv6_conn_s *)g_active_icmpv6_connections.head;
+ }
+ else
+ {
+ return (FAR struct icmpv6_conn_s *)conn->node.flink;
+ }
+}
+
+/****************************************************************************
+ * Name: icmpv6_findconn
+ *
+ * Description:
+ * Find an ICMPv6 connection structure that is expecting a ICMPv6 ECHO response
+ * with this ID from this device
+ *
+ * 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, uint8_t id)
+{
+ FAR struct icmpv6_conn_s *conn;
+
+ for (conn = icmpv6_nextconn(NULL); conn != NULL; conn = icmpv6_nextconn(conn))
+ {
+ if (conn->id == id && conn->dev == dev && conn->nreqs > 0)
+ {
+ return conn;
+ }
+ }
+
+ return conn;
+}
+#endif /* CONFIG_NET_ICMP */
diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c
index cc2af0533a..5fe32d6859 100644
--- a/net/icmpv6/icmpv6_input.c
+++ b/net/icmpv6/icmpv6_input.c
@@ -64,8 +64,16 @@
* Pre-processor Definitions
****************************************************************************/
-#define ETHBUF ((struct eth_hdr_s *)&dev->d_buf[0])
-#define ICMPv6BUF ((struct icmpv6_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define ETHBUF \
+ ((struct eth_hdr_s *)&dev->d_buf[0])
+#define IPv6BUF \
+ ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define IPICMPv6 \
+ ((struct icmpv6_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define ICMPv6REPLY \
+ ((FAR struct icmpv6_echo_reply_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
+#define ICMPv6SIZE \
+ ((dev)->d_len - IPv6_HDRLEN)
#define ICMPv6SOLICIT \
((struct icmpv6_neighbor_solicit_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
@@ -74,6 +82,127 @@
#define ICMPv6RADVERTISE \
((struct icmpv6_router_advertise_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_datahandler
+ *
+ * Description:
+ * Handle ICMPv6 echo replies that are not accepted by the application.
+ *
+ * Input Parameters:
+ * dev - Device instance only the input packet in d_buf, length = d_len;
+ * conn - A pointer to the ICMPv6 connection structure
+ * buffer - A pointer to the buffer to be copied to the read-ahead
+ * buffers
+ * buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned value:
+ * The number of bytes actually buffered is returned. This will be either
+ * zero or equal to buflen; partial packets are not buffered.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
+ FAR struct icmpv6_conn_s *conn)
+{
+ FAR struct ipv6_hdr_s *ipv6;
+ struct sockaddr_in6 inaddr;
+ FAR struct iob_s *iob;
+ uint16_t offset;
+ uint16_t buflen;
+ uint8_t addrsize;
+ int ret;
+
+ /* Try to allocate on I/O buffer to start the chain without waiting (and
+ * throttling as necessary). If we would have to wait, then drop the
+ * packet.
+ */
+
+ iob = iob_tryalloc(true);
+ if (iob == NULL)
+ {
+ nerr("ERROR: Failed to create new I/O buffer chain\n");
+ return 0;
+ }
+
+ /* Put the IPv6 address at the beginning of the read-ahead buffer */
+
+ ipv6 = IPv6BUF;
+ inaddr.sin6_family = AF_INET6;
+ inaddr.sin6_port = 0;
+ net_ipv6addr_copy(inaddr.sin6_addr.s6_addr16, ipv6->srcipaddr);
+
+ /* Copy the src address info into the I/O buffer chain. We will not wait
+ * for an I/O buffer to become available in this context. It there is
+ * any failure to allocated, the entire I/O buffer chain will be discarded.
+ */
+
+ addrsize = sizeof(struct sockaddr_in6);
+ ret = iob_trycopyin(iob, &addrsize, sizeof(uint8_t), 0, true);
+ 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 length to the I/O buffer chain: %d\n", ret);
+ (void)iob_free_chain(iob);
+ return 0;
+ }
+
+ offset = sizeof(uint8_t);
+
+ ret = iob_trycopyin(iob, (FAR const uint8_t *)&inaddr,
+ sizeof(struct sockaddr_in6), offset, true);
+ 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 source address to the I/O buffer chain: %d\n", ret);
+ (void)iob_free_chain(iob);
+ return 0;
+ }
+
+ offset += sizeof(struct sockaddr_in6);
+
+ /* Copy the new ICMPv6 reply into the I/O buffer chain (without waiting) */
+
+ buflen = ICMPv6SIZE;
+ ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPv6REPLY, buflen, offset, true);
+ if (ret < 0)
+ {
+ /* On a failure, iob_copyin return a negated error value but does
+ * not free any I/O buffers.
+ */
+
+ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
+ (void)iob_free_chain(iob);
+ return 0;
+ }
+
+ /* Add the new I/O buffer chain to the tail of the read-ahead queue (again
+ * without waiting).
+ */
+
+ ret = iob_tryadd_queue(iob, &conn->readahead);
+ if (ret < 0)
+ {
+ nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
+ (void)iob_free_chain(iob);
+ return 0;
+ }
+
+ ninfo("Buffered %d bytes\n", buflen + addrsize + 1);
+ return buflen;
+}
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -98,7 +227,7 @@
void icmpv6_input(FAR struct net_driver_s *dev)
{
- FAR struct icmpv6_iphdr_s *icmp = ICMPv6BUF;
+ FAR struct icmpv6_iphdr_s *ipicmp = IPICMPv6;
#ifdef CONFIG_NET_STATISTICS
g_netstats.icmpv6.recv++;
@@ -106,7 +235,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
/* Handle the ICMPv6 message by its type */
- switch (icmp->type)
+ switch (ipicmp->type)
{
/* If we get a neighbor solicitation for our address we should send
* a neighbor advertisement message back.
@@ -125,7 +254,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
* solicitation came from.
*/
- icmpv6_advertise(dev, icmp->srcipaddr);
+ icmpv6_advertise(dev, ipicmp->srcipaddr);
/* All statistics have been updated. Nothing to do but exit. */
@@ -153,7 +282,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
*/
adv = ICMPv6ADVERTISE;
- if (net_ipv6addr_cmp(icmp->destipaddr, dev->d_ipv6addr))
+ if (net_ipv6addr_cmp(ipicmp->destipaddr, dev->d_ipv6addr))
{
/* This message is required to support the Target link-layer
* address option.
@@ -163,12 +292,12 @@ void icmpv6_input(FAR struct net_driver_s *dev)
{
/* Save the sender's address mapping in our Neighbor Table. */
- neighbor_add(dev, icmp->srcipaddr, adv->tgtlladdr);
+ neighbor_add(dev, ipicmp->srcipaddr, adv->tgtlladdr);
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
/* Then notify any logic waiting for the Neighbor Advertisement */
- icmpv6_notify(icmp->srcipaddr);
+ icmpv6_notify(ipicmp->srcipaddr);
#endif
/* We consumed the packet but we don't send anything in
@@ -213,7 +342,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
/* Get the length of the option data */
- pktlen = (uint16_t)icmp->len[0] << 8 | icmp->len[1];
+ pktlen = (uint16_t)ipicmp->len[0] << 8 | ipicmp->len[1];
if (pktlen <= ICMPv6_RADV_MINLEN)
{
/* Too small to contain any options */
@@ -238,7 +367,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
if (sllopt->opttype == 1 && sllopt->optlen == 1)
{
- neighbor_add(dev, icmp->srcipaddr, sllopt->srclladdr);
+ neighbor_add(dev, ipicmp->srcipaddr, sllopt->srclladdr);
}
FAR struct icmpv6_prefixinfo_s *opt =
@@ -254,7 +383,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
{
/* Yes.. Notify any waiting threads */
- icmpv6_rnotify(dev, icmp->srcipaddr, opt->prefix, opt->preflen);
+ icmpv6_rnotify(dev, ipicmp->srcipaddr, opt->prefix, opt->preflen);
goto icmpv_send_nothing;
}
@@ -277,17 +406,17 @@ void icmpv6_input(FAR struct net_driver_s *dev)
* ICMPv6 checksum before we return the packet.
*/
- icmp->type = ICMPv6_ECHO_REPLY;
+ ipicmp->type = ICMPv6_ECHO_REPLY;
- net_ipv6addr_copy(icmp->destipaddr, icmp->srcipaddr);
- net_ipv6addr_copy(icmp->srcipaddr, dev->d_ipv6addr);
+ net_ipv6addr_copy(ipicmp->destipaddr, ipicmp->srcipaddr);
+ net_ipv6addr_copy(ipicmp->srcipaddr, dev->d_ipv6addr);
- icmp->chksum = 0;
- icmp->chksum = ~icmpv6_chksum(dev);
+ ipicmp->chksum = 0;
+ ipicmp->chksum = ~icmpv6_chksum(dev);
}
break;
-#ifdef CONFIG_NET_ICMPv6_PING
+#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.
*/
@@ -298,15 +427,43 @@ void icmpv6_input(FAR struct net_driver_s *dev)
/* Dispatch the ECHO reply to the waiting thread */
- flags = devif_conn_event(dev, icmp, flags, dev->d_conncb);
+ flags = devif_conn_event(dev, ipicmp, flags, dev->d_conncb);
- /* If the ECHO reply was not handled, then drop the packet */
+ /* Wwas the ECHO reply consumed by any waiting thread? */
- if (flags == ICMPv6_ECHOREPLY)
+ if ((flags & ICMPv6_ECHOREPLY) != 0)
{
- /* The ECHO reply was not handled */
+ FAR struct icmpv6_echo_reply_s *reply;
+ FAR struct icmpv6_conn_s *conn;
+ uint16_t nbuffered;
- goto icmpv6_drop_packet;
+ /* Nothing consumed the ICMP reply. That might 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;
+ }
+
+ /* Yes.. Add the ICMP echo reply to the IPPROTO_ICMP socket read
+ * ahead buffer.
+ */
+
+ nbuffered = icmpv6_datahandler(dev, conn);
+ if (nbuffered == 0)
+ {
+ /* Could not buffer the data.. drop the packet */
+
+ goto icmpv6_drop_packet;
+ }
}
}
break;
@@ -314,13 +471,13 @@ void icmpv6_input(FAR struct net_driver_s *dev)
default:
{
- nwarn("WARNING: Unknown ICMPv6 type: %d\n", icmp->type);
+ nwarn("WARNING: Unknown ICMPv6 type: %d\n", ipicmp->type);
goto icmpv6_type_error;
}
}
ninfo("Outgoing ICMPv6 packet length: %d (%d)\n",
- dev->d_len, (icmp->len[0] << 8) | icmp->len[1]);
+ dev->d_len, (ipicmp->len[0] << 8) | ipicmp->len[1]);
#ifdef CONFIG_NET_STATISTICS
g_netstats.icmpv6.sent++;
diff --git a/net/icmpv6/icmpv6_netpoll.c b/net/icmpv6/icmpv6_netpoll.c
new file mode 100644
index 0000000000..e646bbf418
--- /dev/null
+++ b/net/icmpv6/icmpv6_netpoll.c
@@ -0,0 +1,311 @@
+/****************************************************************************
+ * net/icmpv6/icmpv6_netpoll.c
+ *
+ * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include "icmpv6/icmpv6.h"
+
+#ifdef CONFIG_MM_IOB
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This is an allocated container that holds the poll-related information */
+
+struct icmpv6_poll_s
+{
+ struct pollfd *fds; /* Needed to handle poll events */
+ FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_poll_eventhandler
+ *
+ * Description:
+ * This function is called to perform the actual UDP receive operation
+ * via the device interface layer.
+ *
+ * Parameters:
+ * dev The structure of the network driver that caused the event
+ * conn The connection structure associated with the socket
+ * flags Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static uint16_t icmpv6_poll_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct icmpv6_poll_s *info = (FAR struct icmpv6_poll_s *)pvpriv;
+ FAR struct icmpv6_conn_s *conn = (FAR struct icmpv6_conn_s *)pvconn;
+ pollevent_t eventset;
+
+ ninfo("flags: %04x\n", flags);
+
+ DEBUGASSERT(info == NULL || (info->fds != NULL && conn != NULL));
+
+ /* 'priv' might be null in some race conditions (?). Only process the
+ * the event if this poll is from the same device that the request was
+ * sent out on.
+ */
+
+ if (info != NULL && dev == conn->dev)
+ {
+ /* Check for data or connection availability events. */
+
+ eventset = 0;
+ if ((flags & ICMPv6_ECHOREPLY) != 0)
+ {
+ eventset |= (POLLIN & info->fds->events);
+ }
+
+ /* ICMP_POLL is a sign that we are free to send data. */
+
+ if ((flags & DEVPOLL_MASK) == ICMPv6_POLL)
+ {
+ eventset |= (POLLOUT & info->fds->events);
+ }
+
+ /* Check for loss of connection events. */
+
+ if ((flags & NETDEV_DOWN) != 0)
+ {
+ eventset |= ((POLLHUP | POLLERR) & info->fds->events);
+ }
+
+ /* Awaken the caller of poll() is requested event occurred. */
+
+ if (eventset)
+ {
+ info->fds->revents |= eventset;
+ nxsem_post(info->fds->sem);
+ }
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_pollsetup
+ *
+ * Description:
+ * Setup to monitor events on one ICMP socket
+ *
+ * Input Parameters:
+ * psock - The IPPROTO_ICMP socket of interest
+ * fds - The structure describing the events to be monitored, OR NULL if
+ * this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ * 0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+int icmpv6_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
+{
+ FAR struct icmpv6_conn_s *conn = psock->s_conn;
+ FAR struct icmpv6_poll_s *info;
+ FAR struct devif_callback_s *cb;
+ int ret;
+
+ DEBUGASSERT(conn != NULL && fds != NULL && conn->dev != NULL);
+
+ /* Allocate a container to hold the poll information */
+
+ info = (FAR struct icmpv6_poll_s *)kmm_malloc(sizeof(struct icmpv6_poll_s));
+ if (!info)
+ {
+ return -ENOMEM;
+ }
+
+ /* Some of the following must be atomic */
+
+ net_lock();
+
+ /* Get the device that will provide the provide the NETDEV_DOWN event.
+ * NOTE: in the event that the local socket is bound to IN6ADDR_ANY, the
+ * dev value will be zero and there will be no NETDEV_DOWN notifications.
+ */
+
+ /* Allocate a ICMP callback structure */
+
+ cb = icmpv6_callback_alloc(conn->dev);
+ if (cb == NULL)
+ {
+ ret = -EBUSY;
+ goto errout_with_lock;
+ }
+
+ /* Initialize the poll info container */
+
+ info->fds = fds;
+ info->cb = cb;
+
+ /* Initialize the callback structure. Save the reference to the info
+ * structure as callback private data so that it will be available during
+ * callback processing.
+ */
+
+ cb->flags = 0;
+ cb->priv = (FAR void *)info;
+ cb->event = icmpv6_poll_eventhandler;
+
+ if ((info->fds->events & POLLOUT) != 0)
+ {
+ cb->flags |= UDP_POLL;
+ }
+
+ if ((info->fds->events & POLLIN) != 0)
+ {
+ cb->flags |= UDP_NEWDATA;
+ }
+
+ if ((info->fds->events & (POLLHUP | POLLERR)) != 0)
+ {
+ cb->flags |= NETDEV_DOWN;
+ }
+
+ /* Save the reference in the poll info structure as fds private as well
+ * for use during poll teardown as well.
+ */
+
+ fds->priv = (FAR void *)info;
+
+ /* Check for read data availability now */
+
+ if (!IOB_QEMPTY(&conn->readahead))
+ {
+ /* Normal data may be read without blocking. */
+
+ fds->revents |= (POLLRDNORM & fds->events);
+ }
+
+ /* Check if any requested events are already in effect */
+
+ if (fds->revents != 0)
+ {
+ /* Yes.. then signal the poll logic */
+
+ nxsem_post(fds->sem);
+ }
+
+ net_unlock();
+ return OK;
+
+errout_with_lock:
+ kmm_free(info);
+ net_unlock();
+ return ret;
+}
+
+/****************************************************************************
+ * Name: icmpv6_pollteardown
+ *
+ * Description:
+ * Teardown monitoring of events on an ICMP socket
+ *
+ * Input Parameters:
+ * psock - The IPPROTO_ICMP socket of interest
+ * fds - The structure describing the events to be monitored, OR NULL if
+ * this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ * 0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+int icmpv6_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
+{
+ FAR struct icmpv6_conn_s *conn;
+ FAR struct icmpv6_poll_s *info;
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
+ fds != NULL && fds->priv != NULL);
+
+ conn = psock->s_conn;
+
+ /* Recover the socket descriptor poll state info from the poll structure */
+
+ info = (FAR struct icmpv6_poll_s *)fds->priv;
+ DEBUGASSERT(info != NULL && info->fds != NULL && info->cb != NULL);
+
+ if (info != NULL)
+ {
+ /* Release the callback */
+
+ net_lock();
+ icmpv6_callback_free(conn->dev, info->cb);
+ net_unlock();
+
+ /* Release the poll/select data slot */
+
+ info->fds->priv = NULL;
+
+ /* Then free the poll info container */
+
+ kmm_free(info);
+ }
+
+ return OK;
+}
+
+#endif /* !CONFIG_MM_IOB */
diff --git a/net/icmpv6/icmpv6_ping.c b/net/icmpv6/icmpv6_ping.c
deleted file mode 100644
index a2e4150b0b..0000000000
--- a/net/icmpv6/icmpv6_ping.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/****************************************************************************
- * net/icmpv6/icmpv6_ping.c
- *
- * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include
-#ifdef CONFIG_NET_ICMPv6_PING
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "netdev/netdev.h"
-#include "devif/devif.h"
-#include "inet/inet.h"
-#include "utils/utils.h"
-#include "icmpv6/icmpv6.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#define ETHBUF ((struct eth_hdr_s *)&dev->d_buf[0])
-#define ICMPv6BUF ((struct icmpv6_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
-#define ICMPv6ECHOREQ \
- ((struct icmpv6_echo_request_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
-#define ICMPv6ECHOREPLY \
- ((struct icmpv6_echo_reply_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct icmpv6_ping_s
-{
- FAR struct devif_callback_s *png_cb; /* Reference to callback instance */
-
- sem_t png_sem; /* Use to manage the wait for the response */
- systime_t png_time; /* Start time for determining timeouts */
- systime_t png_ticks; /* System clock ticks to wait */
- int png_result; /* 0: success; <0:negated errno on fail */
- net_ipv6addr_t png_addr; /* The peer to be ping'ed */
- uint16_t png_id; /* Used to match requests with replies */
- uint16_t png_seqno; /* IN: seqno to send; OUT: seqno received */
- uint16_t png_datlen; /* The length of data to send in the ECHO request */
- bool png_sent; /* true... the PING request has been sent */
-};
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: ping_timeout
- *
- * Description:
- * Check for send timeout.
- *
- * Parameters:
- * pstate - Ping state structure
- *
- * Returned Value:
- * TRUE:timeout FALSE:no timeout
- *
- * Assumptions:
- * The network is locked
- *
- ****************************************************************************/
-
-static inline int ping_timeout(FAR struct icmpv6_ping_s *pstate)
-{
- systime_t elapsed = clock_systimer() - pstate->png_time;
- if (elapsed >= pstate->png_ticks)
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/****************************************************************************
- * Name: icmpv6_echo_request
- *
- * Description:
- * Format an ICMPv6 Echo Request message.. This version
- * is for a standalone solicitation. If formats:
- *
- * - The Ethernet header
- * - The IPv6 header
- * - The ICMPv6 Echo Request Message
- *
- * Parameters:
- * dev - Reference to an Ethernet device driver structure
- * pstate - Ping state structure
- *
- * Return:
- * None
- *
- ****************************************************************************/
-
-static void icmpv6_echo_request(FAR struct net_driver_s *dev,
- FAR struct icmpv6_ping_s *pstate)
-{
- FAR struct icmpv6_iphdr_s *icmp;
- FAR struct icmpv6_echo_request_s *req;
- uint16_t reqlen;
- int i;
-
- ninfo("Send ECHO request: seqno=%d\n", pstate->png_seqno);
-
- /* Set up the IPv6 header (most is probably already in place) */
-
- icmp = ICMPv6BUF;
- icmp->vtc = 0x60; /* Version/traffic class (MS) */
- icmp->tcf = 0; /* Traffic class (LS)/Flow label (MS) */
- icmp->flow = 0; /* Flow label (LS) */
-
- /* Length excludes the IPv6 header */
-
- reqlen = SIZEOF_ICMPV6_ECHO_REQUEST_S(pstate->png_datlen);
- icmp->len[0] = (reqlen >> 8);
- icmp->len[1] = (reqlen & 0xff);
-
- icmp->proto = IP_PROTO_ICMP6; /* Next header */
- icmp->ttl = IP_TTL; /* Hop limit */
-
- /* Set the multicast destination IP address */
-
- net_ipv6addr_copy(icmp->destipaddr, pstate->png_addr);
-
- /* Add out IPv6 address as the source address */
-
- net_ipv6addr_copy(icmp->srcipaddr, dev->d_ipv6addr);
-
- /* Set up the ICMPv6 Echo Request message */
-
- req = ICMPv6ECHOREQ;
- req->type = ICMPv6_ECHO_REQUEST; /* Message type */
- req->code = 0; /* Message qualifier */
- req->id = htons(pstate->png_id);
- req->seqno = htons(pstate->png_seqno);
-
- /* Add some easily verifiable data */
-
- for (i = 0; i < pstate->png_datlen; i++)
- {
- req->data[i] = i;
- }
-
- /* Calculate the checksum over both the ICMP header and payload */
-
- icmp->chksum = 0;
- icmp->chksum = ~icmpv6_chksum(dev);
-
- /* Set the size to the size of the IPv6 header and the payload size */
-
- IFF_SET_IPv6(dev->d_flags);
-
- dev->d_sndlen = reqlen;
- dev->d_len = reqlen + IPv6_HDRLEN;
-
- ninfo("Outgoing ICMPv6 Echo Request length: %d (%d)\n",
- dev->d_len, (icmp->len[0] << 8) | icmp->len[1]);
-
-#ifdef CONFIG_NET_STATISTICS
- g_netstats.icmpv6.sent++;
- g_netstats.ipv6.sent++;
-#endif
-}
-
-/****************************************************************************
- * Name: ping_eventhandler
- *
- * Description:
- * This function is called from the interrupt level to perform the actual
- * ECHO request and/or ECHO reply actions when polled by the lower, device
- * interfacing layer.
- *
- * Parameters:
- * dev The structure of the network driver that caused the interrupt
- * conn The received packet, cast to void *
- * pvpriv An instance of struct icmpv6_ping_s cast to void*
- * flags Set of events describing why the callback was invoked
- *
- * Returned Value:
- * Modified value of the input flags
- *
- * Assumptions:
- * The network is locked
- *
- ****************************************************************************/
-
-static uint16_t ping_eventhandler(FAR struct net_driver_s *dev,
- FAR void *conn,
- FAR void *pvpriv, uint16_t flags)
-{
- FAR struct icmpv6_ping_s *pstate = (struct icmpv6_ping_s *)pvpriv;
-
- ninfo("flags: %04x\n", flags);
-
- if (pstate)
- {
- /* Check if the network is still up */
-
- if ((flags & NETDEV_DOWN) != 0)
- {
- nerr("ERROR: Interface is down\n");
- pstate->png_result = -ENETUNREACH;
- goto end_wait;
- }
-
- /* Check if this is a ICMPv6 ECHO reply. If so, return the sequence
- * number to the caller. NOTE: We may not even have sent the
- * requested ECHO request; this could have been the delayed ECHO
- * response from a previous ping.
- */
-
- else if ((flags & ICMPv6_ECHOREPLY) != 0 && conn != NULL)
- {
- FAR struct icmpv6_echo_reply_s *reply = ICMPv6ECHOREPLY;
-
- ninfo("ECHO reply: id=%d seqno=%d\n",
- ntohs(reply->id), ntohs(reply->seqno));
-
- if (ntohs(reply->id) == pstate->png_id)
- {
- /* Consume the ECHOREPLY */
-
- flags &= ~ICMPv6_ECHOREPLY;
- dev->d_len = 0;
-
- /* Return the result to the caller */
-
- pstate->png_result = OK;
- pstate->png_seqno = ntohs(reply->seqno);
- goto end_wait;
- }
- }
-
- /* Check:
- * If the outgoing packet is available (it may have been claimed
- * by a sendto interrupt serving a different thread)
- * -OR-
- * If the output buffer currently contains unprocessed incoming
- * data.
- * -OR-
- * If we have already sent the ECHO request
- *
- * In the first two cases, we will just have to wait for the next
- * polling cycle.
- */
-
- if (dev->d_sndlen <= 0 && /* Packet available */
- (flags & ICMPv6_NEWDATA) == 0 && /* No incoming data */
- !pstate->png_sent) /* Request not sent */
- {
- /* Send the ECHO request now. */
-
- icmpv6_echo_request(dev, pstate);
- pstate->png_sent = true;
- return flags;
- }
-
- /* Check if the selected timeout has elapsed */
-
- if (ping_timeout(pstate))
- {
- int failcode;
-
- /* Check if this device is on the same network as the destination
- * device.
- */
-
- if (!net_ipv6addr_maskcmp(pstate->png_addr, dev->d_ipv6addr,
- dev->d_ipv6netmask))
- {
- /* Destination address was not on the local network served by
- * this device. If a timeout occurs, then the most likely
- * reason is that the destination address is not reachable.
- */
-
- nerr("ERROR: Not reachable\n");
- failcode = -ENETUNREACH;
- }
- else
- {
- nerr("ERROR: Ping timeout\n");
- failcode = -ETIMEDOUT;
- }
-
- /* Report the failure */
-
- pstate->png_result = failcode;
- goto end_wait;
- }
-
- /* Continue waiting */
- }
-
- return flags;
-
-end_wait:
- ninfo("Resuming\n");
-
- /* Do not allow any further callbacks */
-
- pstate->png_cb->flags = 0;
- pstate->png_cb->priv = NULL;
- pstate->png_cb->event = NULL;
-
- /* Wake up the waiting thread */
-
- nxsem_post(&pstate->png_sem);
- return flags;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: imcpv6_ping
- *
- * Description:
- * Send a ECHO request and wait for the ECHO response
- *
- * Parameters:
- * addr - The IP address of the peer to send the ICMPv6 ECHO request to
- * in network order.
- * id - The ID to use in the ICMPv6 ECHO request. This number should be
- * unique; only ECHO responses with this matching ID will be
- * processed (host order)
- * seqno - The sequence number used in the ICMPv6 ECHO request. NOT used
- * to match responses (host order)
- * dsecs - Wait up to this many deci-seconds for the ECHO response to be
- * returned (host order).
- *
- * Return:
- * seqno of received ICMPv6 ECHO with matching ID (may be different
- * from the seqno argument (may be a delayed response from an earlier
- * ping with the same ID). Or a negated errno on any failure.
- *
- * Assumptions:
- * Called from the user level with interrupts enabled.
- *
- ****************************************************************************/
-
-int icmpv6_ping(net_ipv6addr_t addr, uint16_t id, uint16_t seqno,
- uint16_t datalen, int dsecs)
-{
- FAR struct net_driver_s *dev;
- struct icmpv6_ping_s state;
-
-#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
- int ret;
-
- /* Make sure that the IP address mapping is in the Neighbor Table */
-
- ret = icmpv6_neighbor(addr);
- if (ret < 0)
- {
- nerr("ERROR: Not reachable\n");
- return -ENETUNREACH;
- }
-#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */
-
- /* Get the device that will be used to route this ICMP ECHO request */
-
- dev = netdev_findby_ipv6addr(g_ipv6_allzeroaddr, addr);
- if (dev == 0)
- {
- nerr("ERROR: Not reachable\n");
- return -ENETUNREACH;
- }
-
- /* Initialize the state structure */
-
- /* This semaphore is used for signaling and, hence, should not have
- * priority inheritance enabled.
- */
-
- nxsem_init(&state.png_sem, 0, 0);
- nxsem_setprotocol(&state.png_sem, SEM_PRIO_NONE);
-
- state.png_ticks = DSEC2TICK(dsecs); /* System ticks to wait */
- state.png_result = -ENOMEM; /* Assume allocation failure */
- state.png_id = id; /* The ID to use in the ECHO request */
- state.png_seqno = seqno; /* The seqno to use in the ECHO request */
- state.png_datlen = datalen; /* The length of data to send in the ECHO request */
- state.png_sent = false; /* ECHO request not yet sent */
-
- net_ipv6addr_copy(state.png_addr, addr); /* Address of the peer to be ping'ed */
-
- net_lock();
- state.png_time = clock_systimer();
-
- /* Set up the callback */
-
- state.png_cb = icmpv6_callback_alloc(dev);
- if (state.png_cb)
- {
- state.png_cb->flags = (ICMPv6_POLL | ICMPv6_ECHOREPLY);
- state.png_cb->priv = (FAR void *)&state;
- state.png_cb->event = ping_eventhandler;
- state.png_result = -EINTR; /* Assume sem-wait interrupted by signal */
-
- /* Notify the device driver of the availability of TX data */
-
- netdev_txnotify_dev(dev);
-
- /* Wait for either the full round trip transfer to complete or
- * for timeout to occur. (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.
- */
-
- ninfo("Start time: 0x%08x seqno: %d\n", state.png_time, seqno);
- net_lockedwait(&state.png_sem);
-
- icmpv6_callback_free(dev, state.png_cb);
- }
-
- net_unlock();
-
- /* Return the negated error number in the event of a failure, or the
- * sequence number of the ECHO reply on success.
- */
-
- if (!state.png_result)
- {
- ninfo("Return seqno=%d\n", state.png_seqno);
- return (int)state.png_seqno;
- }
- else
- {
- nerr("ERROR: Return error=%d\n", -state.png_result);
- return state.png_result;
- }
-}
-
-#endif /* CONFIG_NET_ICMPv6_PING */
diff --git a/net/icmpv6/icmpv6_poll.c b/net/icmpv6/icmpv6_poll.c
index 10b7beca0d..39af5d75c0 100644
--- a/net/icmpv6/icmpv6_poll.c
+++ b/net/icmpv6/icmpv6_poll.c
@@ -38,7 +38,7 @@
****************************************************************************/
#include
-#if defined(CONFIG_NET_ICMPv6_PING) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
+#if defined(CONFIG_NET_ICMPv6_SOCKET) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
#include
#include
@@ -100,4 +100,4 @@ void icmpv6_poll(FAR struct net_driver_s *dev)
(void)devif_conn_event(dev, NULL, ICMPv6_POLL, dev->d_conncb);
}
-#endif /* CONFIG_NET_ICMPv6_PING || CONFIG_NET_ICMPv6_NEIGHBOR */
+#endif /* CONFIG_NET_ICMPv6_SOCKET || CONFIG_NET_ICMPv6_NEIGHBOR */
diff --git a/net/icmpv6/icmpv6_recvfrom.c b/net/icmpv6/icmpv6_recvfrom.c
new file mode 100644
index 0000000000..79715ca245
--- /dev/null
+++ b/net/icmpv6/icmpv6_recvfrom.c
@@ -0,0 +1,556 @@
+/****************************************************************************
+ * net/icmpv6/icmpv6_recvfrom.c
+ *
+ * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "devif/devif.h"
+#include "socket/socket.h"
+#include "icmpv6/icmpv6.h"
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define IPv6_BUF \
+ ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define ICMPv6_BUF \
+ ((struct icmpv6_echo_reply_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
+#define ICMPv6_SIZE \
+ ((dev)->d_len - IPv6_HDRLEN)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct icmpv6_recvfrom_s
+{
+ FAR struct devif_callback_s *recv_cb; /* Reference to callback instance */
+ FAR struct socket *recv_sock; /* IPPROTO_ICMP6 socket structure */
+ sem_t recv_sem; /* Use to manage the wait for the response */
+ systime_t recv_time; /* Start time for determining timeouts */
+ struct in6_addr recv_from; /* The peer we received the request from */
+ FAR uint8_t *recv_buf; /* Location to return the response */
+ uint16_t recv_buflen; /* Size of the response */
+ int16_t recv_result; /* >=0: receive size on success;
+ * <0:negated errno on fail */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: recvfrom_timeout
+ *
+ * Description:
+ * Check for send timeout.
+ *
+ * Parameters:
+ * pstate - Reference to instance ot recvfrom state structure
+ *
+ * Returned Value:
+ * true: timeout false: no timeout
+ *
+ * Assumptions:
+ * The network is locked
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_SOCKOPTS
+static inline int recvfrom_timeout(FAR struct icmpv6_recvfrom_s *pstate)
+{
+ FAR struct socket *psock;
+
+ /* Check for a timeout configured via setsockopts(SO_SNDTIMEO).
+ * If none... we will let the send wait forever.
+ */
+
+ psock = pstate->recv_sock;
+ if (psock != NULL && psock->s_rcvtimeo != 0)
+ {
+ /* Check if the configured timeout has elapsed */
+
+ return net_timeo(pstate->recv_time, psock->s_rcvtimeo);
+ }
+
+ /* No timeout */
+
+ return false;
+}
+#endif /* CONFIG_NET_SOCKOPTS */
+
+/****************************************************************************
+ * Name: recvfrom_eventhandler
+ *
+ * Description:
+ * This function is called from the interrupt level to perform the actual
+ * ECHO request and/or ECHO reply actions when polled by the lower, device
+ * interfacing layer.
+ *
+ * Parameters:
+ * dev The structure of the network driver that caused the interrupt
+ * conn The received packet, cast to void *
+ * pvpriv An instance of struct icmpv6_recvfrom_s cast to void*
+ * flags Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ * Modified value of the input flags
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static uint16_t recvfrom_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct icmpv6_recvfrom_s *pstate = (struct icmpv6_recvfrom_s *)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);
+
+ if (pstate != NULL)
+ {
+ /* Check if the network is still up */
+
+ if ((flags & NETDEV_DOWN) != 0)
+ {
+ nerr("ERROR: Interface is down\n");
+ pstate->recv_result = -ENETUNREACH;
+ 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. */
+
+ if ((flags & ICMPv6_ECHOREPLY) != 0) /* No incoming data */
+ {
+ unsigned int recvsize;
+
+ /* Check if it is for us */
+
+ icmpv6 = ICMPv6_BUF;
+ 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
+ * buffer that the caller of sendto provided? Truncate? Error
+ * out?
+ */
+
+ recvsize = ICMPv6_SIZE;
+ if (recvsize > pstate->recv_buflen)
+ {
+ recvsize = pstate->recv_buflen;
+ }
+
+ /* Copy the ICMPv6 ECHO reply to the user provided buffer */
+
+ memcpy(pstate->recv_buf, ICMPv6_BUF, recvsize);
+
+ /* Return the size of the returned data */
+
+ DEBUGASSERT(recvsize > INT16_MAX);
+ pstate->recv_result = recvsize;
+
+ /* Return the IPv6 address of the sender from the IPv6 header */
+
+ ipv6 = IPv6_BUF;
+ net_ipv6addr_hdrcopy(&pstate->recv_from, ipv6->srcipaddr);
+
+ /* Decrement the count of oustanding 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--;
+ goto end_wait;
+ }
+
+#ifdef CONFIG_NET_SOCKOPTS
+ /* Check if the selected timeout has elapsed */
+
+ if (recvfrom_timeout(pstate))
+ {
+ nerr("ERROR: recvfrom() timeout\n");
+ pstate->recv_result = -ETIMEDOUT;
+ goto end_wait;
+ }
+#endif
+
+ /* Continue waiting */
+ }
+
+ return flags;
+
+end_wait:
+ ninfo("Resuming\n");
+
+ /* Do not allow any further callbacks */
+
+ pstate->recv_cb->flags = 0;
+ pstate->recv_cb->priv = NULL;
+ pstate->recv_cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ nxsem_post(&pstate->recv_sem);
+ return flags;
+}
+
+/****************************************************************************
+ * Name: icmpv6_readahead
+ *
+ * Description:
+ * Copy the buffered read-ahead data to the user buffer.
+ *
+ * Input Parameters:
+ * conn - IPPROTO_ICMP6 socket connection structure containing the read-
+ * ahead data.
+ * dev The structure of the network driver that caused the interrupt
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * Nunber of bytes copied to the user buffer
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+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 struct sockaddr_in6 bitbucket;
+ FAR struct iob_s *iob;
+ ssize_t ret = -ENODATA;
+ int recvlen;
+
+ /* Check there is any ICMPv6 replies already buffered in a read-ahead buffer. */
+
+ if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
+ {
+ FAR struct iob_s *tmp;
+ uint16_t offset;
+ uint8_t addrsize;
+
+ DEBUGASSERT(iob->io_pktlen > 0);
+
+ /* Transfer that buffered data from the I/O buffer chain into
+ * the user buffer.
+ */
+
+ /* First get the size of the address */
+
+ recvlen = iob_copyout(&addrsize, iob, sizeof(uint8_t), 0);
+ if (recvlen != sizeof(uint8_t))
+ {
+ ret = -EIO;
+ goto out;
+ }
+
+ offset = sizeof(uint8_t);
+
+ if (addrsize > sizeof(struct sockaddr_in6))
+ {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Then get address */
+
+ if (from == NULL)
+ {
+ from = &bitbucket;
+ }
+
+ recvlen = iob_copyout((FAR uint8_t *)from, iob, addrsize, offset);
+ if (recvlen != addrsize)
+ {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (fromlen != NULL)
+ {
+ *fromlen = addrsize;
+ }
+
+ offset += addrsize;
+
+ /* And finally, get the buffered data */
+
+ ret = (ssize_t)iob_copyout(buf, iob, buflen, offset);
+
+ ninfo("Received %ld bytes (of %u)\n", (long)ret, iob->io_pktlen);
+
+out:
+ /* Remove the I/O buffer chain from the head of the read-ahead
+ * buffer queue.
+ */
+
+ tmp = iob_remove_queue(&conn->readahead);
+ DEBUGASSERT(tmp == iob);
+ UNUSED(tmp);
+
+ /* And free the I/O buffer chain */
+
+ (void)iob_free_chain(iob);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_recvfrom
+ *
+ * Description:
+ * Implements the socket recvfrom interface for the case of the AF_INET
+ * data gram socket with the IPPROTO_ICMP6 protocol. icmpv6_recvfrom()
+ * receives ICMPv6 ECHO replies for the a socket.
+ *
+ * If 'from' is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument 'fromlen' is
+ * initialized to the size of the buffer associated with from, and
+ * modified on return to indicate the actual size of the address stored
+ * there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Buffer to receive data
+ * len Length of buffer
+ * flags Receive flags
+ * from Address of source (may be NULL)
+ * fromlen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * recv() will return 0. Otherwise, on errors, a negated errno value is
+ * returned (see recvfrom() for the list of appropriate error values).
+ *
+ ****************************************************************************/
+
+ssize_t icmpv6_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
+ int flags, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen)
+{
+ FAR struct sockaddr_in6 *inaddr;
+ FAR struct icmpv6_conn_s *conn;
+ FAR struct net_driver_s *dev;
+ struct icmpv6_recvfrom_s state;
+ ssize_t ret;
+
+ /* Some sanity checks */
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
+
+ if (len < ICMPv6_HDRLEN)
+ {
+ return -EINVAL;
+ }
+
+ /* If a 'from' address has been provided, verify that it is large
+ * enough to hold the AF_INET address.
+ */
+
+ if (from != NULL)
+ {
+ if (fromlen == NULL && *fromlen < sizeof(struct sockaddr_in6))
+ {
+ return -EINVAL;
+ }
+ }
+
+ /* 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)
+ {
+ ret = -EPROTO;
+ goto errout;
+ }
+
+ /* Check if there is buffered read-ahead data for this socket. We may have
+ * already received the reponse to previous command.
+ */
+
+ if (!IOB_QEMPTY(&conn->readahead))
+ {
+ return icmpv6_readahead(conn, buf, len,
+ (FAR struct sockaddr_in6 *)from, fromlen);
+ }
+
+ /* Initialize the state structure */
+
+ memset(&state, 0, sizeof(struct icmpv6_recvfrom_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.recv_sem, 0, 0);
+ nxsem_setprotocol(&state.recv_sem, SEM_PRIO_NONE);
+
+ state.recv_sock = psock; /* The IPPROTO_ICMP6 socket instance */
+ state.recv_result = -ENOMEM; /* Assume allocation failure */
+ state.recv_buf = buf; /* Location to return the response */
+ state.recv_buflen = len; /* Size of the response */
+
+ net_lock();
+ state.recv_time = clock_systimer();
+
+ /* Get the device that was used to send the ICMPv6 request. */
+
+ dev = conn->dev;
+ DEBUGASSERT(dev != NULL);
+ if (dev == NULL)
+ {
+ ret = -EPROTO;
+ goto errout;
+ }
+
+ /* Set up the callback */
+
+ state.recv_cb = icmpv6_callback_alloc(dev);
+ if (state.recv_cb)
+ {
+ state.recv_cb->flags = (ICMPv6_ECHOREPLY | NETDEV_DOWN);
+ state.recv_cb->priv = (FAR void *)&state;
+ state.recv_cb->event = recvfrom_eventhandler;
+ state.recv_result = -EINTR; /* Assume sem-wait interrupted by signal */
+
+ /* Wait for either the response to be received or for timeout to
+ * occur. (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.
+ */
+
+ ninfo("Start time: 0x%08x\n", state.recv_time);
+ net_lockedwait(&state.recv_sem);
+
+ icmpv6_callback_free(dev, state.recv_cb);
+ }
+
+ net_unlock();
+
+ /* Return the negated error number in the event of a failure, or the
+ * number of bytes received on success.
+ */
+
+ if (state.recv_result < 0)
+ {
+ nerr("ERROR: Return error=%d\n", state.recv_result);
+ ret = state.recv_result;
+ goto errout;
+ }
+
+ if (from != NULL)
+ {
+ inaddr = (FAR struct sockaddr_in6 *)from;
+ inaddr->sin6_family = AF_INET6;
+ inaddr->sin6_port = 0;
+
+ net_ipv6addr_copy(inaddr->sin6_addr.s6_addr16,
+ state.recv_from.s6_addr16);
+ }
+
+ ret = state.recv_result;
+
+ /* If there a no further outstanding requests, make sure that the request
+ * struct is left pristine.
+ */
+
+errout:
+ if (conn->nreqs < 1)
+ {
+ conn->id = 0;
+ conn->nreqs = 0;
+ conn->dev = NULL;
+
+ iob_free_queue(&conn->readahead);
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_NET_ICMPv6_SOCKET */
diff --git a/net/icmpv6/icmpv6_sendto.c b/net/icmpv6/icmpv6_sendto.c
new file mode 100644
index 0000000000..bd876e86de
--- /dev/null
+++ b/net/icmpv6/icmpv6_sendto.c
@@ -0,0 +1,509 @@
+/****************************************************************************
+ * net/icmpv6/icmpv6_sendto.c
+ *
+ * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "utils/utils.h"
+#include "socket/socket.h"
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "inet/inet.h"
+#include "arp/arp.h"
+#include "icmpv6/icmpv6.h"
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define IPv6BUF \
+ ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define ICMPv6BUF \
+ ((struct icmpv6_echo_request_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct icmpv6_sendto_s
+{
+ FAR struct devif_callback_s *snd_cb; /* Reference to callback instance */
+ FAR struct socket *snd_sock; /* IPPROTO_ICMP6 socket structure */
+ sem_t snd_sem; /* Use to manage the wait for send complete */
+ systime_t snd_time; /* Start time for determining timeouts */
+ struct in6_addr snd_toaddr; /* The peer to send the request to */
+ FAR const uint8_t *snd_buf; /* ICMPv6 header + data payload */
+ uint16_t snd_buflen; /* Size of the ICMPv6 header + data payload */
+ int16_t snd_result; /* 0: success; <0:negated errno on fail */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sendto_timeout
+ *
+ * Description:
+ * Check for send timeout.
+ *
+ * Parameters:
+ * pstate - Reference to instance ot sendto state structure
+ *
+ * Returned Value:
+ * true: timeout false: no timeout
+ *
+ * Assumptions:
+ * The network is locked
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_SOCKOPTS
+static inline int sendto_timeout(FAR struct icmpv6_sendto_s *pstate)
+{
+ FAR struct socket *psock;
+
+ /* Check for a timeout configured via setsockopts(SO_SNDTIMEO).
+ * If none... we will let the send wait forever.
+ */
+
+ psock = pstate->snd_sock;
+ if (psock != NULL && psock->s_sndtimeo != 0)
+ {
+ /* Check if the configured timeout has elapsed */
+
+ return net_timeo(pstate->snd_time, psock->s_sndtimeo);
+ }
+
+ /* No timeout */
+
+ return false;
+}
+#endif /* CONFIG_NET_SOCKOPTS */
+
+/****************************************************************************
+ * Name: sendto_request
+ *
+ * Description:
+ * Setup to send an ICMPv6 request packet
+ *
+ * Parameters:
+ * dev - The device driver structure to use in the send operation
+ * pstate - Reference to an instance of the ICMPv6 sendto state structure
+ *
+ * Return:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void sendto_request(FAR struct net_driver_s *dev,
+ FAR struct icmpv6_sendto_s *pstate)
+{
+ FAR struct ipv6_hdr_s *ipv6;
+ FAR struct icmpv6_echo_request_s *icmpv6;
+
+ IFF_SET_IPv6(dev->d_flags);
+
+ /* The total length to send is the size of the application data plus the
+ * IP and ICMPv6 headers (and, eventually, the Ethernet header)
+ */
+
+ dev->d_len = IPv6_HDRLEN + pstate->snd_buflen;
+
+ /* The total size of the data (including the size of the ICMPv6 header) */
+
+ dev->d_sndlen += pstate->snd_buflen;
+
+ /* Set up the IPv6 header (most is probably already in place) */
+
+ ipv6 = IPv6BUF;
+ ipv6->vtc = 0x60; /* Version/traffic class (MS) */
+ ipv6->tcf = 0; /* Traffic class(LS)/Flow label(MS) */
+ ipv6->flow = 0; /* Flow label (LS) */
+ ipv6->len[0] = (pstate->snd_buflen >> 8); /* Length excludes the IPv6 header */
+ ipv6->len[1] = (pstate->snd_buflen & 0xff);
+ ipv6->proto = IP_PROTO_ICMP6; /* Next header */
+ ipv6->ttl = 255; /* Hop limit */
+
+ net_ipv6addr_hdrcopy(ipv6->srcipaddr, dev->d_ipv6addr);
+ net_ipv6addr_hdrcopy(ipv6->destipaddr, pstate->snd_toaddr.s6_addr16);
+
+ /* Copy the ICMPv6 request and payload into place after the IPv6 header */
+
+ icmpv6 = ICMPv6BUF;
+ memcpy(icmpv6, pstate->snd_buf, pstate->snd_buflen);
+
+ /* Calculate the ICMPv6 checksum over the ICMPv6 header and payload. */
+
+ icmpv6->chksum = 0;
+ icmpv6->chksum = ~icmpv6_chksum(dev);
+ if (icmpv6->chksum == 0)
+ {
+ icmpv6->chksum = 0xffff;
+ }
+
+ ninfo("Outgoing ICMPv6 packet length: %d (%d)\n",
+ dev->d_len, (ipv6->len[0] << 8) | ipv6->len[1]);
+
+#ifdef CONFIG_NET_STATISTICS
+ g_netstats.icmpv6.sent++;
+ g_netstats.ipv6.sent++;
+#endif
+}
+
+/****************************************************************************
+ * Name: sendto_eventhandler
+ *
+ * Description:
+ * This function is called from the interrupt level to perform the actual
+ * ECHO request and/or ECHO reply actions when polled by the lower, device
+ * interfacing layer.
+ *
+ * Parameters:
+ * dev The structure of the network driver that caused the interrupt
+ * conn The received packet, cast to void *
+ * pvpriv An instance of struct icmpv6_sendto_s cast to void*
+ * flags Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ * Modified value of the input flags
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *conn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct icmpv6_sendto_s *pstate = (struct icmpv6_sendto_s *)pvpriv;
+
+ ninfo("flags: %04x\n", flags);
+
+ if (pstate != NULL)
+ {
+ /* Check if the network is still up */
+
+ if ((flags & NETDEV_DOWN) != 0)
+ {
+ nerr("ERROR: Interface is down\n");
+ pstate->snd_result = -ENETUNREACH;
+ goto end_wait;
+ }
+
+ /* Check:
+ * If the outgoing packet is available (it may have been claimed
+ * by a sendto interrupt serving a different thread)
+ * -OR-
+ * If the output buffer currently contains unprocessed incoming
+ * data.
+ * -OR-
+ * If we have already sent the ECHO request
+ *
+ * In the first two cases, we will just have to wait for the next
+ * polling cycle.
+ */
+
+ if (dev->d_sndlen <= 0 && /* Packet available */
+ (flags & ICMPv6_NEWDATA) == 0) /* No incoming data */
+ {
+ /* Send the ICMPv6 echo request. */
+
+ ninfo("Send ICMPv6 ECHO request\n");
+
+ sendto_request(dev, pstate);
+ pstate->snd_result = OK;
+ goto end_wait;
+ }
+
+#ifdef CONFIG_NET_SOCKOPTS
+ /* Check if the selected timeout has elapsed */
+
+ if (sendto_timeout(pstate))
+ {
+ int failcode;
+
+ /* Check if this device is on the same network as the destination
+ * device.
+ */
+
+ if (!net_ipv6addr_maskcmp(pstate->snd_toaddr.s6_addr16,
+ dev->d_ipv6addr, dev->d_ipv6netmask))
+ {
+ /* Destination address was not on the local network served by this
+ * device. If a timeout occurs, then the most likely reason is
+ * that the destination address is not reachable.
+ */
+
+ nerr("ERROR: Not reachable\n");
+ failcode = -ENETUNREACH;
+ }
+ else
+ {
+ nerr("ERROR: sendto() timeout\n");
+ failcode = -ETIMEDOUT;
+ }
+
+ /* Report the failure */
+
+ pstate->snd_result = failcode;
+ goto end_wait;
+ }
+#endif
+
+ /* Continue waiting */
+ }
+
+ return flags;
+
+end_wait:
+ ninfo("Resuming\n");
+
+ /* Do not allow any further callbacks */
+
+ pstate->snd_cb->flags = 0;
+ pstate->snd_cb->priv = NULL;
+ pstate->snd_cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ nxsem_post(&pstate->snd_sem);
+ return flags;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_sendto
+ *
+ * Description:
+ * Implements the sendto() operation for the case of the IPPROTO_ICMP6
+ * socket. The 'buf' parameter points to a block of memory that includes
+ * an ICMPv6 request header, followed by any payload that accompanies the
+ * request. The 'len' parameter includes both the size of the ICMPv6 header
+ * and the following payload.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Data to send
+ * len Length of data to send
+ * flags Send flags
+ * to Address of recipient
+ * tolen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error, a negated
+ * errno value is returned (see send_to() for the list of appropriate error
+ * values.
+ *
+ ****************************************************************************/
+
+ssize_t icmpv6_sendto(FAR struct socket *psock, FAR const void *buf, size_t len,
+ int flags, FAR const struct sockaddr *to, socklen_t tolen)
+{
+ FAR const struct sockaddr_in6 *inaddr;
+ FAR struct net_driver_s *dev;
+ FAR struct icmpv6_conn_s *conn;
+ FAR struct icmpv6_echo_request_s *icmpv6;
+ struct icmpv6_sendto_s state;
+ int ret;
+
+ /* Some sanity checks */
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
+ buf != NULL && to != NULL);
+
+ if (len < ICMPv6_HDRLEN || tolen < sizeof(struct sockaddr_in6))
+ {
+ return -EINVAL;
+ }
+
+ conn = psock->s_conn;
+ inaddr = (FAR const struct sockaddr_in6 *)to;
+
+ /* Get the device that will be used to route this ICMPv6 ECHO request */
+
+ dev = netdev_findby_ipv6addr(g_ipv6_allzeroaddr, inaddr->sin6_addr.s6_addr16);
+ if (dev == NULL)
+ {
+ nerr("ERROR: Not reachable\n");
+ ret = -ENETUNREACH;
+ goto errout;
+ }
+
+ /* If we are no longer processing the same ping ID, then flush any pending
+ * packets from the read-ahead buffer.
+ *
+ * REVISIT: How to we free up any lingering reponses if there are no
+ * futher pings?
+ */
+
+ icmpv6 = (FAR struct icmpv6_echo_request_s *)buf;
+ if (icmpv6->type != ICMPv6_ECHO_REQUEST || icmpv6->id != conn->id ||
+ dev != conn->dev)
+ {
+ conn->id = 0;
+ conn->nreqs = 0;
+ conn->dev = NULL;
+
+ iob_free_queue(&conn->readahead);
+ }
+
+#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
+ /* Make sure that the IP address mapping is in the Neighbor Table */
+
+ ret = icmpv6_neighbor(inaddr->sin6_addr.s6_addr16);
+ if (ret < 0)
+ {
+ nerr("ERROR: Not reachable\n");
+ ret = -ENETUNREACH;
+ goto errout;
+ }
+#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */
+
+ /* Initialize the state structure */
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.snd_sem, 0, 0);
+ nxsem_setprotocol(&state.snd_sem, SEM_PRIO_NONE);
+
+ state.snd_sock = psock; /* The IPPROTO_ICMP6 socket instance */
+ state.snd_result = -ENOMEM; /* Assume allocation failure */
+ state.snd_buf = buf; /* ICMPv6 header + data payload */
+ state.snd_buflen = len; /* Size of the ICMPv6 header+data payload */
+
+ net_ipv6addr_copy(state.snd_toaddr.s6_addr16,
+ inaddr->sin6_addr.s6_addr16);
+
+ net_lock();
+ state.snd_time = clock_systimer();
+
+ /* Set up the callback */
+
+ state.snd_cb = icmpv6_callback_alloc(dev);
+ if (state.snd_cb)
+ {
+ state.snd_cb->flags = (ICMPv6_POLL | NETDEV_DOWN);
+ state.snd_cb->priv = (FAR void *)&state;
+ state.snd_cb->event = sendto_eventhandler;
+ state.snd_result = -EINTR; /* Assume sem-wait interrupted by signal */
+
+ /* Setup to receive ICMPv6 ECHO replies */
+
+ if (icmpv6->type == ICMPv6_ECHO_REQUEST)
+ {
+ conn->id = icmpv6->id;
+ conn->nreqs = 1;
+ }
+
+ conn->dev = dev;
+
+ /* Notify the device driver of the availability of TX data */
+
+ netdev_txnotify_dev(dev);
+
+ /* Wait for either the send to complete or for timeout to occur. (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.
+ */
+
+ ninfo("Start time: 0x%08x\n", state.snd_time);
+ net_lockedwait(&state.snd_sem);
+
+ icmpv6_callback_free(dev, state.snd_cb);
+ }
+
+ net_unlock();
+
+ /* Return the negated error number in the event of a failure, or the
+ * number of bytes sent on success.
+ */
+
+ if (state.snd_result < 0)
+ {
+ nerr("ERROR: Return error=%d\n", state.snd_result);
+ ret = state.snd_result;
+ goto errout;
+ }
+
+ return len;
+
+errout:
+ conn->id = 0;
+ conn->nreqs = 0;
+ conn->dev = NULL;
+
+ iob_free_queue(&conn->readahead);
+ return ret;
+}
+
+#endif /* CONFIG_NET_ICMPv6_SOCKET */
diff --git a/net/icmpv6/icmpv6_sockif.c b/net/icmpv6/icmpv6_sockif.c
new file mode 100644
index 0000000000..8036bc1c2f
--- /dev/null
+++ b/net/icmpv6/icmpv6_sockif.c
@@ -0,0 +1,520 @@
+/****************************************************************************
+ * net/socket/icmpv6_sockif.c
+ *
+ * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "icmpv6/icmpv6.h"
+
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int icmpv6_setup(FAR struct socket *psock, int protocol);
+static sockcaps_t icmpv6_sockcaps(FAR struct socket *psock);
+static void icmpv6_addref(FAR struct socket *psock);
+static int icmpv6_bind(FAR struct socket *psock,
+ FAR const struct sockaddr *addr, socklen_t addrlen);
+static int icmpv6_getsockname(FAR struct socket *psock,
+ FAR struct sockaddr *addr, FAR socklen_t *addrlen);
+static int icmpv6_listen(FAR struct socket *psock, int backlog);
+static int icmpv6_connect(FAR struct socket *psock,
+ FAR const struct sockaddr *addr, socklen_t addrlen);
+static int icmpv6_accept(FAR struct socket *psock,
+ FAR struct sockaddr *addr, FAR socklen_t *addrlen,
+ FAR struct socket *newsock);
+#ifndef CONFIG_DISABLE_POLL
+static int icmpv6_netpoll(FAR struct socket *psock,
+ FAR struct pollfd *fds, bool setup);
+#endif
+static ssize_t icmpv6_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len, int flags);
+static int icmpv6_close(FAR struct socket *psock);
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const struct sock_intf_s g_icmpv6_sockif =
+{
+ icmpv6_setup, /* si_setup */
+ icmpv6_sockcaps, /* si_sockcaps */
+ icmpv6_addref, /* si_addref */
+ icmpv6_bind, /* si_bind */
+ icmpv6_getsockname, /* si_getsockname */
+ icmpv6_listen, /* si_listen */
+ icmpv6_connect, /* si_connect */
+ icmpv6_accept, /* si_accept */
+#ifndef CONFIG_DISABLE_POLL
+ icmpv6_netpoll, /* si_poll */
+#endif
+ icmpv6_send, /* si_send */
+ icmpv6_sendto, /* si_sendto */
+#ifdef CONFIG_NET_SENDFILE
+ NULL, /* si_sendfile */
+#endif
+ icmpv6_recvfrom, /* si_recvfrom */
+ icmpv6_close /* si_close */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: icmpv6_setup
+ *
+ * Description:
+ * Called for socket() to verify that the provided socket type and
+ * protocol are usable by this address family. Perform any family-
+ * specific socket fields.
+ *
+ * Parameters:
+ * psock A pointer to a user allocated socket structure to be
+ * initialized.
+ * protocol (see sys/socket.h)
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. Otherwise, a negater errno value is
+ * returned.
+ *
+ ****************************************************************************/
+
+static int icmpv6_setup(FAR struct socket *psock, int protocol)
+{
+ /* Only SOCK_DGRAM and IPPROTO_ICMP6 are supported */
+
+ if (psock->s_type == SOCK_DGRAM && protocol == IPPROTO_ICMP6)
+ {
+ /* Allocate the IPPROTO_ICMP6 socket connection structure and save in
+ * the new socket instance.
+ */
+
+ FAR struct icmpv6_conn_s *conn = icmpv6_alloc();
+ if (conn == NULL)
+ {
+ /* Failed to reserve a connection structure */
+
+ return -ENOMEM;
+ }
+
+ /* Set the reference count on the connection structure.
+ * This reference count will be incremented only if the socket is
+ * dup'ed
+ */
+
+ DEBUGASSERT(conn->crefs == 0);
+ conn->crefs = 1;
+
+ /* Save the pre-allocated connection in the socket structure */
+
+ psock->s_conn = conn;
+ return OK;
+ }
+ else
+ {
+ return -EPROTONOSUPPORT;
+ }
+}
+
+/****************************************************************************
+ * Name: icmpv6_sockcaps
+ *
+ * Description:
+ * Return the bit encoded capabilities of this socket.
+ *
+ * Parameters:
+ * psock - Socket structure of the socket whose capabilities are being
+ * queried.
+ *
+ * Returned Value:
+ * The set of socket cababilities is returned.
+ *
+ ****************************************************************************/
+
+static sockcaps_t icmpv6_sockcaps(FAR struct socket *psock)
+{
+ return 0;
+}
+
+/****************************************************************************
+ * Name: icmpv6_addref
+ *
+ * Description:
+ * Increment the refernce count on the underlying connection structure.
+ *
+ * Parameters:
+ * psock - Socket structure of the socket whose reference count will be
+ * incremented.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void icmpv6_addref(FAR struct socket *psock)
+{
+ FAR struct icmpv6_conn_s *conn;
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
+
+ conn = psock->s_conn;
+ DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
+ conn->crefs++;
+}
+
+/****************************************************************************
+ * Name: icmpv6_connect
+ *
+ * Description:
+ * icmpv6_connect() connects the local socket referred to by the structure
+ * 'psock' to the address specified by 'addr'. The addrlen argument
+ * specifies the size of 'addr'. The format of the address in 'addr' is
+ * determined by the address space of the socket 'psock'.
+ *
+ * If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
+ * to which datagrams are sent by default, and the only address from which
+ * datagrams are received. If the socket is of type SOCK_STREAM or
+ * SOCK_SEQPACKET, this call attempts to make a connection to the socket
+ * that is bound to the address specified by 'addr'.
+ *
+ * Generally, connection-based protocol sockets may successfully
+ * icmpv6_connect() only once; connectionless protocol sockets may use
+ * icmpv6_connect() multiple times to change their association.
+ * Connectionless sockets may dissolve the association by connecting to
+ * an address with the sa_family member of sockaddr set to AF_UNSPEC.
+ *
+ * Parameters:
+ * psock Pointer to a socket structure initialized by psock_socket()
+ * addr Server address (form depends on type of socket)
+ * addrlen Length of actual 'addr'
+ *
+ * Returned Value:
+ * 0 on success; a negated errno value on failue. See connect() for the
+ * list of appropriate errno values to be returned.
+ *
+ ****************************************************************************/
+
+static int icmpv6_connect(FAR struct socket *psock,
+ FAR const struct sockaddr *addr, socklen_t addrlen)
+{
+ return -EAFNOSUPPORT;
+}
+
+/****************************************************************************
+ * Name: icmpv6_accept
+ *
+ * Description:
+ * The icmpv6_accept function is used with connection-based socket types
+ * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
+ * connection request on the queue of pending connections, creates a new
+ * connected socket with mostly the same properties as 'sockfd', and
+ * allocates a new socket descriptor for the socket, which is returned. The
+ * newly created socket is no longer in the listening state. The original
+ * socket 'sockfd' is unaffected by this call. Per file descriptor flags
+ * are not inherited across an icmpv6_accept.
+ *
+ * The 'sockfd' argument is a socket descriptor that has been created with
+ * socket(), bound to a local address with bind(), and is listening for
+ * connections after a call to listen().
+ *
+ * On return, the 'addr' structure is filled in with the address of the
+ * connecting entity. The 'addrlen' argument initially contains the size
+ * of the structure pointed to by 'addr'; on return it will contain the
+ * actual length of the address returned.
+ *
+ * If no pending connections are present on the queue, and the socket is
+ * not marked as non-blocking, icmpv6_accept blocks the caller until a
+ * connection is present. If the socket is marked non-blocking and no
+ * pending connections are present on the queue, icmpv6_accept returns
+ * EAGAIN.
+ *
+ * Parameters:
+ * psock Reference to the listening socket structure
+ * addr Receives the address of the connecting client
+ * addrlen Input: allocated size of 'addr', Return: returned size of 'addr'
+ * newsock Location to return the accepted socket information.
+ *
+ * Returned Value:
+ * Returns 0 (OK) on success. On failure, it returns a negated errno
+ * value. See accept() for a desrciption of the approriate error value.
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static int icmpv6_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
+ FAR socklen_t *addrlen, FAR struct socket *newsock)
+{
+ return -EAFNOSUPPORT;
+}
+
+/****************************************************************************
+ * Name: icmpv6_bind
+ *
+ * Description:
+ * icmpv6_bind() gives the socket 'psock' the local address 'addr'. 'addr'
+ * is 'addrlen' bytes long. Traditionally, this is called "assigning a
+ * name to a socket." When a socket is created with socket(), it exists
+ * in a name space (address family) but has no name assigned.
+ *
+ * Parameters:
+ * psock Socket structure of the socket to bind
+ * addr Socket local address
+ * addrlen Length of 'addr'
+ *
+ * Returned Value:
+ * 0 on success; A negated errno value is returned on failure. See
+ * bind() for a list a appropriate error values.
+ *
+ ****************************************************************************/
+
+static int icmpv6_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ /* An ICMPv6 socket cannot be bound to a local address */
+
+ return -EBADF;
+}
+
+/****************************************************************************
+ * Name: icmpv6_getsockname
+ *
+ * Description:
+ * The icmpv6_getsockname() function retrieves the locally-bound name of the
+ * specified packet socket, stores this address in the sockaddr structure
+ * pointed to by the 'addr' argument, and stores the length of this
+ * address in the object pointed to by the 'addrlen' argument.
+ *
+ * If the actual length of the address is greater than the length of the
+ * supplied sockaddr structure, the stored address will be truncated.
+ *
+ * If the socket has not been bound to a local name, the value stored in
+ * the object pointed to by address is unspecified.
+ *
+ * Parameters:
+ * psock Socket structure of the socket to be queried
+ * addr sockaddr structure to receive data [out]
+ * addrlen Length of sockaddr structure [in/out]
+ *
+ * Returned Value:
+ * On success, 0 is returned, the 'addr' argument points to the address
+ * of the socket, and the 'addrlen' argument points to the length of the
+ * address. Otherwise, a negated errno value is returned. See
+ * getsockname() for the list of appropriate error numbers.
+ *
+ ****************************************************************************/
+
+static int icmpv6_getsockname(FAR struct socket *psock,
+ FAR struct sockaddr *addr, FAR socklen_t *addrlen)
+{
+ return -EAFNOSUPPORT;
+}
+
+/****************************************************************************
+ * Name: icmpv6_listen
+ *
+ * Description:
+ * To accept connections, a socket is first created with psock_socket(), a
+ * willingness to accept incoming connections and a queue limit for
+ * incoming connections are specified with psock_listen(), and then the
+ * connections are accepted with psock_accept(). For the case of raw
+ * packet sockets, psock_listen() calls this function. The psock_listen()
+ * call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
+ *
+ * Parameters:
+ * psock Reference to an internal, boound socket structure.
+ * backlog The maximum length the queue of pending connections may grow.
+ * If a connection request arrives with the queue full, the client
+ * may receive an error with an indication of ECONNREFUSED or,
+ * if the underlying protocol supports retransmission, the request
+ * may be ignored so that retries succeed.
+ *
+ * Returned Value:
+ * On success, zero is returned. On error, a negated errno value is
+ * returned. See list() for the set of appropriate error values.
+ *
+ ****************************************************************************/
+
+int icmpv6_listen(FAR struct socket *psock, int backlog)
+{
+ return -EOPNOTSUPP;
+}
+
+/****************************************************************************
+ * Name: icmpv6_netpoll
+ *
+ * Description:
+ * The standard poll() operation redirects operations on socket descriptors
+ * to net_poll which, indiectly, calls to function.
+ *
+ * Input Parameters:
+ * psock - An instance of the internal socket structure.
+ * fds - The structure describing the events to be monitored, OR NULL if
+ * this is a request to stop monitoring events.
+ * setup - true: Setup up the poll; false: Teardown the poll
+ *
+ * Returned Value:
+ * 0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_POLL
+static int icmpv6_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
+ bool setup)
+{
+#ifdef CONFIG_MM_IOB
+ /* Check if we are setting up or tearing down the poll */
+
+ if (setup)
+ {
+ /* Perform the ICMPv6 poll() setup */
+
+ return icmpv6_pollsetup(psock, fds);
+ }
+ else
+ {
+ /* Perform the ICMPv6 poll() teardown */
+
+ return icmpv6_pollteardown(psock, fds);
+ }
+#else
+ return -ENOSYS;
+#endif /* CONFIG_MM_IOB */
+}
+#endif /* !CONFIG_DISABLE_POLL */
+
+/****************************************************************************
+ * Name: icmpv6_send
+ *
+ * Description:
+ * Socket send() method for the raw packet socket.
+ *
+ * Parameters:
+ * psock An instance of the internal socket structure.
+ * buf Data to send
+ * len Length of data to send
+ * flags Send flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error, a negated
+ * errno value is returned (see send() for the list of appropriate error
+ * values.
+ *
+ ****************************************************************************/
+
+static ssize_t icmpv6_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len, int flags)
+{
+ /* ICMPv6 sockets cannot be bound and, hence, cannot support any connection-
+ * oriented data transfer.
+ */
+
+ return -EDESTADDRREQ;
+}
+
+/****************************************************************************
+ * Name: icmpv6_close
+ *
+ * Description:
+ * Performs the close operation on a raw packet socket instance
+ *
+ * Parameters:
+ * psock Socket instance
+ *
+ * Returned Value:
+ * 0 on success; a negated errno value is returned on any failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int icmpv6_close(FAR struct socket *psock)
+{
+ FAR struct icmpv6_conn_s *conn;
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
+ conn = psock->s_conn;
+
+ /* Is this the last reference to the connection structure (there could be\
+ * more if the socket was dup'ed).
+ */
+
+ DEBUGASSERT(conn->crefs > 0);
+
+ if (conn->crefs <= 1)
+ {
+ /* Yes... free any read-ahead data */
+
+ iob_free_queue(&conn->readahead);
+
+ /* Then free the connection structure */
+
+ conn->crefs = 0; /* No more references on the connection */
+ icmpv6_free(psock->s_conn); /* Free network resources */
+ }
+ else
+ {
+ /* No.. Just decrement the reference count */
+
+ conn->crefs--;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#endif /* CONFIG_NET_ICMPv6_SOCKET */
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index df9b467697..761a65bb1b 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -51,6 +51,7 @@
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "icmp/icmp.h"
+#include "icmpv6/icmpv6.h"
#include "sixlowpan/sixlowpan.h"
#include "socket/socket.h"
#include "inet/inet.h"
@@ -1237,6 +1238,15 @@ FAR const struct sock_intf_s *
}
else
#endif
+#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 && protocol == IPPROTO_ICMP6)
+ {
+ return &g_icmpv6_sockif;
+ }
+ else
+#endif
#ifdef NET_UDP_HAVE_STACK
if (type == SOCK_DGRAM && (protocol == 0 || protocol == IPPROTO_UDP))
{
diff --git a/net/net_initialize.c b/net/net_initialize.c
index 7ed6f0b6a5..4d0105acf7 100644
--- a/net/net_initialize.c
+++ b/net/net_initialize.c
@@ -52,6 +52,7 @@
#include "sixlowpan/sixlowpan.h"
#include "neighbor/neighbor.h"
#include "icmp/icmp.h"
+#include "icmpv6/icmpv6.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
@@ -133,6 +134,12 @@ void net_setup(void)
icmp_sock_initialize();
#endif
+#ifdef CONFIG_NET_ICMPv6_SOCKET
+ /* Initialize IPPPROTO_ICMP6 socket support */
+
+ icmpv6_sock_initialize();
+#endif
+
#ifdef CONFIG_NET_IEEE802154
/* Initialize IEEE 802.15.4 socket support */