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