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 
27 /* Include necessary system files.  */
28 
29 #include "nx_api.h"
30 #include "nx_ip.h"
31 #include "nx_ipv6.h"
32 #include "nx_icmp.h"
33 #include "nx_packet.h"
34 
35 
36 #ifdef NX_IPSEC_ENABLE
37 #include "nx_ipsec.h"
38 #endif
39 
40 
41 /**************************************************************************/
42 /*                                                                        */
43 /*  FUNCTION                                               RELEASE        */
44 /*                                                                        */
45 /*    _nx_ip_dispatch_process                             PORTABLE C      */
46 /*                                                           6.1.9        */
47 /*  AUTHOR                                                                */
48 /*                                                                        */
49 /*    Yuxin Zhou, Microsoft Corporation                                   */
50 /*                                                                        */
51 /*  DESCRIPTION                                                           */
52 /*                                                                        */
53 /*    This function goes through IP header and option fields, and         */
54 /*    dispatches into various process routines depending on the header    */
55 /*    options.                                                            */
56 /*                                                                        */
57 /*  INPUT                                                                 */
58 /*                                                                        */
59 /*    ip_ptr                                Pointer to IP instance        */
60 /*    packet_ptr                            Incoming IP packet            */
61 /*    protocol                              The first protocol immediately*/
62 /*                                            following IP header         */
63 /*                                                                        */
64 /*  OUTPUT                                                                */
65 /*                                                                        */
66 /*    Status                                0: do not drop packet         */
67 /*                                          1: drop packet                */
68 /*                                                                        */
69 /*  CALLS                                                                 */
70 /*                                                                        */
71 /*    [nx_ip_icmpv6_packet_process]         ICMPv6 header process         */
72 /*    [nx_ip_tcp_packet_receive]            TCP packet process            */
73 /*    [nx_ip_udp_packet_receive]            UDP packet process            */
74 /*                                            ICMP ping request           */
75 /*    _nx_ipv6_process_hop_by_hop_option    IPv6 hop by hop option        */
76 /*                                            process                     */
77 /*    NX_ICMPV6_SEND_PARAMETER_PROBELM      Send ICMP parameter problem   */
78 /*    _nx_ipv6_process_routing_option       IPv6 routing option process   */
79 /*    _nx_ipv6_process_fragment_option      IPv6 fragment option process  */
80 /*    [nx_ipsec_authentication_header_receive]                            */
81 /*                                          IPSec authentication header   */
82 /*                                            process                     */
83 /*    [nx_ipsec_encapsulating_security_payload_receive                    */
84 /*                                          IPSec encapsulating security  */
85 /*                                            payload process             */
86 /*    (ip_icmp_packet_receive)              Receive a ICMP packet         */
87 /*    (ip_igmp_packet_receive)              Receive a IGMP packet         */
88 /*                                                                        */
89 /*  CALLED BY                                                             */
90 /*                                                                        */
91 /*    Application Code                                                    */
92 /*                                                                        */
93 /*  RELEASE HISTORY                                                       */
94 /*                                                                        */
95 /*    DATE              NAME                      DESCRIPTION             */
96 /*                                                                        */
97 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
98 /*  09-30-2020     Yuxin Zhou               Modified comment(s), fixed    */
99 /*                                            destination header check,   */
100 /*                                            resulting in version 6.1    */
101 /*  10-15-2021     Yuxin Zhou               Modified comment(s), expanded */
102 /*                                            protocols support for raw   */
103 /*                                            packet,                     */
104 /*                                            resulting in version 6.1.9  */
105 /*                                                                        */
106 /**************************************************************************/
_nx_ip_dispatch_process(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT protocol)107 UINT _nx_ip_dispatch_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT protocol)
108 {
109 
110 UINT              drop_packet;
111 
112 #ifdef FEATURE_NX_IPV6
113 NXD_IPV6_ADDRESS *incoming_addr;
114 UINT              next_option_offset;
115 
116 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
117 UINT              nx_packet_option_offset;
118 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE  */
119 #endif /* FEATURE_NX_IPV6 */
120 
121 #ifdef NX_IPSEC_ENABLE
122 UINT              ret;
123 ULONG             next_protocol = 0;
124 NXD_ADDRESS       src_addr, dest_addr;
125 #ifndef NX_DISABLE_IPV4
126 NX_IPV4_HEADER   *ipv4_header;
127 #endif /* NX_DISABLE_IPV4 */
128 #ifdef FEATURE_NX_IPV6
129 NX_IPV6_HEADER   *ipv6_header;
130 NX_ICMPV6_HEADER *icmp_header_ptr;
131 #endif /* FEATURE_NX_IPV6 */
132 #endif /* NX_IPSEC_ENABLE */
133 
134 
135     /* Initialize local variables. */
136     drop_packet = 0;
137 #ifdef FEATURE_NX_IPV6
138     next_option_offset = (UINT)sizeof(NX_IPV6_HEADER);
139     incoming_addr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr;
140 #endif /* FEATURE_NX_IPV6 */
141 
142     /* Parse all options in the packet till we're done or an error is encountered. */
143     while (!drop_packet)
144     {
145 
146         /* Add debug information. */
147         NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
148 
149 #if defined(FEATURE_NX_IPV6) && !defined(NX_DISABLE_ICMPV6_ERROR_MESSAGE)
150         /* Set a local variable for convenience. */
151         nx_packet_option_offset = packet_ptr -> nx_packet_option_offset;
152 #endif /* defined(FEATURE_NX_IPV6) && !defined(NX_DISABLE_ICMPV6_ERROR_MESSAGE) */
153         switch (protocol)
154         {
155 
156 #ifdef FEATURE_NX_IPV6
157         case NX_PROTOCOL_NEXT_HEADER_HOP_BY_HOP:
158 
159             /* This should be the first header; if it is not, this is a malformed packet. */
160             if (packet_ptr -> nx_packet_option_state >= (UCHAR)HOP_BY_HOP_HEADER)
161             {
162 
163                 drop_packet = 1;
164 
165 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
166                 NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 1, nx_packet_option_offset);
167 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE */
168             }
169             else
170             {
171 
172                 /* Start the option header handling. */
173                 packet_ptr -> nx_packet_option_state = (UCHAR)HOP_BY_HOP_HEADER;
174 
175                 /* Dispatch packet to the Option handler. */
176                 drop_packet = _nx_ipv6_process_hop_by_hop_option(ip_ptr, packet_ptr);
177             }
178 
179             break;
180 
181         case NX_PROTOCOL_NEXT_HEADER_DESTINATION:
182 
183             /* Invalid header option if we have already processed 1 destination option. */
184             if (packet_ptr -> nx_packet_destination_header >= 1)
185             {
186 
187                 /* If we already have processed one destination option, we expect this
188                    to be the second one. */
189                 if ((packet_ptr -> nx_packet_option_state < (UCHAR)DESTINATION_HEADER_1) ||
190                     (packet_ptr -> nx_packet_destination_header > 1))
191                 {
192                     drop_packet = 1;
193                 }
194                 else
195                 {
196                     packet_ptr -> nx_packet_option_state = (UCHAR)DESTINATION_HEADER_2;
197                 }
198             }
199             else
200             {
201 
202                 /* This is the first time we encounter a destination header option. */
203                 /* If we are before the routing header option, this must be the 1st one.
204                    Otherwise, it must be the 2nd one. */
205 
206                 if (packet_ptr -> nx_packet_option_state < (UCHAR)ROUTING_HEADER)
207                 {
208 
209                     packet_ptr -> nx_packet_option_state = (UCHAR)DESTINATION_HEADER_1;
210                 }
211                 else
212                 {
213                     packet_ptr -> nx_packet_option_state = (UCHAR)DESTINATION_HEADER_2;
214                 }
215             }
216 
217             packet_ptr -> nx_packet_destination_header++;
218 
219             if (!drop_packet)
220             {
221                 /* Proceed with hop by hop handling if there are no errors. */
222                 drop_packet = _nx_ipv6_process_hop_by_hop_option(ip_ptr, packet_ptr);
223             }
224 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
225             else
226             {
227 
228                 /* Return an error message to the sender of the packet. */
229                 NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 1, nx_packet_option_offset);
230             }
231 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE */
232 
233             break;
234 
235         case NX_PROTOCOL_NEXT_HEADER_ROUTING:
236 
237             if (packet_ptr -> nx_packet_option_state >= (UCHAR)ROUTING_HEADER)
238             {
239 
240 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
241                 NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 1, nx_packet_option_offset);
242 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE */
243 
244                 drop_packet = 1;
245             }
246             else
247             {
248 
249                 packet_ptr -> nx_packet_option_state = (UCHAR)ROUTING_HEADER;
250 
251                 drop_packet = _nx_ipv6_process_routing_option(ip_ptr, packet_ptr);
252             }
253             break;
254 
255         case NX_PROTOCOL_NEXT_HEADER_FRAGMENT:
256 
257 #ifndef NX_DISABLE_FRAGMENTATION
258             if (packet_ptr -> nx_packet_option_state >= (UCHAR)FRAGMENT_HEADER)
259             {
260 #endif /* NX_DISABLE_FRAGMENTATION */
261 
262 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
263                 NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 1, nx_packet_option_offset);
264 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE */
265 
266                 drop_packet = 1;
267 #ifndef NX_DISABLE_FRAGMENTATION
268             }
269             else
270             {
271 
272                 packet_ptr -> nx_packet_option_state = (UCHAR)FRAGMENT_HEADER;
273 
274 #ifdef NX_ENABLE_LOW_WATERMARK
275                 if (packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_available >=
276                     packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_low_watermark)
277 #endif
278                 {
279                     drop_packet = _nx_ipv6_process_fragment_option(ip_ptr, packet_ptr);
280                 }
281 #ifdef NX_ENABLE_LOW_WATERMARK
282                 else
283                 {
284                     drop_packet = NX_POOL_ERROR;
285                 }
286 #endif
287 
288                 if (drop_packet != NX_CONTINUE)
289                 {
290 
291                     /* Special case: do not further process the packet here.
292                        Once all fragments are received, we will continue processing the headers. */
293                     return(drop_packet);
294                 }
295                 else
296                 {
297 
298                     /* Continue processing the packet. */
299                     drop_packet = 0;
300                 }
301             }
302 #endif /* NX_DISABLE_FRAGMENTATION */
303             break;
304 
305         case NX_PROTOCOL_NO_NEXT_HEADER:
306 
307             drop_packet = 1;
308             break;
309 
310 #endif /* FEATURE_NX_IPV6 */
311 
312         case NX_PROTOCOL_NEXT_HEADER_AUTHENTICATION:
313 
314 #ifdef NX_IPSEC_ENABLE
315             if (ip_ptr -> nx_ip_ipsec_authentication_header_receive == NX_NULL)
316             {
317 
318                 /* If IPsec is not enabled by the application, drop the packet. */
319                 return(1);
320             }
321             else
322             {
323 
324                 ret =  ip_ptr -> nx_ip_ipsec_authentication_header_receive(ip_ptr, packet_ptr, &next_protocol, &packet_ptr);
325 
326                 if (ret == NX_SUCCESS)
327                 {
328 
329                     /* Indicate that IPSec consumed the packet. */
330                     return(0);
331                 }
332 
333                 if (ret != NX_IPSEC_PKT_CONT)
334                 {
335 
336                     return(1);
337                 }
338 
339                 /* Continue processing the packet if status = NX_IPSEC_PKT_CONT */
340             }
341 #else /* NX_IPSEC_ENABLE */
342 
343             /* Drop this packet if IPsec module is not present. */
344             drop_packet = 1;
345 #endif /* NX_IPSEC_ENABLE */
346 
347             break;
348 
349         case NX_PROTOCOL_NEXT_HEADER_ENCAP_SECURITY:
350 
351 #ifdef NX_IPSEC_ENABLE
352             if (ip_ptr -> nx_ip_ipsec_encapsulating_security_payload_receive == NX_NULL)
353             {
354 
355                 /* If IPsec is not enabled by the application, drop the packet. */
356                 return(1);
357             }
358             else
359             {
360 
361                 ret =  ip_ptr -> nx_ip_ipsec_encapsulating_security_payload_receive(ip_ptr, packet_ptr, &next_protocol, &packet_ptr);
362 
363                 if (ret == NX_SUCCESS)
364                 {
365 
366                     /* Indicate IPSec consumed the packet. */
367                     return(0);
368                 }
369 
370                 if (ret != NX_IPSEC_PKT_CONT)
371                 {
372                     return(1);
373                 }
374 
375                 /* Continue processing the packet if status = NX_IPSEC_PKT_CONT */
376             }
377             break;
378 
379 #else /* NX_IPSEC_ENABLE */
380             /* Drop this packet if IPsec module is not present. */
381             return(1);
382 #endif /* NX_IPSEC_ENABLE */
383 
384         default:
385 
386             /* Not part of the IP headers. */
387 #ifdef NX_IPSEC_ENABLE
388             /* Check ingress_sa for packet that is not ESP or AH.  */
389             if (packet_ptr -> nx_packet_ipsec_sa_ptr == NX_NULL)
390             {
391 
392                 /* Get source and destination address.  */
393 #ifdef FEATURE_NX_IPV6
394                 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
395                 {
396                     ipv6_header = (NX_IPV6_HEADER *)(packet_ptr -> nx_packet_ip_header);
397 
398                     src_addr.nxd_ip_version = NX_IP_VERSION_V6;
399                     dest_addr.nxd_ip_version = NX_IP_VERSION_V6;
400 
401                     COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_source_ip,
402                                       src_addr.nxd_ip_address.v6);
403 
404 
405                     COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_destination_ip,
406                                       dest_addr.nxd_ip_address.v6);
407                 }
408                 else
409 #endif /* FEATURE_NX_IPV6 */
410                 {
411 #ifndef NX_DISABLE_IPV4
412                     ipv4_header = (NX_IPV4_HEADER *)(packet_ptr -> nx_packet_ip_header);
413 
414                     src_addr.nxd_ip_version = NX_IP_VERSION_V4;
415                     dest_addr.nxd_ip_version = NX_IP_VERSION_V4;
416 
417                     src_addr.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_source_ip;
418                     dest_addr.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_destination_ip;
419 #endif /* NX_DISABLE_IPV4 */
420                 }
421 
422                 if (_nx_ipsec_sa_ingress_lookup(ip_ptr, &src_addr, &dest_addr, 0, (UCHAR)protocol,
423                                                 NX_NULL, packet_ptr -> nx_packet_prepend_ptr) != NX_IPSEC_TRAFFIC_BYPASS)
424                 {
425 #ifdef FEATURE_NX_IPV6
426                     /* Check whether it is a NA packet.  */
427                     if (protocol == NX_PROTOCOL_ICMPV6)
428                     {
429 
430                         /* Bypass NA packet. */
431                         icmp_header_ptr = (NX_ICMPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
432                         if (icmp_header_ptr -> nx_icmpv6_header_type != NX_ICMPV6_NEIGHBOR_ADVERTISEMENT_TYPE)
433                         {
434                             return(NX_INVALID_PACKET);
435                         }
436                     }
437                     else
438                     {
439 #endif /* FEATURE_NX_IPV6 */
440                         return(NX_INVALID_PACKET);
441 #ifdef FEATURE_NX_IPV6
442                     }
443 #endif /* FEATURE_NX_IPV6 */
444                 }
445             }
446             /* For IPsec tunnel mode, next protocol is checked here. */
447             else if (((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE)
448             {
449                 if (_nx_ipsec_sa_ingress_selector_check(packet_ptr -> nx_packet_prepend_ptr,
450                                                         (UCHAR)protocol,
451                                                         ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_selector_ptr) == NX_IPSEC_TRAFFIC_DROP)
452                 {
453                     _nx_packet_release(packet_ptr);     /* Consume the packet */
454                     return(NX_INVALID_PACKET);
455                 }
456             }
457 #endif /* NX_IPSEC_ENABLE */
458 
459 #if defined(NX_ENABLE_IP_RAW_PACKET_ALL_STACK) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER)
460             if ((ip_ptr -> nx_ip_raw_ip_processing) && (ip_ptr -> nx_ip_raw_packet_filter))
461             {
462 
463                 /* Let RAW packet filter handler filter all incoming packets.  */
464                 if ((ip_ptr -> nx_ip_raw_ip_processing)(ip_ptr, protocol << 16, packet_ptr) == NX_SUCCESS)
465                 {
466                     /* No need to free the packet as it is consumed by the raw process */
467                     return(0);
468                 }
469             }
470 #endif /* defined(NX_ENABLE_IP_RAW_PACKET_ALL_STACK) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER) */
471 
472             if (protocol == NX_PROTOCOL_TCP)
473             {
474 #ifdef FEATURE_NX_IPV6
475                 if ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) ||
476                     ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) &&
477                      (incoming_addr -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID)))
478                 {
479 #endif /* FEATURE_NX_IPV6 */
480 
481                     /* Check that the host is enabled for TCP. */
482                     if (ip_ptr -> nx_ip_tcp_packet_receive)
483                     {
484 
485                         /* Dispatch the packet to the TCP packet handler. */
486                         (ip_ptr -> nx_ip_tcp_packet_receive)(ip_ptr, packet_ptr);
487 
488                         /* No need to free the packet as it is consumed by TCP packet receive.  */
489                         return(0);
490                     }
491 #ifdef FEATURE_NX_IPV6
492                 }
493 #endif /* FEATURE_NX_IPV6 */
494 
495                 /* TCP is not enabled.  Drop the packet. */
496                 drop_packet = 1;
497             }
498 
499 #ifdef FEATURE_NX_IPV6
500             else if ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) &&
501                      (protocol == NX_PROTOCOL_ICMPV6))
502             {
503 
504                 /* Check that ICMPv6 is enabled for this IP instance.  */
505                 if (ip_ptr -> nx_ip_icmpv6_packet_process != NX_NULL)
506                 {
507 
508                     /* Forward to the ICMPv6 packet handler. */
509                     ip_ptr -> nx_ip_icmpv6_packet_process(ip_ptr, packet_ptr);
510 
511                     /*  no need to free packet as it is consumed by ICMP packet receive.  */
512                     return(0);
513                 }
514 
515                 /* ICMPv6 is not enabled.  Drop the packet. */
516                 drop_packet = 1;
517             }
518 #endif /* FEATURE_NX_IPV6 */
519 
520 #ifndef NX_DISABLE_IPV4
521             else if ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) &&
522                      (protocol == NX_PROTOCOL_ICMP))
523             {
524 
525                 /* Check that ICMP is enabled for this IP instance.  */
526                 if (ip_ptr -> nx_ip_icmp_packet_receive != NX_NULL)
527                 {
528 
529                     /* Yes, a ICMP packet is present, dispatch to the appropriate ICMP handler
530                        if present.  */
531                     ip_ptr -> nx_ip_icmp_packet_receive(ip_ptr, packet_ptr);
532                     return(0);
533                 }
534 
535                 /* ICMP is not enabled. Drop the packet. */
536                 drop_packet = 1;
537             }
538             else if ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) &&
539                      (protocol == NX_PROTOCOL_IGMP))
540             {
541                 if (ip_ptr -> nx_ip_igmp_packet_receive != NX_NULL)
542                 {
543 
544                     /* Yes, a IGMP packet is present, dispatch to the appropriate ICMP handler
545                        if present.  */
546                     ip_ptr -> nx_ip_igmp_packet_receive(ip_ptr, packet_ptr);
547                     return(0);
548                 }
549 
550                 /* IGMP is not enabled. Drop the packet.  */
551                 drop_packet = 1;
552             }
553 #endif /* NX_DISABLE_IPV4 */
554             else if (protocol == NX_PROTOCOL_UDP)
555             {
556 
557 #ifdef FEATURE_NX_IPV6
558                 if ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) ||
559                     ((packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) &&
560                      (incoming_addr -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID)))
561                 {
562 #endif /* FEATURE_NX_IPV6 */
563 
564                     /* Check the host is enabled for UDP packet handling. */
565                     if (ip_ptr -> nx_ip_udp_packet_receive)
566                     {
567 
568                         /* Dispatch the packet to the UDP handler. */
569                         (ip_ptr -> nx_ip_udp_packet_receive)(ip_ptr, packet_ptr);
570 
571                         /* No need to free the packet as it is consumed by UDP packet receive.  */
572                         return(0);
573                     }
574 #ifdef FEATURE_NX_IPV6
575                 }
576 #endif /* FEATURE_NX_IPV6 */
577 
578                 /* UDP is not enabled.  Drop the packet. */
579                 drop_packet = 1;
580             }
581             else
582             {
583                 if (ip_ptr -> nx_ip_raw_ip_processing)
584                 {
585 #if defined(NX_ENABLE_IP_RAW_PACKET_ALL_STACK) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER)
586                     if (ip_ptr -> nx_ip_raw_packet_filter == NX_NULL)
587 #endif /* defined(NX_ENABLE_IP_RAW_PACKET_ALL_STACK) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER) */
588                     {
589                         if ((ip_ptr -> nx_ip_raw_ip_processing)(ip_ptr, protocol << 16, packet_ptr) == NX_SUCCESS)
590                         {
591                             /* No need to free the packet as it is consumed by the raw process */
592                             return(0);
593                         }
594                     }
595                 }
596 
597 #if !defined(NX_DISABLE_IPV4) && !defined(NX_DISABLE_ICMPV4_ERROR_MESSAGE)
598                 /* Unknown protocol, send ICMP Destination protocol unreachable. */
599                 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
600                 {
601                     NX_ICMPV4_SEND_DEST_UNREACHABLE(ip_ptr, packet_ptr, NX_ICMP_PROTOCOL_UNREACH_CODE);
602                 }
603 #endif /* !NX_DISABLE_IPV4 && !NX_DISABLE_ICMPV4_ERROR_MESSAGE  */
604 
605 #ifdef FEATURE_NX_IPV6
606                 /* Unknown option.  Send ICMP Parameter problem and discard the packet. */
607                 /* RFC 2460, page 7 */
608 #ifndef NX_DISABLE_ICMPV6_ERROR_MESSAGE
609                 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
610                 {
611                     NX_ICMPV6_SEND_PARAMETER_PROBLEM(ip_ptr, packet_ptr, 1, nx_packet_option_offset);
612                 }
613 #endif /* NX_DISABLE_ICMPV6_ERROR_MESSAGE */
614 #endif /* FEATURE_NX_IPV6 */
615 
616 #ifndef NX_DISABLE_IP_INFO
617 
618                 /* Increment the IP unknown protocol count.  */
619                 ip_ptr -> nx_ip_unknown_protocols_received++;
620 
621 #endif /* NX_DISABLE_IP_INFO */
622 
623 
624                 drop_packet = 1;
625             }
626             break;
627         }
628 
629 
630         /* If the previous header is processed without errors, move on to the next optional
631            header. */
632         if (!drop_packet)
633         {
634 
635 #ifdef FEATURE_NX_IPV6
636         NX_IPV6_HEADER_OPTION *option;
637         ULONG                  option_hdr_len;
638 #endif /* FEATURE_NX_IPV6 */
639 
640 #ifdef NX_IPSEC_ENABLE
641 
642             if (protocol == NX_PROTOCOL_NEXT_HEADER_ENCAP_SECURITY ||
643                 protocol == NX_PROTOCOL_NEXT_HEADER_AUTHENTICATION)
644             {
645 
646                 /* After ESP and AH processing, ESP and AH hdr are removed. */
647                 protocol = next_protocol;
648                 continue;
649             }
650 #endif  /* NX_IPSEC_ENABLE */
651 
652 #ifdef FEATURE_NX_IPV6
653             if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
654             {
655 
656                 /* Find the option we just processed. */
657                 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
658                 option = (NX_IPV6_HEADER_OPTION *)packet_ptr -> nx_packet_prepend_ptr;
659 
660                 /* Check the protocol.  */
661                 if (protocol == NX_PROTOCOL_NEXT_HEADER_FRAGMENT)
662                 {
663 
664                     /* Fixed length for fragment option, the field of option length is reserved.  */
665                     option_hdr_len = sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION);
666                 }
667                 else
668                 {
669 
670                     /* Compute the current option length. */
671                     /* For other IPv6 optional headers, hdr_ext_len is expressed in 64-bit words. */
672                     option_hdr_len = (ULONG)((option -> nx_ipv6_header_option_ext_length + 1) << 3);
673                 }
674 
675                 /* Obtain the next option header type. */
676                 protocol = option -> nx_ipv6_header_option_next_header;
677 
678                 if (((ALIGN_TYPE)(packet_ptr -> nx_packet_prepend_ptr) + option_hdr_len) <
679                     (ALIGN_TYPE)(packet_ptr -> nx_packet_append_ptr))
680                 {
681 
682                     /* Advance to the next header. */
683                     packet_ptr -> nx_packet_prepend_ptr += option_hdr_len;
684                     packet_ptr -> nx_packet_length      -= option_hdr_len;
685                 }
686                 else
687                 {
688 
689                     drop_packet = 1;
690                 }
691 
692                 /*
693                    Advance the nx_packet_option_offset as well.
694                    Option Offset is used when constructing ICMPv6 parameter problem message.
695                  */
696 
697                 packet_ptr -> nx_packet_option_offset = (USHORT)next_option_offset;
698 
699                 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
700                 next_option_offset = (UINT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_ip_header);
701             }
702 #endif /* FEATURE_NX_IPV6 */
703         }
704         else
705         {
706 #ifndef NX_DISABLE_IP_INFO
707 
708             /* Decrement the number of packets delivered.  */
709             ip_ptr -> nx_ip_total_packets_delivered--;
710 
711             /* Decrement the IP packet bytes received (not including the header).  */
712             ip_ptr -> nx_ip_total_bytes_received -=  packet_ptr -> nx_packet_length;
713 
714             /* Increment the IP receive packets dropped count.  */
715             ip_ptr -> nx_ip_receive_packets_dropped++;
716 #endif /* NX_DISABLE_IP_INFO */
717         }
718     }
719 
720     return(drop_packet);
721 }
722 
723