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