blob: 5c58c8455c57d534d0b911841d34e52d5c4a0ec3 [file] [log] [blame]
Sylvain Munaut12ba7782014-06-16 10:13:40 +02001#pragma once
Harald Welteec8b4502010-02-20 20:34:29 +01002
3/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
Harald Welteec8b4502010-02-20 20:34:29 +010016 */
17
18#include <stdint.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010019#include <osmocom/core/linuxlist.h>
20#include <osmocom/core/utils.h>
Max53777012014-06-04 19:07:41 +020021#include <osmocom/core/bits.h>
Neels Hofmeyrf45334b2016-09-16 00:15:56 +020022#include <osmocom/core/defs.h>
Harald Welteec8b4502010-02-20 20:34:29 +010023
Harald Welteba6988b2011-08-17 12:46:48 +020024/*! \defgroup msgb Message buffers
25 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020026 * \file msgb.h */
Harald Weltebd598e32011-08-16 23:26:52 +020027
Harald Welte652a7232010-07-22 21:55:24 +020028#define MSGB_DEBUG
29
Neels Hofmeyr87e45502017-06-20 00:17:59 +020030/*! Osmocom message buffer */
Harald Welteec8b4502010-02-20 20:34:29 +010031struct msgb {
Neels Hofmeyr87e45502017-06-20 00:17:59 +020032 struct llist_head list; /*!< linked list header */
Harald Welteec8b4502010-02-20 20:34:29 +010033
Pablo Neira Ayuso29cbf612011-07-07 19:46:44 +020034
Harald Welteec8b4502010-02-20 20:34:29 +010035 /* Part of which TRX logical channel we were received / transmitted */
Harald Welte074c9f92010-04-30 14:29:11 +020036 /* FIXME: move them into the control buffer */
Harald Weltec5a0ded2011-07-18 16:59:27 +020037 union {
Neels Hofmeyr87e45502017-06-20 00:17:59 +020038 void *dst; /*!< reference of origin/destination */
Harald Weltec5a0ded2011-07-18 16:59:27 +020039 struct gsm_bts_trx *trx;
40 };
Neels Hofmeyr87e45502017-06-20 00:17:59 +020041 struct gsm_lchan *lchan; /*!< logical channel */
Harald Welteec8b4502010-02-20 20:34:29 +010042
Neels Hofmeyr87e45502017-06-20 00:17:59 +020043 unsigned char *l1h; /*!< pointer to Layer1 header (if any) */
44 unsigned char *l2h; /*!< pointer to A-bis layer 2 header: OML, RSL(RLL), NS */
45 unsigned char *l3h; /*!< pointer to Layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */
46 unsigned char *l4h; /*!< pointer to layer 4 header */
Harald Welteec8b4502010-02-20 20:34:29 +010047
Neels Hofmeyr87e45502017-06-20 00:17:59 +020048 unsigned long cb[5]; /*!< control buffer */
Harald Welte074c9f92010-04-30 14:29:11 +020049
Neels Hofmeyr87e45502017-06-20 00:17:59 +020050 uint16_t data_len; /*!< length of underlying data array */
51 uint16_t len; /*!< length of bytes used in msgb */
Harald Welteec8b4502010-02-20 20:34:29 +010052
Neels Hofmeyr87e45502017-06-20 00:17:59 +020053 unsigned char *head; /*!< start of underlying memory buffer */
54 unsigned char *tail; /*!< end of message in buffer */
55 unsigned char *data; /*!< start of message in buffer */
56 unsigned char _data[0]; /*!< optional immediate data array */
Harald Welteec8b4502010-02-20 20:34:29 +010057};
58
Harald Welte179f3572019-03-18 18:38:47 +010059extern struct msgb *msgb_alloc_c(const void *ctx, uint16_t size, const char *name);
Harald Welteec8b4502010-02-20 20:34:29 +010060extern struct msgb *msgb_alloc(uint16_t size, const char *name);
61extern void msgb_free(struct msgb *m);
62extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
63extern struct msgb *msgb_dequeue(struct llist_head *queue);
64extern void msgb_reset(struct msgb *m);
Harald Welte972b5022012-09-08 19:58:59 +020065uint16_t msgb_length(const struct msgb *msg);
Jacob Erlbeckbaa225e2014-02-28 15:14:40 +010066extern const char *msgb_hexdump(const struct msgb *msg);
Harald Welte4a62eda2019-03-18 18:27:00 +010067char *msgb_hexdump_buf(char *buf, size_t buf_len, const struct msgb *msg);
Harald Welte179f3572019-03-18 18:38:47 +010068char *msgb_hexdump_c(const void *ctx, const struct msgb *msg);
Jacob Erlbeckcdd05f02015-11-27 13:26:13 +010069extern int msgb_resize_area(struct msgb *msg, uint8_t *area,
70 int old_size, int new_size);
71extern struct msgb *msgb_copy(const struct msgb *msg, const char *name);
Harald Welte179f3572019-03-18 18:38:47 +010072extern struct msgb *msgb_copy_c(const void *ctx, const struct msgb *msg, const char *name);
Maxdf5b1e12022-10-14 20:39:40 +030073extern struct msgb *msgb_copy_resize(const struct msgb *msg, uint16_t new_len, const char *name);
74extern struct msgb *msgb_copy_resize_c(const void *ctx, const struct msgb *msg, uint16_t new_len, const char *name);
Jacob Erlbeck8db11342015-11-27 13:26:15 +010075static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure));
Harald Welteec8b4502010-02-20 20:34:29 +010076
Neels Hofmeyr3fad5d72017-11-20 14:15:03 +010077/*! Free all msgbs from a queue built with msgb_enqueue().
78 * \param[in] queue list head of a msgb queue.
79 */
80static inline void msgb_queue_free(struct llist_head *queue)
81{
82 struct msgb *msg;
83 while ((msg = msgb_dequeue(queue))) msgb_free(msg);
84}
85
Pau Espin Pedrol8ce6f482018-08-17 10:33:57 +020086/*! Enqueue message buffer to tail of a queue and increment queue size counter
87 * \param[in] queue linked list header of queue
88 * \param[in] msg message buffer to be added to the queue
89 * \param[in] count pointer to variable holding size of the queue
90 *
91 * The function will append the specified message buffer \a msg to the queue
92 * implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count,
93 * then increment \a count
94 */
95static inline void msgb_enqueue_count(struct llist_head *queue, struct msgb *msg,
96 unsigned int *count)
97{
98 msgb_enqueue(queue, msg);
99 (*count)++;
100}
101
102/*! Dequeue message buffer from head of queue and decrement queue size counter
103 * \param[in] queue linked list header of queue
104 * \param[in] count pointer to variable holding size of the queue
105 * \returns message buffer (if any) or NULL if queue empty
106 *
107 * The function will remove the first message buffer from the queue
108 * implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count,
109 * and decrement \a count, all if queue is not empty.
110 */
111static inline struct msgb *msgb_dequeue_count(struct llist_head *queue,
112 unsigned int *count)
113{
114 struct msgb *msg = msgb_dequeue(queue);
115 if (msg)
116 (*count)--;
117 return msg;
118}
119
Harald Welte652a7232010-07-22 21:55:24 +0200120#ifdef MSGB_DEBUG
Pablo Neira Ayuso83419342011-03-22 16:36:13 +0100121#include <osmocom/core/panic.h>
Harald Welte929d8872010-11-05 07:47:41 +0100122#define MSGB_ABORT(msg, fmt, args ...) do { \
Harald Weltedab02872010-11-09 13:42:26 +0100123 osmo_panic("msgb(%p): " fmt, msg, ## args); \
Harald Welte929d8872010-11-05 07:47:41 +0100124 } while(0)
125#else
126#define MSGB_ABORT(msg, fmt, args ...)
Harald Welte652a7232010-07-22 21:55:24 +0200127#endif
128
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200129/*! obtain L1 header of msgb */
Vadim Yanitskiy918b0ce2023-07-08 00:05:41 +0700130#define msgb_l1(m) ((void *)((m)->l1h))
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200131/*! obtain L2 header of msgb */
Vadim Yanitskiy918b0ce2023-07-08 00:05:41 +0700132#define msgb_l2(m) ((void *)((m)->l2h))
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200133/*! obtain L3 header of msgb */
Vadim Yanitskiy918b0ce2023-07-08 00:05:41 +0700134#define msgb_l3(m) ((void *)((m)->l3h))
Maxcb02a392018-12-03 14:00:49 +0100135/*! obtain L4 header of msgb */
Vadim Yanitskiy918b0ce2023-07-08 00:05:41 +0700136#define msgb_l4(m) ((void *)((m)->l4h))
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200137/*! obtain SMS header of msgb */
Maxcb02a392018-12-03 14:00:49 +0100138#define msgb_sms(m) msgb_l4(m)
Harald Welteec8b4502010-02-20 20:34:29 +0100139
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200140/*! determine length of L1 message
Harald Weltebd598e32011-08-16 23:26:52 +0200141 * \param[in] msgb message buffer
142 * \returns size of L1 message in bytes
143 *
144 * This function computes the number of bytes between the tail of the
145 * message and the layer 1 header.
146 */
Harald Weltefdd0a702010-03-01 22:30:51 +0100147static inline unsigned int msgb_l1len(const struct msgb *msgb)
148{
Philipp Maierd9d62102022-10-04 14:43:25 +0200149 OSMO_ASSERT(msgb->l1h);
Harald Weltefdd0a702010-03-01 22:30:51 +0100150 return msgb->tail - (uint8_t *)msgb_l1(msgb);
151}
152
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200153/*! determine length of L2 message
Harald Weltebd598e32011-08-16 23:26:52 +0200154 * \param[in] msgb message buffer
155 * \returns size of L2 message in bytes
156 *
157 * This function computes the number of bytes between the tail of the
158 * message and the layer 2 header.
159 */
Harald Welteec8b4502010-02-20 20:34:29 +0100160static inline unsigned int msgb_l2len(const struct msgb *msgb)
161{
Philipp Maierd9d62102022-10-04 14:43:25 +0200162 OSMO_ASSERT(msgb->l2h);
Harald Welteec8b4502010-02-20 20:34:29 +0100163 return msgb->tail - (uint8_t *)msgb_l2(msgb);
164}
165
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200166/*! determine length of L3 message
Harald Weltebd598e32011-08-16 23:26:52 +0200167 * \param[in] msgb message buffer
168 * \returns size of L3 message in bytes
169 *
170 * This function computes the number of bytes between the tail of the
171 * message and the layer 3 header.
172 */
Harald Welteec8b4502010-02-20 20:34:29 +0100173static inline unsigned int msgb_l3len(const struct msgb *msgb)
174{
Philipp Maierd9d62102022-10-04 14:43:25 +0200175 OSMO_ASSERT(msgb->l3h);
Harald Welteec8b4502010-02-20 20:34:29 +0100176 return msgb->tail - (uint8_t *)msgb_l3(msgb);
177}
178
Vadim Yanitskiye521ede2018-11-07 03:53:03 +0700179/*! determine length of L4 message
180 * \param[in] msgb message buffer
181 * \returns size of L4 message in bytes
182 *
183 * This function computes the number of bytes between the tail of the
184 * message and the layer 4 header.
185 */
186static inline unsigned int msgb_l4len(const struct msgb *msgb)
187{
Philipp Maierd9d62102022-10-04 14:43:25 +0200188 OSMO_ASSERT(msgb->l4h);
Philipp Maier724c1622022-10-05 10:12:49 +0200189 return msgb->tail - (uint8_t *)msgb_l4(msgb);
Vadim Yanitskiye521ede2018-11-07 03:53:03 +0700190}
191
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200192/*! determine the length of the header
Harald Weltebd598e32011-08-16 23:26:52 +0200193 * \param[in] msgb message buffer
194 * \returns number of bytes between start of buffer and start of msg
195 *
196 * This function computes the length difference between the underlying
197 * data buffer and the used section of the \a msgb.
198 */
Harald Welteec8b4502010-02-20 20:34:29 +0100199static inline unsigned int msgb_headlen(const struct msgb *msgb)
200{
201 return msgb->len - msgb->data_len;
202}
Harald Welte652a7232010-07-22 21:55:24 +0200203
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200204/*! determine how much tail room is left in msgb
Harald Weltebd598e32011-08-16 23:26:52 +0200205 * \param[in] msgb message buffer
206 * \returns number of bytes remaining at end of msgb
207 *
208 * This function computes the amount of octets left in the underlying
209 * data buffer after the end of the message.
210 */
Harald Welte652a7232010-07-22 21:55:24 +0200211static inline int msgb_tailroom(const struct msgb *msgb)
212{
213 return (msgb->head + msgb->data_len) - msgb->tail;
214}
215
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200216/*! determine the amount of headroom in msgb
Harald Weltebd598e32011-08-16 23:26:52 +0200217 * \param[in] msgb message buffer
218 * \returns number of bytes left ahead of message start in msgb
219 *
220 * This function computes the amount of bytes left in the underlying
221 * data buffer before the start of the actual message.
222 */
Harald Welte652a7232010-07-22 21:55:24 +0200223static inline int msgb_headroom(const struct msgb *msgb)
224{
225 return (msgb->data - msgb->head);
226}
227
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200228/*! append data to end of message buffer
Harald Weltebd598e32011-08-16 23:26:52 +0200229 * \param[in] msgb message buffer
230 * \param[in] len number of bytes to append to message
231 * \returns pointer to start of newly-appended data
232 *
233 * This function will move the \a tail pointer of the message buffer \a
234 * len bytes further, thus enlarging the message by \a len bytes.
235 *
236 * The return value is a pointer to start of the newly added section at
237 * the end of the message and can be used for actually filling/copying
238 * data into it.
239 */
Harald Welteec8b4502010-02-20 20:34:29 +0100240static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
241{
242 unsigned char *tmp = msgb->tail;
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600243 if (OSMO_UNLIKELY(msgb_tailroom(msgb) < (int) len))
Neels Hofmeyr63cb9492019-11-11 05:51:43 +0100244 MSGB_ABORT(msgb, "Not enough tailroom msgb_put"
245 " (allocated %u, head at %u, len %u, tailroom %u < want tailroom %u)\n",
246 msgb->data_len - sizeof(struct msgb),
247 msgb->head - msgb->_data,
248 msgb->len,
Harald Welte929d8872010-11-05 07:47:41 +0100249 msgb_tailroom(msgb), len);
Harald Welteec8b4502010-02-20 20:34:29 +0100250 msgb->tail += len;
251 msgb->len += len;
252 return tmp;
253}
Harald Weltebd598e32011-08-16 23:26:52 +0200254
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200255/*! append a uint8 value to the end of the message
Harald Weltebd598e32011-08-16 23:26:52 +0200256 * \param[in] msgb message buffer
257 * \param[in] word unsigned 8bit byte to be appended
258 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100259static inline void msgb_put_u8(struct msgb *msgb, uint8_t word)
260{
261 uint8_t *space = msgb_put(msgb, 1);
262 space[0] = word & 0xFF;
263}
Harald Weltebd598e32011-08-16 23:26:52 +0200264
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200265/*! append a uint16 value to the end of the message
Harald Weltebd598e32011-08-16 23:26:52 +0200266 * \param[in] msgb message buffer
267 * \param[in] word unsigned 16bit byte to be appended
268 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100269static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
270{
271 uint8_t *space = msgb_put(msgb, 2);
Max53777012014-06-04 19:07:41 +0200272 osmo_store16be(word, space);
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100273}
Harald Weltebd598e32011-08-16 23:26:52 +0200274
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200275/*! append a uint32 value to the end of the message
Harald Weltebd598e32011-08-16 23:26:52 +0200276 * \param[in] msgb message buffer
277 * \param[in] word unsigned 32bit byte to be appended
278 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100279static inline void msgb_put_u32(struct msgb *msgb, uint32_t word)
280{
281 uint8_t *space = msgb_put(msgb, 4);
Max53777012014-06-04 19:07:41 +0200282 osmo_store32be(word, space);
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100283}
Harald Weltebd598e32011-08-16 23:26:52 +0200284
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200285/*! remove data from end of message
Harald Weltebd598e32011-08-16 23:26:52 +0200286 * \param[in] msgb message buffer
287 * \param[in] len number of bytes to remove from end
288 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100289static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len)
290{
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600291 if (OSMO_UNLIKELY(msgb_length(msgb) < len))
Harald Welte972b5022012-09-08 19:58:59 +0200292 MSGB_ABORT(msgb, "msgb too small to get %u (len %u)\n",
293 len, msgb_length(msgb));
294 msgb->tail -= len;
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100295 msgb->len -= len;
Pau Espin Pedrol9fa09122018-04-11 20:09:13 +0200296 return msgb->tail;
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100297}
Max53777012014-06-04 19:07:41 +0200298
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200299/*! remove uint8 from end of message
Harald Weltebd598e32011-08-16 23:26:52 +0200300 * \param[in] msgb message buffer
301 * \returns 8bit value taken from end of msgb
302 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100303static inline uint8_t msgb_get_u8(struct msgb *msgb)
304{
305 uint8_t *space = msgb_get(msgb, 1);
306 return space[0];
307}
Max53777012014-06-04 19:07:41 +0200308
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200309/*! remove uint16 from end of message
Harald Weltebd598e32011-08-16 23:26:52 +0200310 * \param[in] msgb message buffer
311 * \returns 16bit value taken from end of msgb
312 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100313static inline uint16_t msgb_get_u16(struct msgb *msgb)
314{
315 uint8_t *space = msgb_get(msgb, 2);
Max53777012014-06-04 19:07:41 +0200316 return osmo_load16be(space);
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100317}
Max53777012014-06-04 19:07:41 +0200318
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200319/*! remove uint32 from end of message
Harald Weltebd598e32011-08-16 23:26:52 +0200320 * \param[in] msgb message buffer
321 * \returns 32bit value taken from end of msgb
322 */
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100323static inline uint32_t msgb_get_u32(struct msgb *msgb)
324{
325 uint8_t *space = msgb_get(msgb, 4);
Max53777012014-06-04 19:07:41 +0200326 return osmo_load32be(space);
Ingo Albrecht48e17f82010-03-07 18:03:41 +0100327}
Harald Weltebd598e32011-08-16 23:26:52 +0200328
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200329/*! prepend (push) some data to start of message
Harald Weltebd598e32011-08-16 23:26:52 +0200330 * \param[in] msgb message buffer
331 * \param[in] len number of bytes to pre-pend
332 * \returns pointer to newly added portion at start of \a msgb
333 *
334 * This function moves the \a data pointer of the \ref msgb further
335 * to the front (by \a len bytes), thereby enlarging the message by \a
336 * len bytes.
337 *
338 * The return value is a pointer to the newly added section in the
339 * beginning of the message. It can be used to fill/copy data into it.
340 */
Harald Welteec8b4502010-02-20 20:34:29 +0100341static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
342{
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600343 if (OSMO_UNLIKELY(msgb_headroom(msgb) < (int) len))
Neels Hofmeyr63cb9492019-11-11 05:51:43 +0100344 MSGB_ABORT(msgb, "Not enough headroom msgb_push"
345 " (allocated %u, head at %u < want headroom %u, len %u, tailroom %u)\n",
346 msgb->data_len - sizeof(struct msgb),
347 msgb->head - msgb->_data,
348 len,
349 msgb->len,
350 msgb_tailroom(msgb));
Harald Welteec8b4502010-02-20 20:34:29 +0100351 msgb->data -= len;
352 msgb->len += len;
353 return msgb->data;
354}
Max53777012014-06-04 19:07:41 +0200355
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200356/*! prepend a uint8 value to the head of the message
Vadim Yanitskiy914a8ec2019-03-26 00:20:35 +0700357 * \param[in] msg message buffer
Harald Welte8593f1f2016-11-11 19:26:51 +0100358 * \param[in] word unsigned 8bit byte to be prepended
359 */
360static inline void msgb_push_u8(struct msgb *msg, uint8_t word)
361{
362 uint8_t *space = msgb_push(msg, 1);
363 space[0] = word;
364}
365
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200366/*! prepend a uint16 value to the head of the message
Vadim Yanitskiy914a8ec2019-03-26 00:20:35 +0700367 * \param[in] msg message buffer
Harald Welte8593f1f2016-11-11 19:26:51 +0100368 * \param[in] word unsigned 16bit byte to be prepended
369 */
370static inline void msgb_push_u16(struct msgb *msg, uint16_t word)
371{
372 uint16_t *space = (uint16_t *) msgb_push(msg, 2);
373 osmo_store16be(word, space);
374}
375
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200376/*! prepend a uint32 value to the head of the message
Vadim Yanitskiy914a8ec2019-03-26 00:20:35 +0700377 * \param[in] msg message buffer
Harald Welte8593f1f2016-11-11 19:26:51 +0100378 * \param[in] word unsigned 32bit byte to be prepended
379 */
380static inline void msgb_push_u32(struct msgb *msg, uint32_t word)
381{
382 uint32_t *space = (uint32_t *) msgb_push(msg, 4);
383 osmo_store32be(word, space);
384}
385
Maxb27e6fe2019-01-21 14:19:59 +0100386static inline unsigned char *msgb_push_tl(struct msgb *msgb, uint8_t tag)
Max84fb5bb2018-11-08 13:23:59 +0100387{
388 uint8_t *data = msgb_push(msgb, 2);
389
390 data[0] = tag;
391 data[1] = msgb->len - 2;
392 return data;
393}
394
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200395/*! remove (pull) a header from the front of the message buffer
Harald Weltebd598e32011-08-16 23:26:52 +0200396 * \param[in] msgb message buffer
397 * \param[in] len number of octets to be pulled
398 * \returns pointer to new start of msgb
399 *
400 * This function moves the \a data pointer of the \ref msgb further back
401 * in the message, thereby shrinking the size of the message by \a len
402 * bytes.
403 */
Harald Welteec8b4502010-02-20 20:34:29 +0100404static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
405{
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600406 if (OSMO_UNLIKELY(msgb_length(msgb) < len))
Pau Espin Pedrolc62fc2d2018-04-11 20:14:08 +0200407 MSGB_ABORT(msgb, "msgb too small to pull %u (len %u)\n",
408 len, msgb_length(msgb));
Harald Welteec8b4502010-02-20 20:34:29 +0100409 msgb->len -= len;
410 return msgb->data += len;
411}
Harald Welteec8b4502010-02-20 20:34:29 +0100412
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200413/*! remove (pull) all headers in front of l3h from the message buffer.
Vadim Yanitskiy914a8ec2019-03-26 00:20:35 +0700414 * \param[in] msg message buffer with a valid l3h
Jacob Erlbeck8dac4152014-01-28 11:03:11 +0100415 * \returns pointer to new start of msgb (l3h)
416 *
417 * This function moves the \a data pointer of the \ref msgb further back
418 * in the message, thereby shrinking the size of the message.
419 * l1h and l2h will be cleared.
420 */
421static inline unsigned char *msgb_pull_to_l3(struct msgb *msg)
422{
423 unsigned char *ret = msgb_pull(msg, msg->l3h - msg->data);
424 msg->l1h = msg->l2h = NULL;
425 return ret;
426}
427
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200428/*! remove (pull) all headers in front of l2h from the message buffer.
Vadim Yanitskiy914a8ec2019-03-26 00:20:35 +0700429 * \param[in] msg message buffer with a valid l2h
Harald Welte59a9ebf2017-04-15 19:04:34 +0200430 * \returns pointer to new start of msgb (l2h)
431 *
432 * This function moves the \a data pointer of the \ref msgb further back
433 * in the message, thereby shrinking the size of the message.
434 * l1h will be cleared.
435 */
436static inline unsigned char *msgb_pull_to_l2(struct msgb *msg)
437{
438 unsigned char *ret = msgb_pull(msg, msg->l2h - msg->data);
439 msg->l1h = NULL;
440 return ret;
441}
442
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200443/*! remove uint8 from front of message
Harald Welte972b5022012-09-08 19:58:59 +0200444 * \param[in] msgb message buffer
445 * \returns 8bit value taken from end of msgb
446 */
447static inline uint8_t msgb_pull_u8(struct msgb *msgb)
448{
Steve Markgraf5905d5b2012-11-14 19:36:00 +0100449 uint8_t *space = msgb_pull(msgb, 1) - 1;
Harald Welte972b5022012-09-08 19:58:59 +0200450 return space[0];
451}
Max53777012014-06-04 19:07:41 +0200452
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200453/*! remove uint16 from front of message
Harald Welte972b5022012-09-08 19:58:59 +0200454 * \param[in] msgb message buffer
455 * \returns 16bit value taken from end of msgb
456 */
457static inline uint16_t msgb_pull_u16(struct msgb *msgb)
458{
Steve Markgraf5905d5b2012-11-14 19:36:00 +0100459 uint8_t *space = msgb_pull(msgb, 2) - 2;
Max53777012014-06-04 19:07:41 +0200460 return osmo_load16be(space);
Harald Welte972b5022012-09-08 19:58:59 +0200461}
Max53777012014-06-04 19:07:41 +0200462
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200463/*! remove uint32 from front of message
Harald Welte972b5022012-09-08 19:58:59 +0200464 * \param[in] msgb message buffer
465 * \returns 32bit value taken from end of msgb
466 */
467static inline uint32_t msgb_pull_u32(struct msgb *msgb)
468{
Steve Markgraf5905d5b2012-11-14 19:36:00 +0100469 uint8_t *space = msgb_pull(msgb, 4) - 4;
Max53777012014-06-04 19:07:41 +0200470 return osmo_load32be(space);
Harald Welte972b5022012-09-08 19:58:59 +0200471}
472
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200473/*! Increase headroom of empty msgb, reducing the tailroom
Harald Weltebd598e32011-08-16 23:26:52 +0200474 * \param[in] msg message buffer
475 * \param[in] len amount of extra octets to be reserved as headroom
476 *
477 * This function reserves some memory at the beginning of the underlying
478 * data buffer. The idea is to reserve space in case further headers
479 * have to be pushed to the \ref msgb during further processing.
480 *
481 * Calling this function leads to undefined reusults if it is called on
482 * a non-empty \ref msgb.
483 */
Harald Welteec8b4502010-02-20 20:34:29 +0100484static inline void msgb_reserve(struct msgb *msg, int len)
485{
486 msg->data += len;
487 msg->tail += len;
488}
489
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200490/*! Trim the msgb to a given absolute length
Harald Welteb0f91512012-01-14 21:53:41 +0100491 * \param[in] msg message buffer
492 * \param[in] len new total length of buffer
493 * \returns 0 in case of success, negative in case of error
494 */
495static inline int msgb_trim(struct msgb *msg, int len)
496{
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600497 if (OSMO_UNLIKELY(len < 0))
Jacob Erlbeckff42b262015-11-27 13:26:19 +0100498 MSGB_ABORT(msg, "Negative length is not allowed\n");
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600499 if (OSMO_UNLIKELY(len > msg->data_len))
Harald Welteb0f91512012-01-14 21:53:41 +0100500 return -1;
501
Harald Welte3068d572012-01-14 22:07:59 +0100502 msg->len = len;
503 msg->tail = msg->data + len;
Harald Welteb0f91512012-01-14 21:53:41 +0100504
505 return 0;
506}
507
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200508/*! Trim the msgb to a given layer3 length
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100509 * \param[in] msg message buffer
Harald Welteb0f91512012-01-14 21:53:41 +0100510 * \param[in] l3len new layer3 length
511 * \returns 0 in case of success, negative in case of error
512 */
513static inline int msgb_l3trim(struct msgb *msg, int l3len)
514{
515 return msgb_trim(msg, (msg->l3h - msg->data) + l3len);
516}
517
Harald Welte179f3572019-03-18 18:38:47 +0100518/*! Allocate message buffer with specified headroom from specified talloc context.
519 * \param[in] ctx talloc context from which to allocate
520 * \param[in] size size in bytes, including headroom
521 * \param[in] headroom headroom in bytes
522 * \param[in] name human-readable name
523 * \returns allocated message buffer with specified headroom
524 *
525 * This function is a convenience wrapper around \ref msgb_alloc
526 * followed by \ref msgb_reserve in order to create a new \ref msgb with
527 * user-specified amount of headroom.
528 */
Pau Espin Pedrolaf40b0b2021-06-10 14:33:46 +0200529static inline struct msgb *msgb_alloc_headroom_c(const void *ctx, uint16_t size, uint16_t headroom,
Harald Welte179f3572019-03-18 18:38:47 +0100530 const char *name)
531{
Vadim Yanitskiy22ade292023-02-24 18:00:13 +0700532 OSMO_ASSERT(size >= headroom);
Harald Welte179f3572019-03-18 18:38:47 +0100533
534 struct msgb *msg = msgb_alloc_c(ctx, size, name);
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600535 if (OSMO_LIKELY(msg))
Harald Welte179f3572019-03-18 18:38:47 +0100536 msgb_reserve(msg, headroom);
537 return msg;
538}
539
540
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200541/*! Allocate message buffer with specified headroom
Harald Weltebd598e32011-08-16 23:26:52 +0200542 * \param[in] size size in bytes, including headroom
543 * \param[in] headroom headroom in bytes
544 * \param[in] name human-readable name
545 * \returns allocated message buffer with specified headroom
546 *
547 * This function is a convenience wrapper around \ref msgb_alloc
548 * followed by \ref msgb_reserve in order to create a new \ref msgb with
549 * user-specified amount of headroom.
550 */
Pau Espin Pedrolaf40b0b2021-06-10 14:33:46 +0200551static inline struct msgb *msgb_alloc_headroom(uint16_t size, uint16_t headroom,
Harald Welteec8b4502010-02-20 20:34:29 +0100552 const char *name)
553{
Vadim Yanitskiy22ade292023-02-24 18:00:13 +0700554 OSMO_ASSERT(size >= headroom);
Holger Hans Peter Freyther5853f082011-01-16 17:38:22 +0100555
Harald Welteec8b4502010-02-20 20:34:29 +0100556 struct msgb *msg = msgb_alloc(size, name);
Vadim Yanitskiy85c78312022-02-02 01:34:30 +0600557 if (OSMO_LIKELY(msg))
Harald Welteec8b4502010-02-20 20:34:29 +0100558 msgb_reserve(msg, headroom);
559 return msg;
560}
561
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200562/*! Check a message buffer for consistency
Jacob Erlbeck8db11342015-11-27 13:26:15 +0100563 * \param[in] msg message buffer
564 * \returns 0 (false) if inconsistent, != 0 (true) otherwise
565 */
566static inline int msgb_test_invariant(const struct msgb *msg)
567{
568 const unsigned char *lbound;
569 if (!msg || !msg->data || !msg->tail ||
570 (msg->data + msg->len != msg->tail) ||
571 (msg->data < msg->head) ||
572 (msg->tail > msg->head + msg->data_len))
573 return 0;
574
575 lbound = msg->head;
576
577 if (msg->l1h) {
578 if (msg->l1h < lbound)
579 return 0;
580 lbound = msg->l1h;
581 }
582 if (msg->l2h) {
583 if (msg->l2h < lbound)
584 return 0;
585 lbound = msg->l2h;
586 }
587 if (msg->l3h) {
588 if (msg->l3h < lbound)
589 return 0;
590 lbound = msg->l3h;
591 }
592 if (msg->l4h) {
593 if (msg->l4h < lbound)
594 return 0;
595 lbound = msg->l4h;
596 }
597
598 return lbound <= msg->head + msg->data_len;
599}
600
Maxdb038252018-12-03 14:14:44 +0100601
602/* msgb data comparison helpers */
603
604/*! Compare: check data in msgb against given data
605 * \param[in] msg message buffer
606 * \param[in] data expected data
607 * \param[in] len length of data
608 * \returns boolean indicating whether msgb content is equal to the given data
609 */
610#define msgb_eq_data(msg, data, len) \
611 _msgb_eq(__FILE__, __LINE__, __func__, 0, msg, data, len, false)
612
613/*! Compare: check L1 data in msgb against given data
614 * \param[in] msg message buffer
615 * \param[in] data expected L1 data
616 * \param[in] len length of data
617 * \returns boolean indicating whether msgb L1 content is equal to the given data
618 */
619#define msgb_eq_l1_data(msg, data, len) \
620 _msgb_eq(__FILE__, __LINE__, __func__, 1, msg, data, len, false)
621
622/*! Compare: check L2 data in msgb against given data
623 * \param[in] msg message buffer
624 * \param[in] data expected L2 data
625 * \param[in] len length of data
626 * \returns boolean indicating whether msgb L2 content is equal to the given data
627 */
628#define msgb_eq_l2_data(msg, data, len) \
629 _msgb_eq(__FILE__, __LINE__, __func__, 2, msg, data, len, false)
630
631/*! Compare: check L3 data in msgb against given data
632 * \param[in] msg message buffer
633 * \param[in] data expected L3 data
634 * \param[in] len length of data
635 * \returns boolean indicating whether msgb L3 content is equal to the given data
636 */
637#define msgb_eq_l3_data(msg, data, len) \
638 _msgb_eq(__FILE__, __LINE__, __func__, 3, msg, data, len, false)
639
640/*! Compare: check L4 data in msgb against given data
641 * \param[in] msg message buffer
642 * \param[in] data expected L4 data
643 * \param[in] len length of data
644 * \returns boolean indicating whether msgb L4 content is equal to the given data
645 */
646#define msgb_eq_l4_data(msg, data, len) \
647 _msgb_eq(__FILE__, __LINE__, __func__, 4, msg, data, len, false)
648
649
650/* msgb test/debug helpers */
651
652/*! Compare and print: check data in msgb against given data and print errors if any
653 * \param[in] msg message buffer
654 * \param[in] data expected data
655 * \param[in] len length of data
656 * \returns boolean indicating whether msgb content is equal to the given data
657 */
658#define msgb_eq_data_print(msg, data, len) \
659 _msgb_eq(__FILE__, __LINE__, __func__, 0, msg, data, len, true)
660
661/*! Compare and print: check L1 data in msgb against given data and print errors if any
662 * \param[in] msg message buffer
663 * \param[in] data expected L1 data
664 * \param[in] len length of data
665 * \returns boolean indicating whether msgb L1 content is equal to the given data
666 */
667#define msgb_eq_l1_data_print(msg, data, len) \
668 _msgb_eq(__FILE__, __LINE__, __func__, 1, msg, data, len, true)
669
670/*! Compare and print: check L2 data in msgb against given data and print errors if any
671 * \param[in] msg message buffer
672 * \param[in] data expected L2 data
673 * \param[in] len length of data
674 * \returns boolean indicating whether msgb L2 content is equal to the given data
675 */
676#define msgb_eq_l2_data_print(msg, data, len) \
677 _msgb_eq(__FILE__, __LINE__, __func__, 2, msg, data, len, true)
678
679/*! Compare and print: check L3 data in msgb against given data and print errors if any
680 * \param[in] msg message buffer
681 * \param[in] data expected L3 data
682 * \param[in] len length of data
683 * \returns boolean indicating whether msgb L3 content is equal to the given data
684 */
685#define msgb_eq_l3_data_print(msg, data, len) \
686 _msgb_eq(__FILE__, __LINE__, __func__, 3, msg, data, len, true)
687
688
689/*! Compare and print: check L4 data in msgb against given data and print errors if any
690 * \param[in] msg message buffer
691 * \param[in] data expected L4 data
692 * \param[in] len length of data
693 * \returns boolean indicating whether msgb L4 content is equal to the given data
694 */
695#define msgb_eq_l4_data_print(msg, data, len) \
696 _msgb_eq(__FILE__, __LINE__, __func__, 4, msg, data, len, true)
697
698bool _msgb_eq(const char *file, size_t line, const char *func, uint8_t level,
699 const struct msgb *msg, const uint8_t *data, size_t len, bool print);
700
701
702/* msgb data comparison */
703
704/*! Compare msgbs
705 * \param[in] msg1 message buffer
706 * \param[in] msg2 reference message buffer
707 * \returns boolean indicating whether msgb content is equal
708 */
Vadim Yanitskiyba426e32019-03-25 23:41:07 +0700709#define msgb_eq(msg1, msg2) msgb_eq_data(msg1, msgb_data(msg2), msgb_length(msg2))
Maxdb038252018-12-03 14:14:44 +0100710
711/*! Compare msgbs L1 content
712 * \param[in] msg1 message buffer
713 * \param[in] msg2 reference message buffer
714 * \returns boolean indicating whether msgb L1 content is equal
715 */
Vadim Yanitskiyba426e32019-03-25 23:41:07 +0700716#define msgb_eq_l1(msg1, msg2) msgb_eq_l1_data(msg1, msgb_l1(msg2), msgb_l1len(msg2))
Maxdb038252018-12-03 14:14:44 +0100717
718/*! Compare msgbs L2 content
719 * \param[in] msg1 message buffer
720 * \param[in] msg2 reference message buffer
721 * \returns boolean indicating whether msgb L2 content is equal
722 */
Vadim Yanitskiyba426e32019-03-25 23:41:07 +0700723#define msgb_eq_l2(msg1, msg2) msgb_eq_l2_data(msg1, msgb_l2(msg2), msgb_l2len(msg2))
Maxdb038252018-12-03 14:14:44 +0100724
725/*! Compare msgbs L3 content
726 * \param[in] msg1 message buffer
727 * \param[in] msg2 reference message buffer
728 * \returns boolean indicating whether msgb L3 content is equal
729 */
Vadim Yanitskiyba426e32019-03-25 23:41:07 +0700730#define msgb_eq_l3(msg1, msg2) msgb_eq_l3_data(msg1, msgb_l3(msg2), msgb_l3len(msg2))
Maxdb038252018-12-03 14:14:44 +0100731
732/*! Compare msgbs L4 content
733 * \param[in] msg1 message buffer
734 * \param[in] msg2 reference message buffer
735 * \returns boolean indicating whether msgb L4 content is equal
736 */
Vadim Yanitskiyba426e32019-03-25 23:41:07 +0700737#define msgb_eq_l4(msg1, msg2) msgb_eq_l4_data(msg1, msgb_l4(msg2), msgb_l4len(msg2))
Maxdb038252018-12-03 14:14:44 +0100738
739
Holger Hans Peter Freytheracffb602010-10-18 18:22:31 +0200740/* non inline functions to ease binding */
Harald Weltebd598e32011-08-16 23:26:52 +0200741
Holger Hans Peter Freytheracffb602010-10-18 18:22:31 +0200742uint8_t *msgb_data(const struct msgb *msg);
Neels Hofmeyrf45334b2016-09-16 00:15:56 +0200743
744void *msgb_talloc_ctx_init(void *root_ctx, unsigned int pool_size);
745void msgb_set_talloc_ctx(void *ctx) OSMO_DEPRECATED("Use msgb_talloc_ctx_init() instead");
Philipp Maierc5b47cc2017-10-10 16:53:21 +0200746int msgb_printf(struct msgb *msgb, const char *format, ...);
Holger Hans Peter Freytheracffb602010-10-18 18:22:31 +0200747
Maxcb02a392018-12-03 14:00:49 +0100748static inline const char *msgb_hexdump_l1(const struct msgb *msg)
749{
750 if (!msgb_l1(msg) || !(msgb_l1len(msg)))
751 return "[]";
752 return osmo_hexdump((const unsigned char *) msgb_l1(msg), msgb_l1len(msg));
753}
754
Harald Welte57217702018-02-09 02:01:48 +0100755static inline const char *msgb_hexdump_l2(const struct msgb *msg)
756{
757 if (!msgb_l2(msg) || !(msgb_l2len(msg)))
758 return "[]";
Harald Welteebd2b0f2018-02-09 10:32:03 +0100759 return osmo_hexdump((const unsigned char *) msgb_l2(msg), msgb_l2len(msg));
Harald Welte57217702018-02-09 02:01:48 +0100760}
761
762static inline const char *msgb_hexdump_l3(const struct msgb *msg)
763{
764 if (!msgb_l3(msg) || !(msgb_l3len(msg)))
765 return "[]";
Harald Welteebd2b0f2018-02-09 10:32:03 +0100766 return osmo_hexdump((const unsigned char*) msgb_l3(msg), msgb_l3len(msg));
Harald Welte57217702018-02-09 02:01:48 +0100767}
768
Maxcb02a392018-12-03 14:00:49 +0100769static inline const char *msgb_hexdump_l4(const struct msgb *msg)
770{
771 if (!msgb_l4(msg) || !(msgb_l4len(msg)))
772 return "[]";
773 return osmo_hexdump((const unsigned char*) msgb_l4(msg), msgb_l4len(msg));
774}
775
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200776/*! @} */