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