llc_queue: Store MetaInfo in msgb headroom instead of cb[]

"sizeof(*meta_storage) <= sizeof(llc_msg->cb)" assert fails on debian 13
armv7l.
Since struct MetaInfo cannot always fit inside msgb->cb, move the struct
MetaInfo into the headroom of the msgb.

Related: OS#6831
Change-Id: I98d966c257d50d3b2fc326dce85ead5591acf51f
This commit is contained in:
Pau Espin Pedrol
2025-08-18 14:26:01 +02:00
parent deeb2194ea
commit 0273b89670
4 changed files with 35 additions and 42 deletions

View File

@@ -1369,13 +1369,10 @@ int ms_append_llc_dl_data(struct GprsMs *ms, uint16_t pdu_delay_csec, const uint
LOGPMS(ms, DTBFDL, LOGL_DEBUG, "appending %u bytes to DL LLC queue\n", len);
struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
if (!llc_msg)
return -ENOMEM;
llc_queue_calc_pdu_lifetime(ms->bts, pdu_delay_csec, &expire_time);
memcpy(msgb_put(llc_msg, len), data, len);
llc_queue_enqueue(ms_llc_queue(ms), llc_msg, &expire_time);
rc = llc_queue_enqueue(ms_llc_queue(ms), data, len, &expire_time);
if (rc < 0)
return rc;
ms_start_llc_timer(ms);
dl_tbf = ms_dl_tbf(ms);

View File

@@ -141,24 +141,34 @@ static enum gprs_llc_queue_prio llc_sapi2prio(uint8_t sapi)
}
}
void llc_queue_enqueue(struct gprs_llc_queue *q, struct msgb *llc_msg, const struct timespec *expire_time)
int llc_queue_enqueue(struct gprs_llc_queue *q, const uint8_t *data, uint16_t len, const struct timespec *expire_time)
{
struct msgb *llc_msg;
struct MetaInfo *meta_storage;
struct gprs_llc_hdr *llc_hdr = (struct gprs_llc_hdr *)msgb_data(llc_msg);
struct gprs_llc_hdr *llc_hdr;
enum gprs_llc_queue_prio prio;
osmo_static_assert(sizeof(*meta_storage) <= sizeof(llc_msg->cb), info_does_not_fit);
llc_msg = msgb_alloc_headroom(sizeof(*meta_storage) + len, sizeof(*meta_storage), "llc_pdu_queue");
if (!llc_msg)
return -ENOMEM;
prio = llc_sapi2prio(llc_hdr->sapi);
q->queue_size += 1;
q->queue_octets += msgb_length(llc_msg);
meta_storage = (struct MetaInfo *)&llc_msg->cb[0];
/* Fist set up MetaInfo in the msgb headroom: */
meta_storage = (struct MetaInfo *)llc_msg->head;
osmo_clock_gettime(CLOCK_MONOTONIC, &meta_storage->recv_time);
meta_storage->expire_time = *expire_time;
/* Copy PDU to msgb data: */
llc_hdr = (struct gprs_llc_hdr *)msgb_put(llc_msg, len);
memcpy(llc_hdr, data, len);
prio = llc_sapi2prio(llc_hdr->sapi);
/* Append: */
q->queue_size += 1;
q->queue_octets += msgb_length(llc_msg);
msgb_enqueue(&q->pq[prio].queue, llc_msg);
return 0;
}
void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts)
@@ -205,8 +215,8 @@ void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o
msg = msg1;
msg1 = NULL;
} else {
const struct MetaInfo *mi1 = (struct MetaInfo *)&msg1->cb[0];
const struct MetaInfo *mi2 = (struct MetaInfo *)&msg2->cb[0];
const struct MetaInfo *mi1 = (struct MetaInfo *)msg1->head;
const struct MetaInfo *mi2 = (struct MetaInfo *)msg2->head;
if (timespeccmp(&mi2->recv_time, &mi1->recv_time, >)) {
msg = msg1;
@@ -236,20 +246,21 @@ void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o
/* Prepend / Put back a previously dequeued LLC frame (llc_queue_dequeue()) */
void llc_queue_merge_prepend(struct gprs_llc_queue *q, const struct gprs_llc *llc)
{
struct msgb *llc_msg;
struct MetaInfo *meta_storage;
unsigned int len = llc_frame_length(llc);
struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
llc_msg = msgb_alloc_headroom(sizeof(*meta_storage) + len, sizeof(*meta_storage), "llc_pdu_queue");
OSMO_ASSERT(llc_msg);
memcpy(msgb_put(llc_msg, len), llc->frame, len);
q->queue_size += 1;
q->queue_octets += msgb_length(llc_msg);
meta_storage = (struct MetaInfo *)&llc_msg->cb[0];
meta_storage = (struct MetaInfo *)llc_msg->head;
memcpy(meta_storage, &llc->meta_info, sizeof(struct MetaInfo));
memcpy(msgb_put(llc_msg, len), llc->frame, len);
/* Prepend: */
q->queue_size += 1;
q->queue_octets += msgb_length(llc_msg);
llist_add(&llc_msg->list, &q->pq[llc->prio].queue);
}
@@ -272,7 +283,7 @@ static struct msgb *llc_queue_pick_msg(struct gprs_llc_queue *q, enum gprs_llc_q
if (!msg)
return NULL;
meta_storage = (struct MetaInfo *)&msg->cb[0];
meta_storage = (struct MetaInfo *)msg->head;
q->queue_size -= 1;
q->queue_octets -= msgb_length(msg);
@@ -305,7 +316,7 @@ struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, enum gprs_llc_queue_pri
timespecadd(&tv_now, &hyst_delta, &tv_now2);
while ((msg = llc_queue_pick_msg(q, &prio))) {
info = (const struct MetaInfo *)&msg->cb[0];
info = (const struct MetaInfo *)msg->head;
const struct timespec *tv_disc = &info->expire_time;
const struct timespec *tv_recv = &info->recv_time;

View File

@@ -139,7 +139,7 @@ void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts);
void llc_queue_set_codel_interval(struct gprs_llc_queue *q, unsigned int interval);
void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o);
void llc_queue_merge_prepend(struct gprs_llc_queue *q, const struct gprs_llc *llc);
void llc_queue_enqueue(struct gprs_llc_queue *q, struct msgb *llc_msg, const struct timespec *expire_time);
int llc_queue_enqueue(struct gprs_llc_queue *q, const uint8_t *data, uint16_t len, const struct timespec *expire_time);
struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, enum gprs_llc_queue_prio *out_prio, struct MetaInfo *out_info);
static inline size_t llc_queue_size(const struct gprs_llc_queue *q)

View File

@@ -56,21 +56,6 @@ static struct gprs_llc_queue *prepare_queue(void)
return ms_llc_queue(ms);
}
static void enqueue_data(gprs_llc_queue *queue, const uint8_t *data, size_t len,
const struct timespec *expire_time)
{
struct timespec *tv;
uint8_t *msg_data;
struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
"llc_pdu_queue");
msg_data = (uint8_t *)msgb_put(llc_msg, len);
memcpy(msg_data, data, len);
llc_queue_enqueue(queue, llc_msg, expire_time);
}
static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,
size_t len, const MetaInfo *exp_info)
{
@@ -96,7 +81,7 @@ static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,
static void enqueue_data(gprs_llc_queue *queue, const char *message,
const struct timespec *expire_time)
{
enqueue_data(queue, (uint8_t *)(message), strlen(message), expire_time);
llc_queue_enqueue(queue, (uint8_t *)(message), strlen(message), expire_time);
}
static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message,