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