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