1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 /**
21 * @addtogroup OSKernel
22 * @{
23 * @defgroup OSMbuf Chained Memory Buffers
24 * @{
25 */
26
27 #ifndef _OS_MBUF_H
28 #define _OS_MBUF_H
29
30 #include "os/os.h"
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 /**
37 * A mbuf pool from which to allocate mbufs. This contains a pointer to the os
38 * mempool to allocate mbufs out of, the total number of elements in the pool,
39 * and the amount of "user" data in a non-packet header mbuf. The total pool
40 * size, in bytes, should be:
41 * os_mbuf_count * (omp_databuf_len + sizeof(struct os_mbuf))
42 */
43 struct os_mbuf_pool {
44 /**
45 * Total length of the databuf in each mbuf. This is the size of the
46 * mempool block, minus the mbuf header
47 */
48 uint16_t omp_databuf_len;
49 /**
50 * The memory pool which to allocate mbufs out of
51 */
52 struct os_mempool *omp_pool;
53
54 STAILQ_ENTRY(os_mbuf_pool) omp_next;
55 };
56
57 /**
58 * A packet header structure that preceeds the mbuf packet headers.
59 */
60 struct os_mbuf_pkthdr {
61 /**
62 * Overall length of the packet.
63 */
64 uint16_t omp_len;
65 /**
66 * Flags
67 */
68 uint16_t omp_flags;
69
70 STAILQ_ENTRY(os_mbuf_pkthdr) omp_next;
71 };
72
73 /**
74 * Chained memory buffer.
75 */
76 struct os_mbuf {
77 /**
78 * Current pointer to data in the structure
79 */
80 uint8_t *om_data;
81 /**
82 * Flags associated with this buffer, see OS_MBUF_F_* defintions
83 */
84 uint8_t om_flags;
85 /**
86 * Length of packet header
87 */
88 uint8_t om_pkthdr_len;
89 /**
90 * Length of data in this buffer
91 */
92 uint16_t om_len;
93
94 /**
95 * The mbuf pool this mbuf was allocated out of
96 */
97 struct os_mbuf_pool *om_omp;
98
99 SLIST_ENTRY(os_mbuf) om_next;
100
101 /**
102 * Pointer to the beginning of the data, after this buffer
103 */
104 uint8_t om_databuf[0];
105 };
106
107 /**
108 * Structure representing a queue of mbufs.
109 */
110 struct os_mqueue {
111 STAILQ_HEAD(, os_mbuf_pkthdr) mq_head;
112 /** Event to post when new buffers are available on the queue. */
113 struct ble_npl_event mq_ev;
114 };
115
116 /*
117 * Given a flag number, provide the mask for it
118 *
119 * @param __n The number of the flag in the mask
120 */
121 #define OS_MBUF_F_MASK(__n) (1 << (__n))
122
123 /*
124 * Checks whether a given mbuf is a packet header mbuf
125 *
126 * @param __om The mbuf to check
127 */
128 #define OS_MBUF_IS_PKTHDR(__om) \
129 ((__om)->om_pkthdr_len >= sizeof (struct os_mbuf_pkthdr))
130
131 /** Get a packet header pointer given an mbuf pointer */
132 #define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) \
133 ((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf)))
134
135 /** Given a mbuf packet header pointer, return a pointer to the mbuf */
136 #define OS_MBUF_PKTHDR_TO_MBUF(__hdr) \
137 (struct os_mbuf *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf))
138
139 /**
140 * Gets the length of an entire mbuf chain. The specified mbuf must have a
141 * packet header.
142 */
143 #define OS_MBUF_PKTLEN(__om) (OS_MBUF_PKTHDR(__om)->omp_len)
144
145 /**
146 * Access the data of a mbuf, and cast it to type
147 *
148 * @param __om The mbuf to access, and cast
149 * @param __type The type to cast it to
150 */
151 #define OS_MBUF_DATA(__om, __type) \
152 (__type) ((__om)->om_data)
153
154 /**
155 * Access the "user header" in the head of an mbuf chain.
156 *
157 * @param om Pointer to the head of an mbuf chain.
158 */
159 #define OS_MBUF_USRHDR(om) \
160 (void *)((uint8_t *)(om) + sizeof (struct os_mbuf) + sizeof (struct os_mbuf_pkthdr))
161
162 /**
163 * Retrieves the length of the user header in an mbuf.
164 *
165 * @param om Pointer to the mbuf to query.
166 */
167 #define OS_MBUF_USRHDR_LEN(om) \
168 ((om)->om_pkthdr_len - sizeof (struct os_mbuf_pkthdr))
169
170 /** @cond INTERNAL_HIDDEN */
171
172 /*
173 * Called by OS_MBUF_LEADINGSPACE() macro
174 */
_os_mbuf_leadingspace(struct os_mbuf * om)175 static inline uint16_t _os_mbuf_leadingspace(struct os_mbuf *om)
176 {
177 uint16_t startoff;
178 uint16_t leadingspace;
179 startoff = 0;
180
181 if (OS_MBUF_IS_PKTHDR(om)) {
182 startoff = om->om_pkthdr_len;
183 }
184
185 leadingspace = (uint16_t)(OS_MBUF_DATA(om, uint8_t *) -
186 ((uint8_t *) &om->om_databuf[0] + startoff));
187 return (leadingspace);
188 }
189
190 /** @endcond */
191
192 /**
193 * Returns the leading space (space at the beginning) of the mbuf.
194 * Works on both packet header, and regular mbufs, as it accounts
195 * for the additional space allocated to the packet header.
196 *
197 * @param __omp Is the mbuf pool (which contains packet header length.)
198 * @param __om Is the mbuf in that pool to get the leadingspace for
199 *
200 * @return Amount of leading space available in the mbuf
201 */
202 #define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om)
203
204 /** @cond INTERNAL_HIDDEN */
205
206 /* Called by OS_MBUF_TRAILINGSPACE() macro. */
_os_mbuf_trailingspace(struct os_mbuf * om)207 static inline uint16_t _os_mbuf_trailingspace(struct os_mbuf *om)
208 {
209 struct os_mbuf_pool *omp;
210 omp = om->om_omp;
211 return (&om->om_databuf[0] + omp->omp_databuf_len) -
212 (om->om_data + om->om_len);
213 }
214
215 /** @endcond */
216
217 /**
218 * Returns the trailing space (space at the end) of the mbuf.
219 * Works on both packet header and regular mbufs.
220 *
221 * @param __omp The mbuf pool for this mbuf
222 * @param __om Is the mbuf in that pool to get trailing space for
223 *
224 * @return The amount of trailing space available in the mbuf
225 */
226 #define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om)
227
228 /**
229 * Initializes an mqueue. An mqueue is a queue of mbufs that ties to a
230 * particular task's event queue. Mqueues form a helper API around a common
231 * paradigm: wait on an event queue until at least one packet is available,
232 * then process a queue of packets.
233 *
234 * When mbufs are available on the queue, an event OS_EVENT_T_MQUEUE_DATA
235 * will be posted to the task's mbuf queue.
236 *
237 * @param mq The mqueue to initialize
238 * @param ev_cb The callback to associate with the mqeueue
239 * event. Typically, this callback pulls each
240 * packet off the mqueue and processes them.
241 * @param arg The argument to associate with the mqueue event.
242 *
243 * @return 0 on success, non-zero on failure.
244 */
245 int os_mqueue_init(struct os_mqueue *mq, ble_npl_event_fn *ev_cb, void *arg);
246
247 /**
248 * Remove and return a single mbuf from the mbuf queue. Does not block.
249 *
250 * @param mq The mbuf queue to pull an element off of.
251 *
252 * @return The next mbuf in the queue, or NULL if queue has no mbufs.
253 */
254 struct os_mbuf *os_mqueue_get(struct os_mqueue *);
255
256 /**
257 * Adds a packet (i.e. packet header mbuf) to an mqueue. The event associated
258 * with the mqueue gets posted to the specified eventq.
259 *
260 * @param mq The mbuf queue to append the mbuf to.
261 * @param evq The event queue to post an event to.
262 * @param m The mbuf to append to the mbuf queue.
263 *
264 * @return 0 on success, non-zero on failure.
265 */
266 int os_mqueue_put(struct os_mqueue *, struct ble_npl_eventq *, struct os_mbuf *);
267
268 /**
269 * MSYS is a system level mbuf registry. Allows the system to share
270 * packet buffers amongst the various networking stacks that can be running
271 * simultaeneously.
272 *
273 * Mbuf pools are created in the system initialization code, and then when
274 * a mbuf is allocated out of msys, it will try and find the best fit based
275 * upon estimated mbuf size.
276 *
277 * os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to
278 * allocate mbufs out of it.
279 *
280 * @param new_pool The pool to register with MSYS
281 *
282 * @return 0 on success, non-zero on failure
283 */
284 int os_msys_register(struct os_mbuf_pool *);
285
286 /**
287 * Allocate a mbuf from msys. Based upon the data size requested,
288 * os_msys_get() will choose the mbuf pool that has the best fit.
289 *
290 * @param dsize The estimated size of the data being stored in the mbuf
291 * @param leadingspace The amount of leadingspace to allocate in the mbuf
292 *
293 * @return A freshly allocated mbuf on success, NULL on failure.
294 */
295 struct os_mbuf *os_msys_get(uint16_t dsize, uint16_t leadingspace);
296
297 /**
298 * De-registers all mbuf pools from msys.
299 */
300 void os_msys_reset(void);
301
302 /**
303 * Allocate a packet header structure from the MSYS pool. See
304 * os_msys_register() for a description of MSYS.
305 *
306 * @param dsize The estimated size of the data being stored in the mbuf
307 * @param user_hdr_len The length to allocate for the packet header structure
308 *
309 * @return A freshly allocated mbuf on success, NULL on failure.
310 */
311 struct os_mbuf *os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len);
312
313 /**
314 * Count the number of blocks in all the mbuf pools that are allocated.
315 *
316 * @return total number of blocks allocated in Msys
317 */
318 int os_msys_count(void);
319
320 /**
321 * Return the number of free blocks in Msys
322 *
323 * @return Number of free blocks available in Msys
324 */
325 int os_msys_num_free(void);
326
327 /**
328 * Initialize a pool of mbufs.
329 *
330 * @param omp The mbuf pool to initialize
331 * @param mp The memory pool that will hold this mbuf pool
332 * @param buf_len The length of the buffer itself.
333 * @param nbufs The number of buffers in the pool
334 *
335 * @return 0 on success, error code on failure.
336 */
337 int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp,
338 uint16_t, uint16_t);
339
340 /**
341 * Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized
342 * prior to being returned.
343 *
344 * @param omp The mbuf pool to return the packet from
345 * @param leadingspace The amount of leadingspace to put before the data
346 * section by default.
347 *
348 * @return An initialized mbuf on success, and NULL on failure.
349 */
350 struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t);
351
352 /**
353 * Allocate a new packet header mbuf out of the os_mbuf_pool.
354 *
355 * @param omp The mbuf pool to allocate out of
356 * @param user_pkthdr_len The packet header length to reserve for the caller.
357 *
358 * @return A freshly allocated mbuf on success, NULL on failure.
359 */
360 struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp,
361 uint8_t pkthdr_len);
362
363 /**
364 * Duplicate a chain of mbufs. Return the start of the duplicated chain.
365 *
366 * @param omp The mbuf pool to duplicate out of
367 * @param om The mbuf chain to duplicate
368 *
369 * @return A pointer to the new chain of mbufs
370 */
371 struct os_mbuf *os_mbuf_dup(struct os_mbuf *m);
372
373 /**
374 * Locates the specified absolute offset within an mbuf chain. The offset
375 * can be one past than the total length of the chain, but no greater.
376 *
377 * @param om The start of the mbuf chain to seek within.
378 * @param off The absolute address to find.
379 * @param out_off On success, this points to the relative offset
380 * within the returned mbuf.
381 *
382 * @return The mbuf containing the specified offset on
383 * success.
384 * NULL if the specified offset is out of bounds.
385 */
386 struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off,
387 uint16_t *out_off);
388
389 /*
390 * Copy data from an mbuf chain starting "off" bytes from the beginning,
391 * continuing for "len" bytes, into the indicated buffer.
392 *
393 * @param m The mbuf chain to copy from
394 * @param off The offset into the mbuf chain to begin copying from
395 * @param len The length of the data to copy
396 * @param dst The destination buffer to copy into
397 *
398 * @return 0 on success;
399 * -1 if the mbuf does not contain enough data.
400 */
401 int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst);
402
403 /**
404 * Append data onto a mbuf
405 *
406 * @param om The mbuf to append the data onto
407 * @param data The data to append onto the mbuf
408 * @param len The length of the data to append
409 *
410 * @return 0 on success, and an error code on failure
411 */
412 int os_mbuf_append(struct os_mbuf *m, const void *, uint16_t);
413
414 /**
415 * Reads data from one mbuf and appends it to another. On error, the specified
416 * data range may be partially appended. Neither mbuf is required to contain
417 * an mbuf packet header.
418 *
419 * @param dst The mbuf to append to.
420 * @param src The mbuf to copy data from.
421 * @param src_off The absolute offset within the source mbuf
422 * chain to read from.
423 * @param len The number of bytes to append.
424 *
425 * @return 0 on success;
426 * OS_EINVAL if the specified range extends beyond
427 * the end of the source mbuf chain.
428 */
429 int os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src,
430 uint16_t src_off, uint16_t len);
431
432 /**
433 * Release a mbuf back to the pool
434 *
435 * @param omp The Mbuf pool to release back to
436 * @param om The Mbuf to release back to the pool
437 *
438 * @return 0 on success, -1 on failure
439 */
440 int os_mbuf_free(struct os_mbuf *mb);
441
442 /**
443 * Free a chain of mbufs
444 *
445 * @param omp The mbuf pool to free the chain of mbufs into
446 * @param om The starting mbuf of the chain to free back into the pool
447 *
448 * @return 0 on success, -1 on failure
449 */
450 int os_mbuf_free_chain(struct os_mbuf *om);
451
452 /**
453 * Adjust the length of a mbuf, trimming either from the head or the tail
454 * of the mbuf.
455 *
456 * @param mp The mbuf chain to adjust
457 * @param req_len The length to trim from the mbuf. If positive, trims
458 * from the head of the mbuf, if negative, trims from the
459 * tail of the mbuf.
460 */
461 void os_mbuf_adj(struct os_mbuf *mp, int req_len);
462
463 /**
464 * Performs a memory compare of the specified region of an mbuf chain against a
465 * flat buffer.
466 *
467 * @param om The start of the mbuf chain to compare.
468 * @param off The offset within the mbuf chain to start the
469 * comparison.
470 * @param data The flat buffer to compare.
471 * @param len The length of the flat buffer.
472 *
473 * @return 0 if both memory regions are identical;
474 * A memcmp return code if there is a mismatch;
475 * INT_MAX if the mbuf is too short.
476 */
477 int os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len);
478
479 /**
480 * Compares the contents of two mbuf chains. The ranges of the two chains to
481 * be compared are specified via the two offset parameters and the len
482 * parameter. Neither mbuf chain is required to contain a packet header.
483 *
484 * @param om1 The first mbuf chain to compare.
485 * @param offset1 The absolute offset within om1 at which to
486 * start the comparison.
487 * @param om2 The second mbuf chain to compare.
488 * @param offset2 The absolute offset within om2 at which to
489 * start the comparison.
490 * @param len The number of bytes to compare.
491 *
492 * @return 0 if both mbuf segments are identical;
493 * A memcmp() return code if the segment contents
494 * differ;
495 * INT_MAX if a specified range extends beyond the
496 * end of its corresponding mbuf chain.
497 */
498 int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
499 const struct os_mbuf *om2, uint16_t offset2,
500 uint16_t len);
501
502 /**
503 * Increases the length of an mbuf chain by adding data to the front. If there
504 * is insufficient room in the leading mbuf, additional mbufs are allocated and
505 * prepended as necessary. If this function fails to allocate an mbuf, the
506 * entire chain is freed.
507 *
508 * The specified mbuf chain does not need to contain a packet header.
509 *
510 * @param omp The mbuf pool to allocate from.
511 * @param om The head of the mbuf chain.
512 * @param len The number of bytes to prepend.
513 *
514 * @return The new head of the chain on success;
515 * NULL on failure.
516 */
517 struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int len);
518
519 /**
520 * Prepends a chunk of empty data to the specified mbuf chain and ensures the
521 * chunk is contiguous. If either operation fails, the specified mbuf chain is
522 * freed and NULL is returned.
523 *
524 * @param om The mbuf chain to prepend to.
525 * @param len The number of bytes to prepend and pullup.
526 *
527 * @return The modified mbuf on success;
528 * NULL on failure (and the mbuf chain is freed).
529 */
530 struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len);
531
532 /**
533 * Copies the contents of a flat buffer into an mbuf chain, starting at the
534 * specified destination offset. If the mbuf is too small for the source data,
535 * it is extended as necessary. If the destination mbuf contains a packet
536 * header, the header length is updated.
537 *
538 * @param omp The mbuf pool to allocate from.
539 * @param om The mbuf chain to copy into.
540 * @param off The offset within the chain to copy to.
541 * @param src The source buffer to copy from.
542 * @param len The number of bytes to copy.
543 *
544 * @return 0 on success; nonzero on failure.
545 */
546 int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len);
547
548 /**
549 * Attaches a second mbuf chain onto the end of the first. If the first chain
550 * contains a packet header, the header's length is updated. If the second
551 * chain has a packet header, its header is cleared.
552 *
553 * @param first The mbuf chain being attached to.
554 * @param second The mbuf chain that gets attached.
555 */
556 void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second);
557
558 /**
559 * Increases the length of an mbuf chain by the specified amount. If there is
560 * not sufficient room in the last buffer, a new buffer is allocated and
561 * appended to the chain. It is an error to request more data than can fit in
562 * a single buffer.
563 *
564 * @param omp
565 * @param om The head of the chain to extend.
566 * @param len The number of bytes to extend by.
567 *
568 * @return A pointer to the new data on success;
569 * NULL on failure.
570 */
571 void *os_mbuf_extend(struct os_mbuf *om, uint16_t len);
572
573 /**
574 * Rearrange a mbuf chain so that len bytes are contiguous,
575 * and in the data area of an mbuf (so that OS_MBUF_DATA() will
576 * work on a structure of size len.) Returns the resulting
577 * mbuf chain on success, free's it and returns NULL on failure.
578 *
579 * If there is room, it will add up to "max_protohdr - len"
580 * extra bytes to the contiguous region, in an attempt to avoid being
581 * called next time.
582 *
583 * @param omp The mbuf pool to take the mbufs out of
584 * @param om The mbuf chain to make contiguous
585 * @param len The number of bytes in the chain to make contiguous
586 *
587 * @return The contiguous mbuf chain on success, NULL on failure.
588 */
589 struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t len);
590
591 /**
592 * Removes and frees empty mbufs from the front of a chain. If the chain
593 * contains a packet header, it is preserved.
594 *
595 * @param om The mbuf chain to trim.
596 *
597 * @return The head of the trimmed mbuf chain.
598 */
599 struct os_mbuf *os_mbuf_trim_front(struct os_mbuf *om);
600
601 /**
602 * Creates a single chained mbuf from m1 and m2 utilizing all
603 * the available buffer space in all mbufs in the resulting
604 * chain. In other words, ensures there is no leading space in
605 * any mbuf in the resulting chain and trailing space only in
606 * the last mbuf in the chain. Mbufs from either chain may be
607 * freed if not needed. No mbufs are allocated. Note that mbufs
608 * from m2 are added to the end of m1. If m1 has a packet
609 * header, it is retained and length updated. If m2 has a packet
610 * header it is discarded. If m1 is NULL, NULL is returned and
611 * m2 is left untouched.
612 *
613 * @param m1 Pointer to first mbuf chain to pack
614 * @param m2 Pointer to second mbuf chain to pack
615 *
616 * @return struct os_mbuf* Pointer to resulting mbuf chain
617 */
618 struct os_mbuf *os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2);
619
620 #ifdef __cplusplus
621 }
622 #endif
623
624 #endif /* _OS_MBUF_H */
625
626 /**
627 * @} OSMbuf
628 * @} OSKernel
629 */