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