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 Protocol (IP)                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_ip.h"
29 #include "nx_packet.h"
30 #include "nx_ipv6.h"
31 #include "nx_icmpv6.h"
32 
33 #ifdef FEATURE_NX_IPV6
34 
35 
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _nx_ipv6_packet_receive                             PORTABLE C      */
42 /*                                                           6.1          */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Yuxin Zhou, Microsoft Corporation                                   */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function receives IPv6 packets from the nx_ip_packet_receive.  */
50 /*    The packet is either processed here or placed it in a deferred      */
51 /*    processing queue, depending on the complexity of the packet.        */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    ip_ptr                                Pointer to IP control block   */
56 /*    packet_ptr                            Pointer to packet received    */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    None                                                                */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _nx_packet_release                    Packet release function       */
65 /*    _nx_ip_dispatch_process               The routine that examines     */
66 /*                                            other optional headers and  */
67 /*                                            upper layer protocols.      */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    Application I/O Driver                                              */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
78 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
79 /*                                            resulting in version 6.1    */
80 /*                                                                        */
81 /**************************************************************************/
_nx_ipv6_packet_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr)82 VOID  _nx_ipv6_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
83 {
84 
85 UINT              error;
86 ULONG             delta;
87 UINT              pkt_length;
88 UCHAR             next_header_type;
89 NX_IPV6_HEADER   *ip_header_ptr;
90 NXD_IPV6_ADDRESS *interface_ipv6_address_next;
91 NXD_IPV6_ADDRESS *incoming_address = NX_NULL;
92 #ifndef NX_DISABLE_PACKET_CHAIN
93 NX_PACKET        *before_last_packet;
94 NX_PACKET        *last_packet;
95 #endif /* NX_DISABLE_PACKET_CHAIN */
96 
97 #ifdef NX_ENABLE_IPV6_MULTICAST
98 INT               i = 0;
99 #endif /* NX_ENABLE_IPV6_MULTICAST  */
100 
101 
102     /* Add debug information. */
103     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
104 
105     /* Points to the base of IPv6 header. */
106     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
107     ip_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
108 
109     /* Byte swap WORD 1 to obtain IPv6 payload length. */
110     NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
111 
112     pkt_length = (UINT)((ip_header_ptr -> nx_ip_header_word_1 >> 16) + sizeof(NX_IPV6_HEADER));
113 
114     /* Make sure the packet length field matches the payload length field in the IPv6 header. */
115     if (packet_ptr -> nx_packet_length != (ULONG)pkt_length)
116     {
117 
118         /* Determine if the packet length is less than the size reported in the IP header.  */
119         if (packet_ptr -> nx_packet_length < (ULONG)pkt_length)
120         {
121 
122             /* The incoming packet has a wrong payload size. */
123 #ifndef NX_DISABLE_IP_INFO
124 
125             /* Increment the IP invalid packet error.  */
126             ip_ptr -> nx_ip_invalid_packets++;
127 
128             /* Increment the IP receive packets dropped count.  */
129             ip_ptr -> nx_ip_receive_packets_dropped++;
130 #endif
131 
132             /* Release the packet!  */
133             _nx_packet_release(packet_ptr);
134 
135             /* In all cases, receive processing is finished.  Return to caller.  */
136             return;
137         }
138 
139         /* Calculate the difference in the length.  */
140         delta =  packet_ptr -> nx_packet_length - pkt_length;
141 
142         /* Adjust the packet length.  */
143         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length - delta;
144 
145         /* Adjust the append pointer.  */
146 
147 #ifndef NX_DISABLE_PACKET_CHAIN
148         /* Loop to process adjustment that spans multiple packets.  */
149         while (delta)
150         {
151 
152             /* Determine if the packet is chained (or still chained after the adjustment).  */
153             if (packet_ptr -> nx_packet_last == NX_NULL)
154             {
155 
156                 /* No, packet is not chained, simply adjust the append pointer in the packet.  */
157                 packet_ptr -> nx_packet_append_ptr =  packet_ptr -> nx_packet_append_ptr - delta;
158 
159                 /* Break out of the loop, since the adjustment is complete.  */
160                 break;
161             }
162 
163             /* Pickup the pointer to the last packet.  */
164             last_packet =  packet_ptr -> nx_packet_last;
165 
166             /* Determine if the amount to adjust is less than the payload in the last packet.  */
167             /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
168             if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta)
169             {
170 
171                 /* Yes, simply adjust the append pointer of the last packet in the chain.  */
172                 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
173                 last_packet -> nx_packet_append_ptr =  last_packet -> nx_packet_append_ptr - delta;
174 
175                 /* Get out of the loop, since the adjustment is complete.  */
176                 break;
177             }
178             else
179             {
180 
181                 /* Adjust the delta by the amount in the last packet.  */
182                 delta =  delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr));
183 
184                 /* Find the packet before the last packet.  */
185                 before_last_packet =  packet_ptr;
186                 while (before_last_packet -> nx_packet_next != last_packet)
187                 {
188 
189                     /* Move to the next packet in the chain.  */
190                     before_last_packet =  before_last_packet -> nx_packet_next;
191                 }
192 
193                 /* At this point, we need to release the last packet and adjust the other packet
194                    pointers.  */
195 
196                 /* Ensure the next packet pointer is NULL in what is now the last packet.  */
197                 before_last_packet -> nx_packet_next =  NX_NULL;
198 
199                 /* Determine if the packet is still chained.  */
200                 if (packet_ptr != before_last_packet)
201                 {
202 
203                     /* Yes, the packet is still chained, setup the last packet pointer.  */
204                     packet_ptr -> nx_packet_last =  before_last_packet;
205                 }
206                 else
207                 {
208 
209                     /* The packet is no longer chained, set the last packet pointer to NULL.  */
210                     packet_ptr -> nx_packet_last =  NX_NULL;
211                 }
212 
213                 /* Release the last packet.   */
214                 _nx_packet_release(last_packet);
215             }
216         }
217 #else
218 
219         /* Simply adjust the append pointer in the packet.  */
220         packet_ptr -> nx_packet_append_ptr =  packet_ptr -> nx_packet_append_ptr - delta;
221 #endif /* NX_DISABLE_PACKET_CHAIN */
222     }
223 
224     /* Byte swap the rest of the IPv6 header fields. */
225     NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
226     NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
227     NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
228 
229     /* Get a pointer to the first address in the address list for this interface (e.g.
230        the interface the packet was received on). */
231     interface_ipv6_address_next = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nxd_interface_ipv6_address_list_head;
232 
233     /* Check if this packet is intended for this host by looping through all the addresses in the IP interface table for a match. */
234     while (interface_ipv6_address_next)
235     {
236 
237         /* Ignore invalid addresses. */
238         if (interface_ipv6_address_next -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_UNKNOWN)
239         {
240 
241             /* Does the incoming packet match one of the IP interfaces? */
242             if (CHECK_IPV6_ADDRESSES_SAME(ip_header_ptr -> nx_ip_header_destination_ip,
243                                           interface_ipv6_address_next -> nxd_ipv6_address))
244             {
245 
246                 /* Yes, we found a match! */
247                 incoming_address = interface_ipv6_address_next;
248 
249                 break;
250             }
251             /* Check for multicast address. */
252             else if (CHECK_IPV6_SOLICITED_NODE_MCAST_ADDRESS(ip_header_ptr -> nx_ip_header_destination_ip,
253                                                              interface_ipv6_address_next -> nxd_ipv6_address))
254             {
255 
256                 /* Yes, this is a multicast address. */
257                 incoming_address = interface_ipv6_address_next;
258 
259                 break;
260             }
261         }
262 
263         /* No match yet, get the next address. */
264         interface_ipv6_address_next = interface_ipv6_address_next -> nxd_ipv6_address_next;
265     }
266 
267 #ifdef NX_ENABLE_IPV6_MULTICAST
268 
269     if ((incoming_address == NX_NULL) && ((ip_header_ptr -> nx_ip_header_destination_ip[0] & 0xFF000000) == 0xFF000000))
270     {
271 
272         /* Search the address whether match our multicast join list.  */
273         for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++)
274         {
275 
276             /* Match the destination address with the multicast list */
277             if ((ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list == packet_ptr -> nx_packet_address.nx_packet_interface_ptr) &&
278                 (CHECK_IPV6_ADDRESSES_SAME(ip_header_ptr -> nx_ip_header_destination_ip, (ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list))))
279             {
280                 incoming_address = ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list -> nxd_interface_ipv6_address_list_head;
281                 break;
282             }
283         }
284     }
285 #endif /* NX_ENABLE_IPV6_MULTICAST  */
286 
287     /* Check for valid interface. */
288     if (incoming_address == NX_NULL)
289     {
290 
291         /* The incoming packet has a destination address that does not match any of
292            the local interface addresses so its not for me. */
293 
294 #ifndef NX_DISABLE_IP_INFO
295         /* Increment the IP receive packets dropped count.  */
296         ip_ptr -> nx_ip_receive_packets_dropped++;
297 #endif
298 
299         /* Release the packet. */
300         _nx_packet_release(packet_ptr);
301 
302         /* In all cases, receive processing is finished.  Return to caller.  */
303         return;
304     }
305 
306     /* Set the matching address to the packet address. */
307     packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr = incoming_address;
308 
309     /*
310        Update the IP header pointer, packet length and packet prepend pointer
311        to point to the next header (either IP option header or
312        upper layer protocol header.
313      */
314 
315     packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV6_HEADER);
316     packet_ptr -> nx_packet_length -= (ULONG)sizeof(NX_IPV6_HEADER);
317 
318     packet_ptr -> nx_packet_option_offset = 6;
319     next_header_type = (UCHAR)((ip_header_ptr -> nx_ip_header_word_1 >> 8) & 0xFF);
320 
321     /*
322         Search all the extension headers, terminate after upper layer protocols
323        (such as UDP, TCP, ICMP).
324 
325        Also check the order of the optional headers.  Once an out-of-order option
326        field is detected, the search is terminated and an ICMPv6 error message is
327        generated.
328      */
329 
330     /* Initialize start of search for just passed the IP header. */
331     packet_ptr -> nx_packet_option_state = (UCHAR)IPV6_BASE_HEADER;
332     packet_ptr -> nx_packet_destination_header = 0;
333 
334 #ifndef NX_DISABLE_IP_INFO
335 
336     /* Increment the number of packets delivered.  */
337     ip_ptr -> nx_ip_total_packets_delivered++;
338 
339     /* Increment the IP packet bytes received (not including the header).  */
340     ip_ptr -> nx_ip_total_bytes_received +=  packet_ptr -> nx_packet_length;
341 #endif
342 
343     error = _nx_ip_dispatch_process(ip_ptr, packet_ptr, next_header_type);
344 
345     if (error)
346     {
347         _nx_packet_release(packet_ptr);
348     }
349 
350     return;
351 }
352 
353 
354 #endif /* FEATURE_NX_IPV6 */
355 
356