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 #ifdef NX_IPSEC_ENABLE
33 #include "nx_ipsec.h"
34 #endif /* NX_IPSEC_ENABLE */
35
36 #ifndef NX_DISABLE_IPV4
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _nx_ip_packet_send PORTABLE C */
42 /* 6.1.8 */
43 /* AUTHOR */
44 /* */
45 /* Yuxin Zhou, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function prepends an IP header and sends an IP packet to the */
50 /* appropriate link driver. */
51 /* */
52 /* INPUT */
53 /* */
54 /* ip_ptr Pointer to IP control block */
55 /* packet_ptr Pointer to packet to send */
56 /* destination_ip Destination IP address */
57 /* type_of_service Type of service for packet */
58 /* time_to_live Time to live value for packet */
59 /* protocol Protocol being encapsulated */
60 /* fragment Don't fragment bit */
61 /* next_hop_address Next Hop address */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* None */
66 /* */
67 /* CALLS */
68 /* */
69 /* _nx_ip_checksum_compute Compute IP checksum */
70 /* _nx_ip_header_add Add the IP header */
71 /* _nx_ip_route_find Find suitable outgoing */
72 /* _nx_ip_driver_packet_send Send the IP packet */
73 /* _nx_packet_transmit_release Release transmit packet */
74 /* */
75 /* CALLED BY */
76 /* */
77 /* NetX Source Code */
78 /* */
79 /* RELEASE HISTORY */
80 /* */
81 /* DATE NAME DESCRIPTION */
82 /* */
83 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
84 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
85 /* resulting in version 6.1 */
86 /* 08-02-2021 Yuxin Zhou Modified comment(s), and */
87 /* supported TCP/IP offload, */
88 /* added new ip filter, */
89 /* resulting in version 6.1.8 */
90 /* */
91 /**************************************************************************/
_nx_ip_packet_send(NX_IP * ip_ptr,NX_PACKET * packet_ptr,ULONG destination_ip,ULONG type_of_service,ULONG time_to_live,ULONG protocol,ULONG fragment,ULONG next_hop_address)92 VOID _nx_ip_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr,
93 ULONG destination_ip, ULONG type_of_service, ULONG time_to_live,
94 ULONG protocol, ULONG fragment, ULONG next_hop_address)
95 {
96
97 #ifdef NX_IPSEC_ENABLE
98 UINT status = 0;
99 ULONG payload_size;
100 USHORT value;
101 UCHAR is_hw_processed = NX_FALSE;
102 NX_IPV4_HEADER *ip_header_ptr;
103 ULONG checksum;
104 ULONG val;
105 #endif /* NX_IPSEC_ENABLE */
106
107
108 /* Add debug information. */
109 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
110
111 #ifndef NX_DISABLE_IP_INFO
112
113 /* Increment the total send requests counter. */
114 ip_ptr -> nx_ip_total_packet_send_requests++;
115 #endif
116
117 /* Make sure the packet interface is set. */
118 if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr == NX_NULL)
119 {
120
121 #ifndef NX_DISABLE_IP_INFO
122
123 /* Increment the IP invalid packet error. */
124 ip_ptr -> nx_ip_invalid_transmit_packets++;
125 #endif /* !NX_DISABLE_IP_INFO */
126
127 /* Prepend the IP header to the packet. First, make room for the IP header. */
128 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER);
129
130 /* Increase the packet length. */
131 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_IPV4_HEADER);
132
133 /* Release the packet. */
134 _nx_packet_transmit_release(packet_ptr);
135
136 /* Return... nothing more can be done! */
137 return;
138 }
139
140 #ifdef NX_ENABLE_TCPIP_OFFLOAD
141 if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag &
142 NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD)
143 {
144 #ifndef NX_DISABLE_IP_INFO
145
146 /* Increment the IP invalid packet error. */
147 ip_ptr -> nx_ip_invalid_transmit_packets++;
148 #endif
149
150 /* Ignore sending all packets for TCP/IP offload. Release the packet. */
151 _nx_packet_transmit_release(packet_ptr);
152
153 /* Return... nothing more can be done! */
154 return;
155 }
156 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
157
158 #ifdef NX_IPSEC_ENABLE
159 /* Check if this packet is continued after HW crypto engine. */
160 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
161 ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TRANSPORT_MODE &&
162 (packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_AH_PACKET ||
163 packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_ESP_PACKET))
164 {
165 is_hw_processed = NX_TRUE;
166 }
167
168 /* Process this packet in IPsec transport mode? */
169 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
170 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_ESP_PACKET &&
171 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_AH_PACKET &&
172 ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TRANSPORT_MODE)
173 {
174
175 /* Perform IPSec processing and insert IPsec headers before the IP header. */
176 /* Notice that for TCP transmission, a new packet is used to store the encrypted data, while the
177 original TCP packet is put back on to the transmitted queue. */
178 payload_size = packet_ptr -> nx_packet_length;
179 status = _nx_ipsec_ip_output_packet_process(ip_ptr, &packet_ptr, (protocol >> 16), payload_size, &payload_size);
180
181 if ((status != NX_SUCCESS) &&
182 (status != NX_IPSEC_HW_PENDING))
183 {
184
185 /* Install an area for the IP header. This is required by the nx_packet_transmit_release. */
186 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER);
187
188 /* Increase the packet length for the IP header. */
189 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + sizeof(NX_IPV4_HEADER);
190
191 /* IPsec output packet process failed. */
192
193 /* Release the packet. */
194 _nx_packet_transmit_release(packet_ptr);
195
196 return;
197 }
198
199 /* Now set the IPSec protocol. */
200 protocol = (ULONG)((((NX_IPSEC_SA *)packet_ptr -> nx_packet_ipsec_sa_ptr) -> nx_ipsec_sa_protocol) << 16);
201
202 /* Set the DF bit.
203 Transport mode SAs have been defined to not carry fragments (IPv4 or IPv6),RFC 4301 page 66&88..*/
204 fragment = NX_DONT_FRAGMENT;
205 }
206 #endif /* NX_IPSEC_ENABLE */
207
208
209 /* If the packet is processed by HW crypto engine, do not add IP header. */
210 #ifdef NX_IPSEC_ENABLE
211 if (!is_hw_processed)
212 #endif /* NX_IPSEC_ENABLE */
213 {
214
215 /* Add the IP Header to the packet. */
216 _nx_ip_header_add(ip_ptr, packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address,
217 destination_ip, type_of_service, time_to_live, protocol, fragment);
218
219 #ifdef NX_ENABLE_IP_PACKET_FILTER
220 /* Check if the IP packet filter is set. */
221 if (ip_ptr -> nx_ip_packet_filter)
222 {
223
224 /* Yes, call the IP packet filter routine. */
225 if (ip_ptr -> nx_ip_packet_filter((VOID *)(packet_ptr -> nx_packet_prepend_ptr),
226 NX_IP_PACKET_OUT) != NX_SUCCESS)
227 {
228
229 /* Drop the packet. */
230 _nx_packet_transmit_release(packet_ptr);
231 return;
232 }
233 }
234
235 /* Check if the IP packet filter extended is set. */
236 if (ip_ptr -> nx_ip_packet_filter_extended)
237 {
238
239 /* Yes, call the IP packet filter extended routine. */
240 if (ip_ptr -> nx_ip_packet_filter_extended(ip_ptr, packet_ptr, NX_IP_PACKET_OUT) != NX_SUCCESS)
241 {
242
243 /* Drop the packet. */
244 _nx_packet_transmit_release(packet_ptr);
245 return;
246 }
247 }
248 #endif /* NX_ENABLE_IP_PACKET_FILTER */
249 }
250
251 /* If trace is enabled, insert this event into the trace buffer. */
252 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IP_SEND, ip_ptr, destination_ip, packet_ptr, packet_ptr -> nx_packet_length, NX_TRACE_INTERNAL_EVENTS, 0, 0);
253
254
255 #ifdef NX_IPSEC_ENABLE
256
257 if (is_hw_processed)
258 {
259
260 /* Destination IP is unknow after HW crypto engine process. */
261 /* Get destination IP from IP header. */
262 /* Setup the IP header pointer. */
263 ip_header_ptr = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
264
265 /* Fix payload size. */
266 value = (USHORT)(packet_ptr -> nx_packet_length);
267 NX_CHANGE_USHORT_ENDIAN(value);
268
269 /* First clear payload_size field. */
270 ip_header_ptr -> nx_ip_header_word_0 &= 0xFFFF;
271
272 /* Fill payload_size field. */
273 ip_header_ptr -> nx_ip_header_word_0 |= (ULONG)(value << NX_SHIFT_BY_16) & 0xFFFF0000;
274
275 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
276 if (!(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM))
277 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
278 {
279
280 /* Clear checksum in the IP header. */
281 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & 0xFFFF;
282
283 checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4,
284 /* Length is the size of IP header, including options */
285 20,
286 /* IPv4 header checksum does not use src/dest addresses */
287 NULL, NULL);
288
289 val = (ULONG)(~checksum);
290 val = val & NX_LOWER_16_MASK;
291
292 /* Convert to network byte order. */
293 NX_CHANGE_ULONG_ENDIAN(val);
294
295 /* Now store the checksum in the IP header. */
296 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val;
297 }
298 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
299 else
300 {
301 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
302 }
303 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
304 }
305
306 /* Process this packet in IPsec tunnel mode? */
307 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
308 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_ESP_PACKET &&
309 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_AH_PACKET &&
310 ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE)
311 {
312
313
314 /* Perform IPSec processing for tunneling. Insert IPsec headers and encapsulating the IP header. */
315 payload_size = packet_ptr -> nx_packet_length;
316 status = _nx_ipsec_ip_output_packet_process(ip_ptr, &packet_ptr, NX_PROTOCOL_IPV4, payload_size, &payload_size);
317
318 if ((status != NX_SUCCESS) &&
319 (status != NX_IPSEC_HW_PENDING))
320 {
321 /* IPsec output packet process failed. */
322
323 /* Release the packet. */
324 _nx_packet_transmit_release(packet_ptr);
325 }
326
327 /* Tunnel consume the packet. */
328 return;
329 }
330
331 /* Process IPSec on packet requiring AH processing. */
332 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
333 packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_AH_PACKET)
334 {
335
336 status = ip_ptr -> nx_ip_ipsec_authentication_header_transmit(ip_ptr, &packet_ptr, protocol, 1);
337
338 if ((status != NX_SUCCESS) &&
339 (status != NX_IPSEC_HW_PENDING))
340 {
341 /* Release the packet. */
342 _nx_packet_transmit_release(packet_ptr);
343
344 return;
345 }
346 }
347
348 /* HW crypto driver is processing packet. */
349 if (status == NX_IPSEC_HW_PENDING)
350 {
351
352 #ifndef NX_DISABLE_IP_INFO
353
354 /* Decrement the total send requests counter. */
355 ip_ptr -> nx_ip_total_packet_send_requests--;
356 #endif
357 return;
358 }
359
360 #endif
361
362 /* If the next hop address is null, indicates the specified interface is unreached. */
363 if (next_hop_address == 0)
364 {
365
366 /* Check whether the forward feature is enabled. */
367 if (ip_ptr -> nx_ip_forward_packet_process)
368 {
369
370 /* Initialize the interface. */
371 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL;
372
373 /* Figure out the best interface to send the packet on. */
374 _nx_ip_route_find(ip_ptr, destination_ip, &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, &next_hop_address);
375 }
376
377 /* Make sure the packet interface and next hop address are set. */
378 /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */
379 if ((packet_ptr -> nx_packet_address.nx_packet_interface_ptr == NX_NULL) || (next_hop_address == 0))
380 {
381
382 #ifndef NX_DISABLE_IP_INFO
383
384 /* Increment the IP invalid packet error. */
385 ip_ptr -> nx_ip_invalid_transmit_packets++;
386 #endif /* !NX_DISABLE_IP_INFO */
387
388 /* Release the packet. */
389 _nx_packet_transmit_release(packet_ptr);
390
391 /* Return... nothing more can be done! */
392 return;
393 }
394 }
395
396 /* Directly send the packet. */
397 _nx_ip_driver_packet_send(ip_ptr, packet_ptr, destination_ip, fragment, next_hop_address);
398 }
399
400 #endif /* NX_DISABLE_IPV4 */
401
402