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