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:
parent
bad3379bc4
commit
70c59a9d91
@ -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 <username> <password>
|
||||
<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 <count>] [-i <interval>] <ip-address>
|
||||
</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 <remote-path>] -h <ip-address> <local-path>
|
||||
<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>
|
||||
<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 <link>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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 <script-path>
|
||||
<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 <sec>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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] <string or filepath>
|
||||
<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] <string or filepath>
|
||||
<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 <username> <password>
|
||||
<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 <username>
|
||||
<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 <usec>
|
||||
<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 <local-path>] <url>
|
||||
<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>
|
||||
<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>
|
||||
<p><b>Command Syntax:</b></p>
|
||||
<ul><pre>
|
||||
ping [-c <count>] [-i <interval>] <ip-address>
|
||||
ping6 [-c <count>] [-i <interval>] <ip-address>
|
||||
</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>
|
||||
</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>
|
||||
<td>!<code>CONFIG_DISABLE_MOUNTPOINT</code> && <code>CONFIG_NFILE_DESCRIPTORS</code> > 0 && <code>CONFIG_FS_WRITABLE</code> && <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> && <code>CONFIG_NET_ICMPv6</code> &&
|
||||
<code>CONFIG_NET_ICMPv6_PING</code> && !<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>
|
||||
<td><code>CONFIG_NET</code> && <code>CONFIG_NET_ICMP</code> &&
|
||||
<code>CONFIG_NET_ICMP_SOCKET</code> && <code>CONFIG_SYSTEM_PING</code> && !<code>CONFIG_DISABLE_SIGNALS</code> && !<code>CONFIG_DISABLE_POLL</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b><code>ping6</code></b></td>
|
||||
<td><code>CONFIG_NET</code> && <code>CONFIG_NET_ICMPv6</code> &&
|
||||
<code>CONFIG_NET_ICMPv6_SOCKET</code> && <code>CONFIG_SYSTEM_PING6</code> && !<code>CONFIG_DISABLE_SIGNALS</code> && !<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
1
TODO
@ -646,7 +646,6 @@ o Kernel/Protected Build
|
||||
COMMAND KERNEL INTERFACE(s)
|
||||
-------- ----------------------------------------------
|
||||
mkrd ramdisk_register()
|
||||
ping6 icmpv6_ping()
|
||||
mount foreach_mountpoint()
|
||||
|
||||
Status: Open
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
286
net/icmpv6/icmpv6_conn.c
Normal 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 */
|
@ -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
311
net/icmpv6/icmpv6_netpoll.c
Normal 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 */
|
@ -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 */
|
@ -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 */
|
||||
|
556
net/icmpv6/icmpv6_recvfrom.c
Normal file
556
net/icmpv6/icmpv6_recvfrom.c
Normal 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
509
net/icmpv6/icmpv6_sendto.c
Normal 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
520
net/icmpv6/icmpv6_sockif.c
Normal 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 */
|
@ -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))
|
||||
{
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user