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