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 /**   Packet Pool Management (Packet)                                     */
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_packet.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _nx_packet_data_append                              PORTABLE C      */
36 /*                                                           6.1          */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Yuxin Zhou, Microsoft Corporation                                   */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function copies the specified data to the end of the specified */
44 /*    packet.  Additional packets are allocated from the specified pool   */
45 /*    if needed.                                                          */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    packet_ptr                            Pointer to packet to append to*/
50 /*    data_start                            Pointer to start of the data  */
51 /*    data_size                             Number of bytes to append     */
52 /*    pool_ptr                              Pool to allocate packet from  */
53 /*    wait_option                           Suspension option             */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Completion status             */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _nx_packet_allocate                   Allocate data packet          */
62 /*    _nx_packet_release                    Release data packet           */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application Code                                                    */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
73 /*  09-30-2020     Yuxin Zhou               Modified comment(s), and      */
74 /*                                            verified memcpy use cases,  */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_nx_packet_data_append(NX_PACKET * packet_ptr,VOID * data_start,ULONG data_size,NX_PACKET_POOL * pool_ptr,ULONG wait_option)78 UINT  _nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size,
79                              NX_PACKET_POOL *pool_ptr, ULONG wait_option)
80 {
81 
82 #ifndef NX_DISABLE_PACKET_CHAIN
83 UINT       status;                 /* Return status              */
84 NX_PACKET *new_list_ptr;           /* Head of new list pointer   */
85 NX_PACKET *last_packet =  NX_NULL; /* Last supplied packet       */
86 #endif /* NX_DISABLE_PACKET_CHAIN */
87 ULONG      available_bytes;        /* Number of available bytes  */
88 ULONG      copy_size;              /* Size for each memory copy  */
89 UCHAR     *source_ptr;             /* Buffer source pointer      */
90 NX_PACKET *work_ptr;               /* Working packet pointer     */
91 
92 
93     /* If trace is enabled, insert this event into the trace buffer.  */
94     NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_DATA_APPEND, packet_ptr, data_start, data_size, pool_ptr, NX_TRACE_PACKET_EVENTS, 0, 0);
95 
96 #ifndef NX_DISABLE_PACKET_CHAIN
97     /* Calculate the number of bytes available at the end of the supplied packet.  */
98     if (packet_ptr -> nx_packet_last)
99     {
100 
101         /* More than one packet.  Walk the packet chain starting at the last packet
102            to calculate the remaining bytes.  */
103         available_bytes =  0;
104         work_ptr =  packet_ptr -> nx_packet_last;
105         do
106         {
107 
108             /* Calculate the available bytes in this packet.  */
109             /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
110             /*lint -e{737} suppress loss of sign, since nx_packet_data_end is assumed to be larger than nx_packet_append_ptr. */
111             available_bytes =  available_bytes +
112                 (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr);
113 
114             /* Remember the last packet.  */
115             last_packet =  work_ptr;
116 
117             /* Move to the next packet.   There typically won't be another packet, but just in
118                case the logic is here for it!  */
119             work_ptr =  work_ptr -> nx_packet_next;
120         } while (work_ptr);
121     }
122     else
123 #endif /* NX_DISABLE_PACKET_CHAIN */
124     {
125 
126         /* Just calculate the number of bytes available in the first packet.  */
127         /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
128         available_bytes =  (ULONG)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr);
129     }
130 
131     /* Determine if any new packets are required to satisfy this request. */
132     if (available_bytes < data_size)
133     {
134 
135 #ifndef NX_DISABLE_PACKET_CHAIN
136         /* Setup a temporary head pointer.  */
137         new_list_ptr =  NX_NULL;
138 
139         /* Loop to pickup enough packets to complete the append request.  */
140         while (available_bytes < data_size)
141         {
142 
143             /* Allocate a new packet.  */
144             status =  _nx_packet_allocate(pool_ptr, &work_ptr, 0, wait_option);
145 
146             /* Determine if an error is present.  */
147             if (status)
148             {
149 
150                 /* Yes, an error is present.   */
151 
152                 /* First release any packets that have been allocated so far.  */
153                 if (new_list_ptr)
154                 {
155                     _nx_packet_release(new_list_ptr);
156                 }
157 
158                 /* Return the error status to the caller of this service.  */
159                 return(status);
160             }
161 
162             /* Add debug information. */
163             NX_PACKET_DEBUG(__FILE__, __LINE__, work_ptr);
164 
165             /* No error is present.  Link the new packet to the temporary list being built.  */
166             if (new_list_ptr)
167             {
168 
169                 /* Determine if there is already more than one packet on the list.  */
170                 if (new_list_ptr -> nx_packet_last)
171                 {
172 
173                     /* Yes, link up the last packet to the new packet and update the
174                        last pointer.  */
175                     /*lint -e{644} suppress variable might not be initialized, since "work_ptr" was initialized in _nx_packet_allocate. */
176                     (new_list_ptr -> nx_packet_last) -> nx_packet_next =  work_ptr;
177                     new_list_ptr -> nx_packet_last =  work_ptr;
178                 }
179                 else
180                 {
181 
182                     /* Second packet allocated.  Just setup the last and next in the
183                        head pointer.  */
184                     new_list_ptr -> nx_packet_last =  work_ptr;
185                     new_list_ptr -> nx_packet_next =  work_ptr;
186                 }
187             }
188             else
189             {
190 
191                 /* Just setup the temporary list head.  */
192                 new_list_ptr =  work_ptr;
193             }
194 
195             /* Adjust the number of available bytes according to how much space
196                is in the new packet.  */
197             /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
198             /*lint -e{737} suppress loss of sign, since nx_packet_data_end is assumed to be larger than nx_packet_append_ptr. */
199             /*lint -e{613} suppress possible use of null pointer, since "work_ptr" was set in _nx_packet_allocate. */
200             available_bytes =  available_bytes +
201                 (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr);
202         }
203 
204         /* At this point, all the necessary packets have been allocated and are present
205            on the temporary list.  We need to link this new list to the end of the supplied
206            packet.  */
207         if (last_packet)
208         {
209 
210             /* Already more than one packet.  Add the new packet list to the end.  */
211             last_packet -> nx_packet_next =  new_list_ptr;
212         }
213         else
214         {
215 
216             /* Link the new packet list to the head packet.  */
217             packet_ptr -> nx_packet_next =  new_list_ptr;
218         }
219 
220         /* Clear the last packet that was used to maintain the new list.  */
221         /*lint -e{613} suppress possible use of null pointer, since "new_list_ptr" was set in previous loop. */
222         new_list_ptr -> nx_packet_last =  NX_NULL;
223 #else
224         NX_PARAMETER_NOT_USED(pool_ptr);
225         NX_PARAMETER_NOT_USED(wait_option);
226 
227         return(NX_SIZE_ERROR);
228 #endif /* NX_DISABLE_PACKET_CHAIN */
229     }
230 
231     /* Setup the new data length in the packet.  */
232     packet_ptr -> nx_packet_length =   packet_ptr -> nx_packet_length + data_size;
233 
234     /* Now copy the supplied data buffer at the end of the packet.  */
235     source_ptr =  (UCHAR *)data_start;
236 #ifndef NX_DISABLE_PACKET_CHAIN
237     if (packet_ptr -> nx_packet_last)
238     {
239         work_ptr =    packet_ptr -> nx_packet_last;
240     }
241     else
242     {
243 #endif /* NX_DISABLE_PACKET_CHAIN */
244         work_ptr =    packet_ptr;
245 #ifndef NX_DISABLE_PACKET_CHAIN
246     }
247     while (data_size)
248     {
249 
250         /* Determine the amount of memory to copy.  */
251         /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
252         if (data_size < (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr))
253         {
254             copy_size =  data_size;
255         }
256         else
257         {
258 
259             /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
260             copy_size =  (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr);
261         }
262 #else
263         copy_size = data_size;
264 #endif /* NX_DISABLE_PACKET_CHAIN */
265 
266         /* Copy the data into the current packet buffer.  */
267         memcpy(work_ptr -> nx_packet_append_ptr, source_ptr, copy_size); /* Use case of memcpy is verified.  lgtm[cpp/banned-api-usage-required-any] */
268 
269         /* Adjust the remaining data size.  */
270         data_size =  data_size - copy_size;
271 
272         /* Update this packets append pointer.  */
273         work_ptr -> nx_packet_append_ptr =  work_ptr -> nx_packet_append_ptr + copy_size;
274 
275 #ifndef NX_DISABLE_PACKET_CHAIN
276         /* Any more data left to append?  */
277         if (data_size)
278         {
279 
280             /* Yes, there is more to move.  Update the source pointer, move the work pointer
281                to the next packet in the chain and update the last packet pointer.  */
282             source_ptr =  source_ptr + copy_size;
283             work_ptr =  work_ptr -> nx_packet_next;
284             packet_ptr -> nx_packet_last =  work_ptr;
285         }
286     }
287 #endif /* NX_DISABLE_PACKET_CHAIN */
288 
289     /* Add debug information. */
290     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
291 
292     /* Return successful status.  */
293     return(NX_SUCCESS);
294 }
295 
296