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 
31 #ifndef NX_DISABLE_IPV4
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_ip_forward_packet_process                       PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function attempts to forward the IP packet to the destination  */
45 /*    IP by using the NetX send packet routine.  Note that the IP header  */
46 /*    is still intact prior to the packet.                                */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    ip_ptr                                Pointer to IP control block   */
51 /*    packet_ptr                            Pointer to packet to forward  */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _nx_packet_release                    Packet release                */
60 /*    _nx_packet_data_adjust                Adjust the packet data to fill*/
61 /*                                            the specified header        */
62 /*    _nx_ip_driver_packet_send             Send the IP packet            */
63 /*    _nx_ip_fragment_forward_packet        Fragment the forward packet   */
64 /*    _nx_ip_packet_deferred_receive        IP deferred receive packet    */
65 /*                                            processing                  */
66 /*    _nx_ip_route_find                     Find suitable outgoing        */
67 /*                                            interface                   */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    _nx_ip_packet_receive                 Receive IP packet             */
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_ip_forward_packet_process(NX_IP * ip_ptr,NX_PACKET * packet_ptr)82 VOID  _nx_ip_forward_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
83 {
84 
85 NX_IPV4_HEADER *ip_header_ptr;
86 NX_INTERFACE   *outgoing_interface = NX_NULL;
87 ULONG           next_hop_address = 0;
88 ULONG           destination_ip;
89 ULONG           time_to_live;
90 ULONG           fragment_bit;
91 ULONG           status;
92 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
93 UINT            compute_checksum = 1;
94 #endif
95 ULONG           checksum;
96 ULONG           old_m;
97 ULONG           new_m;
98 
99 
100     /* The NetX IP forwarding consists of simply sending the same packet out through
101        the internal send routine.  Applications may choose to modify this code or
102        replace the nx_ip_forward_packet_process pointer in the IP structure to point
103        at an application-specific routine for forwarding.  */
104 
105     /* It's assumed that the IP header is still present in front of the packet.  Position
106        backwards to access it.  */
107     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
108     ip_header_ptr =  (NX_IPV4_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
109 
110     /* Check for if the destination address is Class D address.  */
111     if ((ip_header_ptr -> nx_ip_header_destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE)
112     {
113 
114         /* Discard the packet.  */
115         _nx_packet_release(packet_ptr);
116         return;
117     }
118 
119     /* Determine if source address or destination addrss is link-local address(169.254/16 Hexadecimal:0xA9FE0000).  */
120     if (((ip_header_ptr -> nx_ip_header_source_ip & 0xFFFF0000) == 0xA9FE0000) ||
121         ((ip_header_ptr -> nx_ip_header_destination_ip & 0xFFFF0000) == 0xA9FE0000))
122     {
123 
124         /* Discard the packet.  */
125         _nx_packet_release(packet_ptr);
126         return;
127     }
128 
129     /* Check whether find the correct forwarding interface.  */
130     if (_nx_ip_route_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &outgoing_interface, &next_hop_address) == NX_SUCCESS)
131     {
132 
133         /* If the forwarding interface is same as the receiving interface,
134            According to the RFC 792 Redirect Message on page 12,
135            send a redirect message to source address. */
136 
137         /* Update the forwarding interface. */
138         /*lint -e{644} suppress variable might not be initialized, since "outgoing_interface" was initialized as long as return value is NX_SUCCESS. */
139         packet_ptr -> nx_packet_ip_interface = outgoing_interface;
140 
141         /* Get the relevant information from original packet.  */
142         destination_ip = ip_header_ptr -> nx_ip_header_destination_ip;
143         time_to_live = ((ip_header_ptr -> nx_ip_header_word_2 & NX_IP_TIME_TO_LIVE_MASK) >> NX_IP_TIME_TO_LIVE_SHIFT) - 1;
144         fragment_bit = (ip_header_ptr -> nx_ip_header_word_1 & NX_DONT_FRAGMENT);
145 
146         /* If the TTL is 0, discard the packet.  */
147         if (!time_to_live)
148         {
149 
150 #ifndef NX_DISABLE_IP_INFO
151 
152             /* Increment the IP receive packets dropped count.  */
153             ip_ptr -> nx_ip_receive_packets_dropped++;
154 #endif
155 
156             /* No correct forwarding interface, toss the packet!  */
157             _nx_packet_release(packet_ptr);
158             return;
159         }
160 
161         /* Update the TTL value.  */
162         ip_header_ptr -> nx_ip_header_word_2 = (ip_header_ptr -> nx_ip_header_word_2 - 0x01000000);
163 
164         /* Update the checksum, according to the RFC1624 page2, Eqn.3.
165            HC  - old checksum in header
166            HC' - new checksum in header
167            m   - old value of a 16-bit field
168            m'  - new value of a 16-bit field
169            HC' = ~(C + (-m) + m')
170             = ~(~HC + ~m + m') */
171 
172 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
173         if (packet_ptr -> nx_packet_ip_interface -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
174         {
175             compute_checksum = 0;
176         }
177 #endif
178 
179 
180 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
181         /* Check whether the destination IP address matched with one interface of IP instance.  */
182         /*lint -e{613} suppress possible use of null pointer, since "outgoing_interface" was set in _nx_ip_route_find. */
183         if (outgoing_interface -> nx_interface_ip_address == destination_ip)
184         {
185 
186 
187             /* Clear the capability flag.  */
188             packet_ptr -> nx_packet_interface_capability_flag &= (ULONG)(~NX_INTERFACE_CAPABILITY_IPV4_RX_CHECKSUM);
189 
190 
191             /* Set the computer checksum flag.  */
192             compute_checksum = 1;
193         }
194 #endif
195 
196 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
197         /* Computer the checksum.  */
198         /*lint -e{774} suppress boolean always evaluates to True, since it is necessary with NX_ENABLE_INTERFACE_CAPABILITY macro. */
199         if (compute_checksum)
200         {
201 #endif
202             /* Get the old checksum (HC) in header. */
203             checksum = ip_header_ptr -> nx_ip_header_word_2 & NX_LOWER_16_MASK;
204 
205             /* Get the new TTL(m') in the header. */
206             new_m = (ip_header_ptr -> nx_ip_header_word_2 & 0xFFFF0000) >> 16;
207 
208             /* Get the old TTL(m). */
209             old_m = new_m + 0x0100;
210 
211             /* Update the checksum, get the new checksum(HC'),
212                The new_m is ULONG value, so need get the lower value after invert. */
213             checksum = ((~checksum) & 0xFFFF) + ((~old_m) & 0xFFFF) + new_m;
214 
215             /* Fold a 4-byte value into a two byte value */
216             checksum = (checksum >> 16) + (checksum & 0xFFFF);
217 
218             /* Do it again in case previous operation generates an overflow */
219             checksum = (checksum >> 16) + (checksum & 0xFFFF);
220 
221             /* Now store the new checksum in the IP header.  */
222             ip_header_ptr -> nx_ip_header_word_2 =  ((ip_header_ptr -> nx_ip_header_word_2 & 0xFFFF0000) | ((~checksum) & NX_LOWER_16_MASK));
223 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
224         }
225         else
226         {
227             /* Set the checksum to 0.  */
228             ip_header_ptr -> nx_ip_header_word_2 =  (ip_header_ptr -> nx_ip_header_word_2 & 0xFFFF0000);
229             packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
230         }
231 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
232 
233         /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
234            swap the endian of the IP header.  */
235         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
236         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
237         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
238         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
239         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
240 
241         /* Check whether the destination IP address matched with one interface of IP instance.  */
242         /*lint -e{613} suppress possible use of null pointer, since "outgoing_interface" was set in _nx_ip_route_find. */
243         if (outgoing_interface -> nx_interface_ip_address == destination_ip)
244         {
245 
246             /* Forward this packet to correct interface.  */
247             _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
248             return;
249         }
250         else
251         {
252 
253             /* Check if the packet can fill physical header.  */
254             status = _nx_packet_data_adjust(packet_ptr, NX_PHYSICAL_HEADER);
255 
256             /* Check status.  */
257             if (status)
258             {
259 
260                 /* Release the packet. */
261                 _nx_packet_release(packet_ptr);
262                 return;
263             }
264 
265             /* Determine if fragmentation is needed.  */
266             if (packet_ptr -> nx_packet_length <= packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size)
267             {
268 
269                 /* Call the function to directly forward the packet.  */
270                 /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */
271                 _nx_ip_driver_packet_send(ip_ptr, packet_ptr, destination_ip, fragment_bit, next_hop_address);
272                 return;
273             }
274 #ifndef NX_DISABLE_FRAGMENTATION
275             else
276             {
277                 /* Check the DF bit flag.  */
278                 if ((ip_ptr -> nx_ip_fragment_processing) && (!(fragment_bit & NX_DONT_FRAGMENT)))
279                 {
280 
281                     /* Fragment and send the packet.  */
282                     _nx_ip_fragment_forward_packet(ip_ptr, packet_ptr, destination_ip, NX_FRAGMENT_OKAY, next_hop_address);
283                     return;
284                 }
285             }
286 #endif
287         }
288     }
289 
290     /* No correct forwarding interface, toss the packet!  */
291     _nx_packet_release(packet_ptr);
292     return;
293 }
294 
295 #endif /* NX_DISABLE_IPV4 */
296 
297