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