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