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
This commit is contained in:
Gregory Nutt 2017-10-24 11:23:08 -06:00
parent bad3379bc4
commit 70c59a9d91
32 changed files with 2775 additions and 704 deletions

View File

@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttShell (NSH)</i></font></big></h1>
<p>Last Updated: October 23, 2017</p>
<p>Last Updated: October 24, 2017</p>
</td>
</tr>
</table>
@ -353,157 +353,151 @@
<tr>
<td><br></td>
<td>
<a href="#cmdping6">2.45 Check Network Peer (ping6)</a>
<a href="#cmdpoweroff">2.45 Shut the system down (poweroff)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdpoweroff">2.46 Shut the system down (poweroff)</a>
<a href="#cmdput">2.46 Send File Via TFTP (put)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdput">2.47 Send File Via TFTP (put)</a>
<a href="#cmdpwd">2.47 Show Current Working Directory (pwd)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdpwd">2.48 Show Current Working Directory (pwd)</a>
<a href="#cmdreadlink">2.48 Show target of a link (readlink)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdreadlink">2.49 Show target of a link (readlink)</a>
<a href="#cmdreboot">2.49 Reset and reboot the system (reboot)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdreboot">2.50 Reset and reboot the system (reboot)</a>
<a href="#cmdrm">2.50 Remove a File (rm)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdrm">2.51 Remove a File (rm)</a>
<a href="#cmdrmdir">2.51 Remove a Directory (rmdir)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdrmdir">2.52 Remove a Directory (rmdir)</a>
<a href="#cmdrmmod">2.52 Remove on OS Module (rmmod)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdrmmod">2.53 Remove on OS Module (rmmod)</a>
<a href="#cmdroute">2.53 Show routing table (route)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdroute">2.54 Show routing table (route)</a>
<a href="#cmdset">2.54 Set an Environment Variable (set)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdset">2.55 Set an Environment Variable (set)</a>
<a href="#cmdsh">2.55 Execute an NSH Script (sh)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdsh">2.56 Execute an NSH Script (sh)</a>
<a href="#cmdshutdown">2.56 Shut the system down (shutdown)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdshutdown">2.57 Shut the system down (shutdown)</a>
<a href="#cmdsleep">2.57 Wait for Seconds (sleep)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdsleep">2.58 Wait for Seconds (sleep)</a>
<a href="#cmdtelnetd">2.58 Start the Telnet Daemon (telnetd)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdtelnetd">2.59 Start the Telnet Daemon (telnetd)</a>
<a href="#cmdtime">2.59 Time execution of another command (time)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdtime">2.60 Time execution of another command (time)</a>
<a href="#cmdunmount">2.60 Unmount a File System (umount)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdunmount">2.61 Unmount a File System (umount)</a>
<a href="#cmduname">2.61 Print system information (uname)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmduname">2.62 Print system information (uname)</a>
<a href="#cmdunset">2.62 Unset an Environment Variable (unset)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdunset">2.63 Unset an Environment Variable (unset)</a>
<a href="#cmdurldec">2.63 URL Decode (urldecode)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdurldec">2.64 URL Decode (urldecode)</a>
<a href="#cmdurlencode">2.64 URL Encode (urlencode)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdurlencode">2.65 URL Encode (urlencode)</a>
<a href="#cmduseradd">2.65 Add a New User (useradd)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmduseradd">2.66 Add a New User (useradd)</a>
<a href="#cmduserdel">2.66 Delete a user (userdel)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmduserdel">2.67 Delete a user (userdel)</a>
<a href="#cmdusleep">2.67 Wait for Microseconds (usleep)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdusleep">2.68 Wait for Microseconds (usleep)</a>
<a href="#cmdwget">2.68 Get File Via HTTP (wget)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdwget">2.69 Get File Via HTTP (wget)</a>
</td>
</tr>
<tr>
<td><br></td>
<td>
<a href="#cmdxd">2.70 Hexadecimal Dump of Memory (xd)</a>
<a href="#cmdxd">2.69 Hexadecimal Dump of Memory (xd)</a>
</td>
</tr>
<tr>
@ -515,7 +509,7 @@
<tr>
<td><br></td>
<td>
<a href="#builtinping">3.1 Check Network Peer (ping)</a>
<a href="#builtinping">3.1 Check Network Peer (ping/pin6)</a>
</td>
</tr>
@ -2532,26 +2526,7 @@ passwd &lt;username&gt; &lt;password&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdping6"><h2>2.45 Check Network Peer (ping6)</h2></a>
</td>
</tr>
</table>
<p><b>Command Syntax:</b></p>
<ul><pre>
ping6 [-c &lt;count&gt;] [-i &lt;interval&gt;] &lt;ip-address&gt;
</pre></ul>
<p>
<b>Synopsis</b>.
Test the network communication with a remote peer.
</p>
<code>ping6</code> differs from <a href="#builtinping"><code>ping</code></a> in that it uses IPv6 addressing.
</p>
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdpoweroff"><h2>2.46 Shut the system down (poweroff)</h2></a>
<a name="cmdpoweroff"><h2>2.45 Shut the system down (poweroff)</h2></a>
</td>
</tr>
</table>
@ -2573,7 +2548,7 @@ poweroff
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdput"><h2>2.47 Send File Via TFTP (put)</h2></a>
<a name="cmdput"><h2>2.46 Send File Via TFTP (put)</h2></a>
</td>
</tr>
</table>
@ -2608,7 +2583,7 @@ put [-b|-n] [-f &lt;remote-path&gt;] -h &lt;ip-address&gt; &lt;local-path&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdpwd"><h2>2.48 Show Current Working Directory (pwd)</h2></a>
<a name="cmdpwd"><h2>2.47 Show Current Working Directory (pwd)</h2></a>
</td>
</tr>
</table>
@ -2638,7 +2613,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdreadlink"><h2>2.49 Show target of a link (readlink)</h2></a>
<a name="cmdreadlink"><h2>2.48 Show target of a link (readlink)</h2></a>
</td>
</tr>
</table>
@ -2655,7 +2630,7 @@ readlink &lt;link&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdreboot"><h2>2.50 Reboot the system (reboot)</h2></a>
<a name="cmdreboot"><h2>2.49 Reboot the system (reboot)</h2></a>
</td>
</tr>
</table>
@ -2676,7 +2651,7 @@ reboot
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdrm"><h2>2.51 Remove a File (rm)</h2></a>
<a name="cmdrm"><h2>2.50 Remove a File (rm)</h2></a>
</td>
</tr>
</table>
@ -2710,7 +2685,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdrmdir"><h2>2.52 Remove a Directory (rmdir)</h2></a>
<a name="cmdrmdir"><h2>2.51 Remove a Directory (rmdir)</h2></a>
</td>
</tr>
</table>
@ -2745,7 +2720,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdrmmod"><h2>2.53 Remove on OS Module (rmmod)</h2></a>
<a name="cmdrmmod"><h2>2.52 Remove on OS Module (rmmod)</h2></a>
</td>
</tr>
</table>
@ -2773,7 +2748,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdroute"><h2>2.54 Show routing table (route)</h2></a>
<a name="cmdroute"><h2>2.53 Show routing table (route)</h2></a>
</td>
</tr>
</table>
@ -2793,7 +2768,7 @@ route ipv4|ipv6
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdset"><h2>2.55 Set an Environment Variable (set)</h2></a>
<a name="cmdset"><h2>2.54 Set an Environment Variable (set)</h2></a>
</td>
</tr>
</table>
@ -2862,7 +2837,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdsh"><h2>2.56 Execute an NSH Script (sh)</h2></a>
<a name="cmdsh"><h2>2.55 Execute an NSH Script (sh)</h2></a>
</td>
</tr>
</table>
@ -2880,7 +2855,7 @@ sh &lt;script-path&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdshutdown"><h2>2.57 Shut the system down (shutdown)</h2></a>
<a name="cmdshutdown"><h2>2.56 Shut the system down (shutdown)</h2></a>
</td>
</tr>
</table>
@ -2901,7 +2876,7 @@ shutdown [--reboot]
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdsleep"><h2>2.58 Wait for Seconds (sleep)</h2></a>
<a name="cmdsleep"><h2>2.57 Wait for Seconds (sleep)</h2></a>
</td>
</tr>
</table>
@ -2918,7 +2893,7 @@ sleep &lt;sec&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdtelnetd"><h2>2.59 Time Start the Telnet Daemon (telnetd)</h2></a>
<a name="cmdtelnetd"><h2>2.58 Time Start the Telnet Daemon (telnetd)</h2></a>
</td>
</tr>
</table>
@ -2944,7 +2919,7 @@ telnetd
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdtime"><h2>2.60 Time execution of another command (time)</h2></a>
<a name="cmdtime"><h2>2.59 Time execution of another command (time)</h2></a>
</td>
</tr>
</table>
@ -3002,7 +2977,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdunmount"><h2>2.61 Unmount a File System (umount)</h2></a>
<a name="cmdunmount"><h2>2.60 Unmount a File System (umount)</h2></a>
</td>
</tr>
</table>
@ -3032,7 +3007,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmduname"><h2>2.62 Print system information (uname)</h2></a>
<a name="cmduname"><h2>2.61 Print system information (uname)</h2></a>
</td>
</tr>
</table>
@ -3099,7 +3074,7 @@ uname [-a | -imnoprsv]
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdunset"><h2>2.63 Unset an Environment Variable (unset)</h2></a>
<a name="cmdunset"><h2>2.62 Unset an Environment Variable (unset)</h2></a>
</td>
</tr>
</table>
@ -3125,7 +3100,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdurldec"><h2>2.64 URL Decode (urldecode)</h2></a>
<a name="cmdurldec"><h2>2.63 URL Decode (urldecode)</h2></a>
</td>
</tr>
</table>
@ -3142,7 +3117,7 @@ urldecode [-f] &lt;string or filepath&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdurlencode"><h2>2.65 URL Encode (urlencode)</h2></a>
<a name="cmdurlencode"><h2>2.64 URL Encode (urlencode)</h2></a>
</td>
</tr>
</table>
@ -3159,7 +3134,7 @@ urlencode [-f] &lt;string or filepath&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmduseradd"><h2>2.66 Add a New User (useradd)</h2></a>
<a name="cmduseradd"><h2>2.65 Add a New User (useradd)</h2></a>
</td>
</tr>
</table>
@ -3176,7 +3151,7 @@ useradd &lt;username&gt; &lt;password&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmduserdel"><h2>2.67 Delete a user (userdel)</h2></a>
<a name="cmduserdel"><h2>2.66 Delete a user (userdel)</h2></a>
</td>
</tr>
</table>
@ -3193,7 +3168,7 @@ userdel &lt;username&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdusleep"><h2>2.68 Wait for Microseconds (usleep)</h2></a>
<a name="cmdusleep"><h2>2.67 Wait for Microseconds (usleep)</h2></a>
</td>
</tr>
</table>
@ -3210,7 +3185,7 @@ usleep &lt;usec&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdwget"><h2>2.69 Get File Via HTTP (wget)</h2></a>
<a name="cmdwget"><h2>2.68 Get File Via HTTP (wget)</h2></a>
</td>
</tr>
</table>
@ -3237,7 +3212,7 @@ wget [-o &lt;local-path&gt;] &lt;url&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="cmdxd"><h2>2.70 Hexadecimal Dump of Memory (xd)</h2></a>
<a name="cmdxd"><h2>2.69 Hexadecimal Dump of Memory (xd)</h2></a>
</td>
</tr>
</table>
@ -3285,7 +3260,7 @@ nsh&gt;
<table width ="100%">
<tr bgcolor="#e4e4e4">
<td>
<a name="builtinping"><h2>3.1 Check Network Peer (ping)</h2></a>
<a name="builtinping"><h2>3.1 Check Network Peer (ping/ping6)</h2></a>
</td>
</tr>
</table>
@ -3293,6 +3268,7 @@ nsh&gt;
<p><b>Command Syntax:</b></p>
<ul><pre>
ping [-c &lt;count&gt;] [-i &lt;interval&gt;] &lt;ip-address&gt;
ping6 [-c &lt;count&gt;] [-i &lt;interval&gt;] &lt;ip-address&gt;
</pre></ul>
<p>
<b>Synopsis</b>.
@ -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&gt;
</pre></ul>
</p>
<code>ping6</code> differs from <code>ping</code> in that it uses IPv6 addressing.
</p>
<table width ="100%">
<tr bgcolor="#e4e4e4">
@ -3574,12 +3553,6 @@ nsh&gt;
<td>!<code>CONFIG_DISABLE_MOUNTPOINT</code> &amp;&amp; <code>CONFIG_NFILE_DESCRIPTORS</code> &gt; 0 &amp;&amp; <code>CONFIG_FS_WRITABLE</code> &amp;&amp; <code>CONFIG_NSH_LOGIN_PASSWD</code></td>
<td><code>CONFIG_NSH_DISABLE_PASSWD</code></td>
</tr>
<tr>
<td><b><code>ping6</code></b></td>
<td><code>CONFIG_NET</code> &amp;&amp; <code>CONFIG_NET_ICMPv6</code> &amp;&amp;
<code>CONFIG_NET_ICMPv6_PING</code> &amp;&amp; !<code>CONFIG_DISABLE_SIGNALS</code></td>
<td><code>CONFIG_NSH_DISABLE_PING6</code></td>
</tr>
<tr>
<td><b><code>poweroff</code></b></td>
<td><code>CONFIG_BOARDCTL_POWEROFF</td>
@ -3761,6 +3734,11 @@ nsh&gt;
<td><code>CONFIG_NET</code> &amp;&amp; <code>CONFIG_NET_ICMP</code> &amp;&amp;
<code>CONFIG_NET_ICMP_SOCKET</code> &amp;&amp; <code>CONFIG_SYSTEM_PING</code> &amp;&amp; !<code>CONFIG_DISABLE_SIGNALS</code> &amp;&amp; !<code>CONFIG_DISABLE_POLL</code></td>
</tr>
<tr>
<td><b><code>ping6</code></b></td>
<td><code>CONFIG_NET</code> &amp;&amp; <code>CONFIG_NET_ICMPv6</code> &amp;&amp;
<code>CONFIG_NET_ICMPv6_SOCKET</code> &amp;&amp; <code>CONFIG_SYSTEM_PING6</code> &amp;&amp; !<code>CONFIG_DISABLE_SIGNALS</code> &amp;&amp; !<code>CONFIG_DISABLE_POLL</code></td>
</tr>
</table></center>
<table width ="100%">
@ -5556,7 +5534,7 @@ xxd -i romfs_img >nsh_romfsimg.h
<li><a href="#passwdfiles">Password File</a></li>
<li><a href="#passwdromfs">Password File, ROMFS</a></li>
<li><a href="#builtinping"><code>ping</code></a></li>
<li><a href="#cmdping6"><code>ping6</code></a></li>
<li><a href="#builtinping"><code>ping6</code></a></li>
<li><a href="#cmdpoweroff"><code>poweroff</code></a></li>
<li><a href="#nshprompt">Prompt</a></li>
<li><a href="#cmdps"><code>ps</code></a></li>

