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_igmp.h"
30
31 #ifdef NX_IPSEC_ENABLE
32 #include "nx_ipsec.h"
33 #endif /* NX_IPSEC_ENABLE */
34
35 #ifndef NX_DISABLE_IPV4
36 /**************************************************************************/
37 /* */
38 /* FUNCTION RELEASE */
39 /* */
40 /* _nx_ip_header_add PORTABLE C */
41 /* 6.3.0 */
42 /* AUTHOR */
43 /* */
44 /* Yuxin Zhou, Microsoft Corporation */
45 /* */
46 /* DESCRIPTION */
47 /* */
48 /* This function prepends an IP header. */
49 /* */
50 /* INPUT */
51 /* */
52 /* ip_ptr Pointer to IP control block */
53 /* packet_ptr Pointer to packet to send */
54 /* source_ip Source IP address */
55 /* destination_ip Destination IP address */
56 /* type_of_service Type of service for packet */
57 /* time_to_live Time to live value for packet */
58 /* protocol Protocol being encapsulated */
59 /* fragment Don't fragment bit */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* NX_SUCCESS Added the header successfully */
64 /* NX_UNDERFLOW Invalid packet header */
65 /* */
66 /* CALLS */
67 /* */
68 /* _nx_ip_checksum_compute Compute IP checksum */
69 /* _nx_packet_transmit_release Release transmit packet */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* NetX Source Code */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
80 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* 08-02-2021 Yuxin Zhou Modified comment(s), and */
83 /* supported TCP/IP offload, */
84 /* resulting in version 6.1.8 */
85 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
86 /* supported random IP id, */
87 /* resulting in version 6.3.0 */
88 /* */
89 /**************************************************************************/
_nx_ip_header_add(NX_IP * ip_ptr,NX_PACKET * packet_ptr,ULONG source_ip,ULONG destination_ip,ULONG type_of_service,ULONG time_to_live,ULONG protocol,ULONG fragment)90 UINT _nx_ip_header_add(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG source_ip, ULONG destination_ip,
91 ULONG type_of_service, ULONG time_to_live, ULONG protocol, ULONG fragment)
92 {
93 ULONG router_alert = 0;
94 NX_IPV4_HEADER *ip_header_ptr;
95 ULONG checksum;
96 #if defined(NX_DISABLE_IP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
97 UINT compute_checksum = 1;
98 #endif /* defined(NX_DISABLE_IP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
99 ULONG val;
100
101 #ifdef NX_ENABLE_IP_ID_RANDOMIZATION
102 NX_PARAMETER_NOT_USED(ip_ptr);
103 #endif /* NX_ENABLE_IP_ID_RANDOMIZATION */
104
105 #ifndef NX_DISABLE_IGMPV2
106 /* Check IGMPv2 protocol. */
107 if ((protocol == NX_IP_IGMP) && (ip_ptr -> nx_ip_igmp_router_version == NX_IGMP_HOST_VERSION_2))
108 {
109 router_alert = 4;
110 }
111 #endif
112
113 /* Prepend the IP header to the packet. First, make room for the IP header. */
114 packet_ptr -> nx_packet_prepend_ptr = (packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER)) - router_alert;
115
116 /* Increase the packet length. */
117 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_IPV4_HEADER) + router_alert;
118
119 /* Assert prepend pointer is no less than data start pointer. */
120 /*lint -e{946} suppress pointer subtraction, since it is necessary. */
121 NX_ASSERT(packet_ptr -> nx_packet_prepend_ptr >= packet_ptr -> nx_packet_data_start);
122
123 /* Setup the IP header pointer. */
124 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
125 ip_header_ptr = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
126 packet_ptr -> nx_packet_ip_header = packet_ptr -> nx_packet_prepend_ptr;
127 packet_ptr -> nx_packet_ip_header_length = (UCHAR)(packet_ptr -> nx_packet_ip_header_length +
128 sizeof(NX_IPV4_HEADER) + router_alert);
129
130 /* Determine if this is an identical copy for TCP retransmission.
131 RFC1122, Section3.2.1.5, Page32-33. RFC1122, Section4.2.2.15, Page90-91. */
132 if (packet_ptr -> nx_packet_identical_copy == NX_TRUE)
133 {
134
135 /* Yes, this an identical copy for TCP retransmission.
136 The IP header has been added, return. */
137 return(NX_SUCCESS);
138 }
139
140 /* Build the IP header. */
141
142 #ifndef NX_DISABLE_IGMPV2
143 if (router_alert)
144 {
145
146 /* Build the first 32-bit word of the IP header. */
147 ip_header_ptr -> nx_ip_header_word_0 = (ULONG)((NX_IP_VERSION_V4 << 28) |
148 (NX_IP_HEADER_LENGTH_ENCODE_6 << 24) |
149 type_of_service |
150 (0xFFFF & packet_ptr -> nx_packet_length));
151 }
152 else
153 #endif
154 {
155
156 /* Build the first 32-bit word of the IP header. */
157 ip_header_ptr -> nx_ip_header_word_0 = (NX_IP_VERSION | type_of_service | (0xFFFF & packet_ptr -> nx_packet_length));
158 }
159
160 /* Build the second 32-bit word of the IP header. */
161 #ifdef NX_ENABLE_IP_ID_RANDOMIZATION
162 ip_header_ptr -> nx_ip_header_word_1 = (((ULONG)NX_RAND()) << NX_SHIFT_BY_16) | fragment;
163 #else
164 ip_header_ptr -> nx_ip_header_word_1 = (ip_ptr -> nx_ip_packet_id++ << NX_SHIFT_BY_16) | fragment;
165 #endif /* NX_ENABLE_IP_ID_RANDOMIZATION */
166
167 /* Build the third 32-bit word of the IP header. */
168 ip_header_ptr -> nx_ip_header_word_2 = ((time_to_live << NX_IP_TIME_TO_LIVE_SHIFT) | protocol);
169
170 /* Place the source IP address in the IP header. */
171 ip_header_ptr -> nx_ip_header_source_ip = source_ip;
172
173 /* Place the destination IP address in the IP header. */
174 ip_header_ptr -> nx_ip_header_destination_ip = destination_ip;
175
176 #ifndef NX_DISABLE_IGMPV2
177 if (router_alert)
178 {
179
180 /* Append Router Alert Option. */
181 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
182 *((ULONG *)(packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IPV4_HEADER))) = (NX_IP_OPTION_COPY_FLAG |
183 NX_IP_OPTION_CLASS |
184 NX_IP_OPTION_ROUTER_ALERT_NUMBER |
185 NX_IP_OPTION_ROUTER_ALERT_LENGTH |
186 NX_IP_OPTION_ROUTER_ALERT_VALUE);
187 }
188 #endif
189
190 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
191 swap the endian of the IP header. */
192 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
193 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
194 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
195 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
196 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
197 #ifndef NX_DISABLE_IGMPV2
198 if (router_alert)
199 {
200
201 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
202 NX_CHANGE_ULONG_ENDIAN(*((ULONG *)(packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IPV4_HEADER))));
203 }
204 #endif
205
206 #ifdef NX_DISABLE_IP_TX_CHECKSUM
207 compute_checksum = 0;
208 #endif /* NX_DISABLE_IP_TX_CHECKSUM */
209 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
210 if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
211 {
212 compute_checksum = 0;
213 }
214 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
215 #ifdef NX_IPSEC_ENABLE
216 if (packet_ptr -> nx_packet_ipsec_sa_ptr != NX_NULL)
217 {
218 if ((((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE) &&
219 (((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_encryption_method != NX_CRYPTO_NONE))
220 {
221 compute_checksum = 1;
222 }
223 }
224
225 #endif /* NX_IPSEC_ENABLE */
226
227 #if defined(NX_DISABLE_IP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
228 if (compute_checksum)
229 #endif /* defined(NX_DISABLE_IP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
230 {
231 checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4,
232 /* Length is the size of IP header, including options */
233 (UINT)(20 + router_alert),
234 /* IPv4 header checksum does not use src/dest addresses */
235 NULL, NULL);
236
237 val = (ULONG)(~checksum);
238 val = val & NX_LOWER_16_MASK;
239
240 /* Convert to network byte order. */
241 NX_CHANGE_ULONG_ENDIAN(val);
242
243 /* Now store the checksum in the IP header. */
244 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val;
245 }
246 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
247 else
248 {
249 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
250 }
251 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
252
253 /* Return... */
254 return(NX_SUCCESS);
255 }
256
257 #endif /* NX_DISABLE_IPV4 */
258
259