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