1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** NetX Component                                                        */
17 /**                                                                       */
18 /**   Internet Control Message Protocol (ICMP)                            */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "nx_api.h"
29 #include "nx_packet.h"
30 #include "nx_ip.h"
31 #include "nx_ipv6.h"
32 #include "nx_icmpv6.h"
33 
34 
35 #ifdef FEATURE_NX_IPV6
36 static const ULONG _nx_ipv6_unspecified_address[4] = {0, 0, 0, 0};
37 
38 /**************************************************************************/
39 /*                                                                        */
40 /*  FUNCTION                                               RELEASE        */
41 /*                                                                        */
42 /*    _nx_icmpv6_send_ns                                  PORTABLE C      */
43 /*                                                           6.1          */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    Yuxin Zhou, Microsoft Corporation                                   */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*   This function sends out an ICMPv6 Neighbor Solicitation (NS) message.*/
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    ip_ptr                                Pointer to IP control block   */
55 /*    targetIPAddr                          Target IPv6 Address           */
56 /*    send_slla                             Send Source Link Layer Address*/
57 /*    outgoing_address                      IP interface to transmit the  */
58 /*                                                 packet out on          */
59 /*    sendUnicast                           Send out a unicast NS         */
60 /*    NDCacheEntry                          Pointer to ND cache entry     */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    None                                                                */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _nx_ip_checksum_compute               Computer ICMP checksum        */
69 /*    _nx_ipv6_packet_send                  Send packet out               */
70 /*    _nx_packet_allocate                   Packet allocate function      */
71 /*    _nx_packet_release                    Packet release function       */
72 /*    _nx_ipv6_header_add                   Add IPv6 header               */
73 /*    (ip_link_driver)                      User supplied link driver     */
74 /*                                                                        */
75 /*  CALLED BY                                                             */
76 /*                                                                        */
77 /*    _nx_icmpv6_packet_process             Main ICMP packet pocess       */
78 /*    _nx_icmpv6_perform_DAD                Procedure for Duplicate       */
79 /*                                             Address Detection.         */
80 /*    _nx_ipv6_packet_send                  IPv6 packet transmit process  */
81 /*    _nx_nd_cache_periodic_update          ND Cache timeout routine.     */
82 /*                                                                        */
83 /*  RELEASE HISTORY                                                       */
84 /*                                                                        */
85 /*    DATE              NAME                      DESCRIPTION             */
86 /*                                                                        */
87 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
88 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
89 /*                                            resulting in version 6.1    */
90 /*                                                                        */
91 /**************************************************************************/
_nx_icmpv6_send_ns(NX_IP * ip_ptr,ULONG * neighbor_IP_address,INT send_slla,NXD_IPV6_ADDRESS * outgoing_address,INT sendUnicast,ND_CACHE_ENTRY * NDCacheEntry)92 VOID _nx_icmpv6_send_ns(NX_IP                 *ip_ptr,
93                         ULONG                 *neighbor_IP_address,
94                         INT                    send_slla,
95                         NXD_IPV6_ADDRESS      *outgoing_address,
96                         INT                    sendUnicast,
97                         ND_CACHE_ENTRY        *NDCacheEntry)
98 {
99 
100 NX_PACKET    *pkt_ptr;
101 USHORT        checksum;
102 #if defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
103 UINT          compute_checksum = 1;
104 #endif /* defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
105 NX_ICMPV6_ND *nd_ptr;
106 ULONG        *src_address;
107 ULONG         dest_address[4];
108 NX_IP_DRIVER  driver_request;
109 
110 
111     /* Allocate a packet to build the ICMPv6 NS message in.  */
112 #ifdef NX_ENABLE_DUAL_PACKET_POOL
113     /* Allocate from auxiliary packet pool first. */
114     if (_nx_packet_allocate(ip_ptr -> nx_ip_auxiliary_packet_pool, &pkt_ptr, NX_IPv6_ICMP_PACKET, NX_NO_WAIT))
115     {
116         if (ip_ptr -> nx_ip_auxiliary_packet_pool != ip_ptr -> nx_ip_default_packet_pool)
117 #endif /* NX_ENABLE_DUAL_PACKET_POOL */
118         {
119             if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &pkt_ptr, NX_IPv6_ICMP_PACKET, NX_NO_WAIT))
120             {
121 
122                 /* Error getting packet, so just get out!  */
123                 return;
124             }
125         }
126 #ifdef NX_ENABLE_DUAL_PACKET_POOL
127         else
128         {
129 
130             /* Error getting packet, so just get out!  */
131             return;
132         }
133     }
134 #endif /* NX_ENABLE_DUAL_PACKET_POOL */
135 
136     /* Add debug information. */
137     NX_PACKET_DEBUG(__FILE__, __LINE__, pkt_ptr);
138 
139     /* Mark the packet as IPv6 packet. */
140     /*lint -e{644} suppress variable might not be initialized, since "pkt_ptr" was initialized in _nx_packet_allocate. */
141     pkt_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6;
142 
143     /* Setup the size of the ICMPv6 NS message */
144     pkt_ptr -> nx_packet_length = sizeof(NX_ICMPV6_ND);
145 
146     /* Add 8 more bytes if sending source link layer address. */
147     if (send_slla)
148     {
149         pkt_ptr -> nx_packet_length += 8;
150     }
151 
152     /* Check to see if the packet has enough room to fill with NS.  */
153     if ((UINT)(pkt_ptr -> nx_packet_data_end - pkt_ptr -> nx_packet_prepend_ptr) < pkt_ptr -> nx_packet_length)
154     {
155 
156         /* Error getting packet, so just get out!  */
157         _nx_packet_release(pkt_ptr);
158         return;
159     }
160 
161     /* Setup the append pointer to the end of the message. */
162     pkt_ptr -> nx_packet_append_ptr = pkt_ptr -> nx_packet_prepend_ptr + pkt_ptr -> nx_packet_length;
163 
164     /* Set up the ND message in the buffer. */
165     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
166     nd_ptr = (NX_ICMPV6_ND *)(pkt_ptr -> nx_packet_prepend_ptr);
167     nd_ptr -> nx_icmpv6_nd_header.nx_icmpv6_header_type = NX_ICMPV6_NEIGHBOR_SOLICITATION_TYPE;
168     nd_ptr -> nx_icmpv6_nd_header.nx_icmpv6_header_code = 0;
169     nd_ptr -> nx_icmpv6_nd_header.nx_icmpv6_header_checksum = 0;
170     nd_ptr -> nx_icmpv6_nd_flag = 0;
171 
172     /* copy the target IP address */
173     COPY_IPV6_ADDRESS(neighbor_IP_address, nd_ptr -> nx_icmpv6_nd_targetAddress);
174 
175     /* Convert the IP address to network byte order. */
176     NX_IPV6_ADDRESS_CHANGE_ENDIAN(nd_ptr -> nx_icmpv6_nd_targetAddress);
177 
178     if (sendUnicast)
179     {
180 
181         COPY_IPV6_ADDRESS(neighbor_IP_address, dest_address);
182     }
183     else
184     {
185 
186         /* Set up the next hop address, which is the target host's Solicited-Node
187            Multicast Address.  The address is formed by taking the last 24 bits of
188            the target IP address, in the form of:
189            0xFF02:0000:0000:0000:0000:0001:FFxx:xxxx */
190         SET_SOLICITED_NODE_MULTICAST_ADDRESS(dest_address, neighbor_IP_address);
191     }
192 
193     /* Set up source IP address to use for this packet.
194        If the global address is not valid yet, we use the unspecified address (::)
195        Otherwise the global address is used */
196     if (outgoing_address -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID)
197     {
198 
199         src_address = outgoing_address -> nxd_ipv6_address;
200     }
201     else
202     {
203 
204         /*lint -e{929} suppress cast of pointer to pointer, since it is necessary  */
205         src_address = (ULONG *)_nx_ipv6_unspecified_address;
206     }
207 
208     pkt_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr = outgoing_address;
209 
210     /* outgoing_address -> nxd_ipv6_address_attached can not be NULL. */
211     NX_ASSERT(outgoing_address -> nxd_ipv6_address_attached != NX_NULL);
212 
213     if (send_slla)  /* Need to send SLLA option */
214     {
215 
216     USHORT           *mac_addr;
217     NX_ICMPV6_OPTION *nd_options;
218 
219         /*lint -e{923} suppress cast between pointer and ULONG, since it is necessary  */
220         nd_options = (NX_ICMPV6_OPTION *)NX_UCHAR_POINTER_ADD(nd_ptr, sizeof(NX_ICMPV6_ND));
221 
222         /* Fill in the options field */
223         nd_options -> nx_icmpv6_option_type = 1;
224         nd_options -> nx_icmpv6_option_length = 1;
225 
226         /* Fill in the source MAC address */
227         mac_addr = &nd_options ->  nx_icmpv6_option_data;
228         mac_addr[0] = (USHORT)(outgoing_address -> nxd_ipv6_address_attached -> nx_interface_physical_address_msw);
229         mac_addr[1] = (USHORT)((outgoing_address -> nxd_ipv6_address_attached -> nx_interface_physical_address_lsw & 0xFFFF0000) >> 16); /* lgtm[cpp/overflow-buffer] */
230         mac_addr[2] = (USHORT)(outgoing_address -> nxd_ipv6_address_attached -> nx_interface_physical_address_lsw & 0x0000FFFF); /* lgtm[cpp/overflow-buffer] */
231 
232         /* Byte swapping. */
233         NX_CHANGE_USHORT_ENDIAN(mac_addr[0]);
234         NX_CHANGE_USHORT_ENDIAN(mac_addr[1]); /* lgtm[cpp/overflow-buffer] */
235         NX_CHANGE_USHORT_ENDIAN(mac_addr[2]); /* lgtm[cpp/overflow-buffer] */
236     }
237 
238 #ifdef NX_DISABLE_ICMPV6_TX_CHECKSUM
239     compute_checksum = 0;
240 #endif /* NX_DISABLE_ICMPV6_TX_CHECKSUM */
241 
242 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
243     if (outgoing_address -> nxd_ipv6_address_attached -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM)
244     {
245         compute_checksum = 0;
246     }
247 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
248 #if defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
249     if (compute_checksum)
250 #endif /* defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
251     {
252         /* Compute checksum.  The return value is already in network byte order */
253         checksum = _nx_ip_checksum_compute(pkt_ptr, NX_PROTOCOL_ICMPV6, (UINT)pkt_ptr -> nx_packet_length, src_address, dest_address);
254 
255         checksum = (USHORT)(~checksum);
256 
257         /* Byte swapping. */
258         NX_CHANGE_USHORT_ENDIAN(checksum);
259 
260         nd_ptr -> nx_icmpv6_nd_header.nx_icmpv6_header_checksum = checksum;
261     }
262 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
263     else
264     {
265         pkt_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM;
266     }
267 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
268 
269     /* Add IPv6 header. */
270     if (_nx_ipv6_header_add(ip_ptr, &pkt_ptr, NX_PROTOCOL_ICMPV6, pkt_ptr -> nx_packet_length,
271                             255, src_address, dest_address, NX_NULL) != NX_SUCCESS)
272     {
273 
274         /* Failed to add header. */
275         return;
276     }
277 
278     /* Build the driver request. */
279     driver_request.nx_ip_driver_ptr                  = ip_ptr;
280     driver_request.nx_ip_driver_command              = NX_LINK_PACKET_SEND;
281     driver_request.nx_ip_driver_packet               = pkt_ptr;
282     driver_request.nx_ip_driver_interface            = outgoing_address -> nxd_ipv6_address_attached;
283     if (sendUnicast)
284     {
285     UCHAR *mac_addr;
286         mac_addr = NDCacheEntry -> nx_nd_cache_mac_addr;
287 
288         /* Set unicast destination MAC. */
289         driver_request.nx_ip_driver_physical_address_msw = ((ULONG)mac_addr[0] << 8) | mac_addr[1];
290         driver_request.nx_ip_driver_physical_address_lsw =
291             ((ULONG)mac_addr[2] << 24) | ((ULONG)mac_addr[3] << 16) | ((ULONG)mac_addr[4] << 8) | mac_addr[5];
292     }
293     else
294     {
295 
296         /*lint -e{644} suppress variable might not be initialized, since dest_address was initialized. */
297         driver_request.nx_ip_driver_physical_address_msw = 0x00003333;
298         driver_request.nx_ip_driver_physical_address_lsw = dest_address[3];
299     }
300 
301 #ifndef NX_DISABLE_IP_INFO
302 
303     /* Increment the IP packet sent count.  */
304     ip_ptr -> nx_ip_total_packets_sent++;
305 
306     /* Increment the IP bytes sent count.  */
307     ip_ptr -> nx_ip_total_bytes_sent +=  pkt_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV6_HEADER);
308 #endif
309 
310     /* Add debug information. */
311     NX_PACKET_DEBUG(__FILE__, __LINE__, pkt_ptr);
312 
313     /* Driver entry must not be NULL. */
314     NX_ASSERT(outgoing_address -> nxd_ipv6_address_attached -> nx_interface_link_driver_entry != NX_NULL);
315 
316     /* Send the IP packet out on the network via the attached driver.  */
317     (outgoing_address -> nxd_ipv6_address_attached -> nx_interface_link_driver_entry)(&driver_request);
318 }
319 
320 #endif /* FEATURE_NX_IPV6 */
321 
322