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