1
TODO
View File

@ -646,7 +646,6 @@ o Kernel/Protected Build
COMMAND KERNEL INTERFACE(s)
-------- ----------------------------------------------
mkrd ramdisk_register()
ping6 icmpv6_ping()
mount foreach_mountpoint()
Status: Open

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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. */

View File

@ -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
}

View File

@ -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. */

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -43,9 +43,14 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <semaphore.h>
#include <queue.h>
#include <assert.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/netdev.h>
#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
}

286
net/icmpv6/icmpv6_conn.c Normal file
View File

@ -0,0 +1,286 @@
/****************************************************************************
* net/icmp/icmpv6_conn.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <arch/irq.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/arp.h>
#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 */

View File

@ -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++;

311
net/icmpv6/icmpv6_netpoll.c Normal file
View File

@ -0,0 +1,311 @@
/****************************************************************************
* net/icmpv6/icmpv6_netpoll.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <poll.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/net/net.h>
#include <devif/devif.h>
#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 */

View File

@ -1,502 +0,0 @@
/****************************************************************************
* net/icmpv6/icmpv6_ping.c
*
* Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#ifdef CONFIG_NET_ICMPv6_PING
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <semaphore.h>
#include <debug.h>
#include <net/if.h>
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/icmpv6.h>
#include <nuttx/net/netstats.h>
#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 */

View File

@ -38,7 +38,7 @@
****************************************************************************/
#include <nuttx/config.h>
#if defined(CONFIG_NET_ICMPv6_PING) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
#if defined(CONFIG_NET_ICMPv6_SOCKET) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
#include <semaphore.h>
#include <debug.h>
@ -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 */

View File

@ -0,0 +1,556 @@
/****************************************************************************
* net/icmpv6/icmpv6_recvfrom.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/icmpv6.h>
#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 */

509
net/icmpv6/icmpv6_sendto.c Normal file
View File

@ -0,0 +1,509 @@
/****************************************************************************
* net/icmpv6/icmpv6_sendto.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <semaphore.h>
#include <assert.h>
#include <debug.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <nuttx/semaphore.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/netstats.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/icmpv6.h>
#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 */

520
net/icmpv6/icmpv6_sockif.c Normal file
View File

@ -0,0 +1,520 @@
/****************************************************************************
* net/socket/icmpv6_sockif.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <socket/socket.h>
#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 */

View File

@ -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))
{

View File

@ -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 */