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