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