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 #include "nx_api.h"
26 #include "nx_packet.h"
27 #include "nx_ip.h"
28 #include "nx_ipv6.h"
29 #include "nx_icmpv6.h"
30 
31 #ifdef FEATURE_NX_IPV6
32 #ifndef NX_DISABLE_ICMPV6_ROUTER_SOLICITATION
33 static const ULONG _nx_ipv6_all_router_address[4] = {0xff020000, 0, 0, 2};
34 
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _nx_icmpv6_send_rs                                  PORTABLE C      */
40 /*                                                           6.1          */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Yuxin Zhou, Microsoft Corporation                                   */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function sends an ICMPv6 Router Solicitation message.          */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    ip_ptr                                Pointer to IP control block   */
52 /*    if_index                              Index of interface            */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    NX_SUCCESS: RS packet is sent                                       */
57 /*    NX_NOT_SUCCESSFUL: RS packet is not sent                            */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _nx_ip_checksum_compute               Computer ICMP checksum        */
62 /*    _nx_ipv6_packet_send                  Send ICMPv6 packet out        */
63 /*    _nx_packet_allocate                   Packet allocation function    */
64 /*    _nxd_ipv6_interface_find              Find outgoing interface for   */
65 /*                                             sending packet             */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    _nxd_ipv6_router_solicitation_check   IPv6 router solicitation      */
70 /*                                             timeout routine.           */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
77 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
78 /*                                            resulting in version 6.1    */
79 /*                                                                        */
80 /**************************************************************************/
_nx_icmpv6_send_rs(NX_IP * ip_ptr,UINT if_index)81 UINT  _nx_icmpv6_send_rs(NX_IP *ip_ptr, UINT if_index)
82 {
83 
84 USHORT           *mac_addr;
85 NX_PACKET        *pkt_ptr;
86 USHORT            checksum;
87 #if defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
88 UINT              compute_checksum = 1;
89 #endif /* defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
90 NX_ICMPV6_RS     *rs_ptr;
91 NX_ICMPV6_OPTION *rs_options;
92 
93 
94     /* Do not send RS packet if ICMPv6 is not enabled. */
95     if (ip_ptr -> nx_ip_icmpv6_packet_process == NX_NULL)
96     {
97         return(NX_NOT_SUCCESSFUL);
98     }
99 
100     /* Allocate a packet to build the ICMPv6 router
101        solicitation message in.  */
102 #ifdef NX_ENABLE_DUAL_PACKET_POOL
103     /* Allocate from auxiliary packet pool first. */
104     if (_nx_packet_allocate(ip_ptr -> nx_ip_auxiliary_packet_pool, &pkt_ptr, (NX_ICMP_PACKET + sizeof(NX_ICMPV6_RS) + 8), NX_NO_WAIT))
105     {
106         if (ip_ptr -> nx_ip_auxiliary_packet_pool != ip_ptr -> nx_ip_default_packet_pool)
107 #endif /* NX_ENABLE_DUAL_PACKET_POOL */
108         {
109             if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool,
110                                     &pkt_ptr, (NX_ICMP_PACKET + sizeof(NX_ICMPV6_RS) + 8), NX_NO_WAIT))
111             {
112 
113                 /* Error getting packet, so just get out!  */
114                 return(NX_NOT_SUCCESSFUL);
115             }
116         }
117 #ifdef NX_ENABLE_DUAL_PACKET_POOL
118         else
119         {
120 
121             /* Error getting packet, so just get out!  */
122             return(NX_NOT_SUCCESSFUL);
123         }
124     }
125 #endif /* NX_ENABLE_DUAL_PACKET_POOL */
126 
127     /* Add debug information. */
128     NX_PACKET_DEBUG(__FILE__, __LINE__, pkt_ptr);
129 
130     /* Find a valid IPv6 address. */
131     if (_nxd_ipv6_interface_find(ip_ptr, (ULONG *)_nx_ipv6_all_router_address,
132                                  &pkt_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr,
133                                  &ip_ptr -> nx_ip_interface[if_index]))
134     {
135         _nx_packet_release(pkt_ptr);
136         return(NX_NOT_SUCCESSFUL);
137     }
138 
139     /*lint -e{644} suppress variable might not be initialized, since "pkt_ptr" was initialized in _nx_packet_allocate. */
140     pkt_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6;
141 
142     /* Set the size of the ICMPv6 router solicitation message. */
143     /* Size of the message is ICMPv6 + options, which is 8 bytes. */
144     pkt_ptr -> nx_packet_length = (sizeof(NX_ICMPV6_RS) + 8);
145 
146     /* Set the prepend pointer. */
147     pkt_ptr -> nx_packet_prepend_ptr -= pkt_ptr -> nx_packet_length;
148 
149     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
150     rs_ptr = (NX_ICMPV6_RS *)(pkt_ptr -> nx_packet_prepend_ptr);
151     rs_ptr -> nx_icmpv6_rs_icmpv6_header.nx_icmpv6_header_type = NX_ICMPV6_ROUTER_SOLICITATION_TYPE;
152     rs_ptr -> nx_icmpv6_rs_icmpv6_header.nx_icmpv6_header_code = 0;
153     rs_ptr -> nx_icmpv6_rs_icmpv6_header.nx_icmpv6_header_checksum = 0;
154     rs_ptr -> nx_icmpv6_rs_reserved = 0;
155 
156     /* Get a pointer to the Option header in the ICMPv6 header. */
157     /*lint -e{923} suppress cast between pointer and ULONG, since it is necessary  */
158     rs_options = (NX_ICMPV6_OPTION *)NX_UCHAR_POINTER_ADD(rs_ptr, sizeof(NX_ICMPV6_RS));
159 
160     /* Fill in the options field */
161     rs_options -> nx_icmpv6_option_type = ICMPV6_OPTION_TYPE_SRC_LINK_ADDR;
162     rs_options -> nx_icmpv6_option_length = 1;
163 
164     /* Fill in the source mac address. */
165     mac_addr = &rs_options -> nx_icmpv6_option_data;
166     mac_addr[0] = (USHORT)(ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_msw);
167     mac_addr[1] = (USHORT)((ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_lsw & 0xFFFF0000) >> 16); /* lgtm[cpp/overflow-buffer] */
168     mac_addr[2] = (USHORT)(ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_lsw & 0x0000FFFF); /* lgtm[cpp/overflow-buffer] */
169 
170     /* Byte swapping. */
171     NX_CHANGE_USHORT_ENDIAN(mac_addr[0]);
172     NX_CHANGE_USHORT_ENDIAN(mac_addr[1]); /* lgtm[cpp/overflow-buffer] */
173     NX_CHANGE_USHORT_ENDIAN(mac_addr[2]); /* lgtm[cpp/overflow-buffer] */
174 
175 #ifdef NX_DISABLE_ICMPV6_TX_CHECKSUM
176     compute_checksum = 0;
177 #endif /* NX_DISABLE_ICMPV6_TX_CHECKSUM */
178 
179 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
180     if (ip_ptr -> nx_ip_interface[if_index].nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM)
181     {
182         compute_checksum = 0;
183     }
184 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
185 
186 #if defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
187     if (compute_checksum)
188 #endif /* defined(NX_DISABLE_ICMPV6_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
189     {
190 
191         /* Compute checksum.  The returned value is already in network byte order. */
192         /*lint -e{929} suppress cast of pointer to pointer, since it is necessary  */
193         checksum = _nx_ip_checksum_compute(pkt_ptr, NX_PROTOCOL_ICMPV6,
194                                            (UINT)pkt_ptr -> nx_packet_length,
195                                            pkt_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address,
196                                            (ULONG *)_nx_ipv6_all_router_address);
197 
198         checksum = (USHORT)(~checksum);
199 
200         /* Byte swapping. */
201         NX_CHANGE_USHORT_ENDIAN(checksum);
202 
203         rs_ptr -> nx_icmpv6_rs_icmpv6_header.nx_icmpv6_header_checksum = checksum;
204     }
205 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
206     else
207     {
208         pkt_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM;
209     }
210 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
211 
212     /*lint -e{929} suppress cast of pointer to pointer, since it is necessary  */
213     _nx_ipv6_packet_send(ip_ptr, pkt_ptr, NX_PROTOCOL_ICMPV6, pkt_ptr -> nx_packet_length, 255,
214                          pkt_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address,
215                          (ULONG *)_nx_ipv6_all_router_address);
216 
217     return(NX_SUCCESS);
218 }
219 #endif /* NX_DISABLE_ICMPV6_ROUTER_SOLICITATION */
220 #endif /* FEATURE_NX_IPV6 */
221 
222