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