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_ipv6.h"
26 #include "nx_icmpv6.h"
27 #include "nx_packet.h"
28
29 #ifdef FEATURE_NX_IPV6
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_icmpv6_send_queued_packets PORTABLE C */
36 /* 6.2.1 */
37 /* AUTHOR */
38 /* */
39 /* Yuxin Zhou, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function sends out queued packets after their destination */
44 /* link layer address becomes known, i.e, after receiving a */
45 /* neighbor advertisement message from the destination host. */
46 /* */
47 /* INPUT */
48 /* */
49 /* ip_ptr Pointer to IP control block */
50 /* nd_entry Destination host ND entry */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* _nx_ipv6_fragment_process IPv6 fragmentation routine */
59 /* [_nx_ip_link_driver_entry] Ethernet Device Driver Entry */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* _nx_icmp_packet_process Main ICMP packet process */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
70 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
71 /* resulting in version 6.1 */
72 /* 03-08-2023 Tiejun Zhou Modified comment(s), and */
73 /* fixed compiler warnings, */
74 /* resulting in version 6.2.1 */
75 /* */
76 /**************************************************************************/
_nx_icmpv6_send_queued_packets(NX_IP * ip_ptr,ND_CACHE_ENTRY * nd_entry)77 VOID _nx_icmpv6_send_queued_packets(NX_IP *ip_ptr, ND_CACHE_ENTRY *nd_entry)
78 {
79
80 NX_IP_DRIVER driver_request;
81 UCHAR *mac_addr;
82 NX_PACKET *queued_list_head, *ip_packet_ptr;
83 UINT next_hop_mtu;
84 #ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
85 NX_IPV6_DESTINATION_ENTRY *dest_entry_ptr;
86 NX_IPV6_HEADER *ip_header_ptr;
87 ULONG status;
88 #endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */
89
90 TX_INTERRUPT_SAVE_AREA
91
92 /* nd_entry must not be NX_NULL. */
93 NX_ASSERT(nd_entry != NX_NULL);
94
95 /* The packet waiting head must not be NX_NULL. */
96 NX_ASSERT(nd_entry -> nx_nd_cache_packet_waiting_head != NX_NULL);
97
98 /*lint --e{613} suppress possible use of null pointer, since "nd_entry" must not be null. */
99 queued_list_head = nd_entry -> nx_nd_cache_packet_waiting_head;
100
101 mac_addr = nd_entry -> nx_nd_cache_mac_addr;
102
103 /* Build the driver request packet. */
104 driver_request.nx_ip_driver_physical_address_msw = ((ULONG)(mac_addr[0]) << 8) | mac_addr[1];
105 driver_request.nx_ip_driver_physical_address_lsw = ((ULONG)(mac_addr[2]) << 24) | ((ULONG)(mac_addr[3]) << 16) | ((ULONG)(mac_addr[4]) << 8) | mac_addr[5];
106 driver_request.nx_ip_driver_ptr = ip_ptr;
107 driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND;
108 driver_request.nx_ip_driver_interface = nd_entry -> nx_nd_cache_interface_ptr;
109 driver_request.nx_ip_driver_status = NX_SUCCESS;
110
111 /* Loop through all the queued packets. */
112 while (queued_list_head)
113 {
114
115 /* Set a pointer to the start of the queue. */
116 ip_packet_ptr = queued_list_head;
117 queued_list_head = queued_list_head -> nx_packet_queue_next;
118
119 /* Clear the packet's queue next pointer */
120 ip_packet_ptr -> nx_packet_queue_next = NX_NULL;
121
122 /* Add this packet to the driver request (to send). */
123 driver_request.nx_ip_driver_packet = ip_packet_ptr;
124
125 /* Set the next hop MTU. */
126 next_hop_mtu = driver_request.nx_ip_driver_interface -> nx_interface_ip_mtu_size;
127
128 /* Check if path MTU Discovery is enabled first. */
129 #ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
130
131 /* It is. To know if we need to fragment this packet we need the path MTU for the packet
132 destination. */
133
134 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
135 ip_header_ptr = (NX_IPV6_HEADER *)ip_packet_ptr -> nx_packet_prepend_ptr;
136
137 /* Convert destination address to host byte order. */
138 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
139
140 /* Find the entry in the cache table for packet's destination. */
141 status = _nx_icmpv6_dest_table_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &dest_entry_ptr, 0, 0);
142
143 /* Convert destination address back to net byte order. */
144 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
145
146 /* Check for successful search and location of packet destination data. */
147 if (status == NX_SUCCESS)
148 {
149
150 ULONG next_hop_address[4];
151 NX_IPV6_DESTINATION_ENTRY *next_hop_dest_entry_ptr;
152
153 /* If this destination has a non null next hop, we need to ascertain the next hop MTU. */
154
155 /* Get the path MTU for the actual destination. */
156 next_hop_mtu = dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu;
157
158 /* Set the next hop address. */
159 COPY_IPV6_ADDRESS(dest_entry_ptr -> nx_ipv6_destination_entry_next_hop, next_hop_address);
160
161 /* Check the next hop address. */
162 if (!CHECK_UNSPECIFIED_ADDRESS(&(next_hop_address[0])))
163 {
164
165 /* Find the next hop in the destination table. */
166 status = _nx_icmpv6_dest_table_find(ip_ptr, next_hop_address, &next_hop_dest_entry_ptr, 0, 0);
167
168 if (status == NX_SUCCESS)
169 {
170
171
172 /* Now compare the destination path MTU with the next hop path MTU*/
173 if ((next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu > 0) &&
174 (next_hop_mtu > next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu))
175 {
176
177 /* Update the path mtu to reflect the next hop route. */
178 next_hop_mtu = next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu;
179 }
180 }
181 }
182 }
183 #endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */
184
185 /* Does the packet payload exceed next hop MTU? */
186 if (ip_packet_ptr -> nx_packet_length > next_hop_mtu)
187 {
188 #ifndef NX_DISABLE_FRAGMENTATION
189
190 /* Yes; ok to fragment the packet payload. */
191 _nx_ipv6_fragment_process(&driver_request, next_hop_mtu);
192
193 #else /* NX_DISABLE_FRAGMENTATION */
194
195 #ifndef NX_DISABLE_IP_INFO
196 /* Increment the IP send packets dropped count. */
197 ip_ptr -> nx_ip_send_packets_dropped++;
198 #endif
199 /* Just release the packet. */
200 _nx_packet_transmit_release(ip_packet_ptr);
201 #endif /* NX_DISABLE_FRAGMENTATION */
202 }
203 else
204 {
205
206 /* The packet requires no fragmentation. Proceed with sending the packet. */
207
208 #ifndef NX_DISABLE_IP_INFO
209
210 /* Increment the IP packet sent count. */
211 ip_ptr -> nx_ip_total_packets_sent++;
212
213 /* Increment the IP bytes sent count. */
214 ip_ptr -> nx_ip_total_bytes_sent += ip_packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV6_HEADER);
215 #endif /* !NX_DISABLE_IP_INFO */
216
217 /* Add debug information. */
218 NX_PACKET_DEBUG(__FILE__, __LINE__, ip_packet_ptr);
219
220 /* Send the queued IP packet out on the network via the attached driver. */
221 (ip_packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached -> nx_interface_link_driver_entry)(&driver_request);
222 }
223 }
224
225 TX_DISABLE
226 /*
227 If the ND Cache is in STALE state, move it to DELAY state.
228 This situation happens when we receive the LLA (link local address) through
229 unsoliciated RA (router advertisement message. In this situation,
230 the entry is in STALE state, and a packet has been transmitted,
231 so the entry needs to be in DELAY state.
232 */
233 if (nd_entry -> nx_nd_cache_nd_status == ND_CACHE_STATE_STALE)
234 {
235
236 nd_entry -> nx_nd_cache_nd_status = ND_CACHE_STATE_DELAY;
237
238 /* Start the Delay first probe timer */
239 nd_entry -> nx_nd_cache_timer_tick = NX_DELAY_FIRST_PROBE_TIME;
240 }
241 TX_RESTORE
242
243 /* Clean up the nd_entry */
244 nd_entry -> nx_nd_cache_packet_waiting_head = NX_NULL;
245 nd_entry -> nx_nd_cache_packet_waiting_tail = NX_NULL;
246
247 /* Clean up the queue length variable. */
248 nd_entry -> nx_nd_cache_packet_waiting_queue_length = 0;
249 }
250 #endif /* FEATURE_NX_IPV6 */
251
252