diff options
Diffstat (limited to 'src/llc.h')
-rw-r--r-- | src/llc.h | 141 |
1 files changed, 82 insertions, 59 deletions
@@ -1,5 +1,6 @@ -/* +/* 3GPP TS 44.064 * Copyright (C) 2013 by Holger Hans Peter Freyther + * Copyright (C) 2022 by by Sysmocom s.f.m.c. GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -10,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #pragma once @@ -21,112 +18,138 @@ #ifdef __cplusplus extern "C" { #endif - #include <osmocom/core/linuxlist.h> -#ifdef __cplusplus -} -#endif #include <stdint.h> #include <string.h> #include <time.h> -#define LLC_MAX_LEN 1543 - -struct gprs_rlcmac_bts; +#include <osmocom/core/endian.h> +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/endian.h> -/** - * I represent the LLC data to a MS - */ -struct gprs_llc { +#include "gprs_codel.h" -#ifdef __cplusplus - static bool is_user_data_frame(uint8_t *data, size_t len); - - void init(); - void reset(); - void reset_frame_space(); +#define LLC_MAX_LEN 1543 - void put_frame(const uint8_t *data, size_t len); - void put_dummy_frame(size_t req_len); - void append_frame(const uint8_t *data, size_t len); +struct gprs_rlcmac_bts; +struct GprsMs; + +struct gprs_llc_hdr { +#if OSMO_IS_LITTLE_ENDIAN + union { /* 5.2, 6.2.0 */ + uint8_t address; + uint8_t sapi:4, unused:2, c_r:1, pd:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + union { + uint8_t address; + uint8_t pd:1, c_r:1, unused:2, sapi:4; #endif - - uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */ - uint16_t m_index; /* current write/read position of frame */ - uint16_t m_length; /* len of current DL LLC_frame, 0 == no frame */ -}; + }; + uint8_t control[0]; +} __attribute__ ((packed)); struct MetaInfo { struct timespec recv_time; struct timespec expire_time; }; +enum gprs_llc_queue_prio { /* lowest value has highest prio */ + LLC_QUEUE_PRIO_GMM = 0, /* SAPI 1 */ + LLC_QUEUE_PRIO_TOM_SMS, /* SAPI 2,7,8 */ + LLC_QUEUE_PRIO_OTHER, /* Other SAPIs */ + _LLC_QUEUE_PRIO_SIZE /* used to calculate size of enum */ +}; + /** - * I store the LLC frames that come from the SGSN. + * I represent the LLC data to a MS */ -struct gprs_llc_queue { -#ifdef __cplusplus - static void calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec, - struct timespec *tv); - static bool is_frame_expired(const struct timespec *now, - const struct timespec *tv); - static bool is_user_data_frame(uint8_t *data, size_t len); +struct gprs_llc { + uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */ + uint16_t index; /* current write/read position of frame */ + uint16_t length; /* len of current DL LLC_frame, 0 == no frame */ - void enqueue(struct msgb *llc_msg, const struct timespec *expire_time); - struct msgb *dequeue(const MetaInfo **info = 0); -#endif - uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */ - size_t m_queue_size; - size_t m_queue_octets; - struct llist_head m_queue; /* queued LLC DL data */ + /* Saved when dequeue from llc_queue; allows re-enqueing in the queue if Tx fails */ + enum gprs_llc_queue_prio prio; + struct MetaInfo meta_info; }; -#ifdef __cplusplus -extern "C" { -#endif -void llc_queue_init(struct gprs_llc_queue *q); -void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts); -void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o); +void llc_init(struct gprs_llc *llc); +void llc_reset(struct gprs_llc *llc); +void llc_reset_frame_space(struct gprs_llc *llc); + +void llc_put_frame(struct gprs_llc *llc, const uint8_t *data, size_t len); +void llc_put_dummy_frame(struct gprs_llc *llc, size_t req_len); +void llc_append_frame(struct gprs_llc *llc, const uint8_t *data, size_t len); static inline uint16_t llc_chunk_size(const struct gprs_llc *llc) { - return llc->m_length - llc->m_index; + return llc->length - llc->index; } static inline uint16_t llc_remaining_space(const struct gprs_llc *llc) { - return LLC_MAX_LEN - llc->m_length; + return LLC_MAX_LEN - llc->length; } static inline uint16_t llc_frame_length(const struct gprs_llc *llc) { - return llc->m_length; + return llc->length; } static inline void llc_consume(struct gprs_llc *llc, size_t len) { - llc->m_index += len; + llc->index += len; } static inline void llc_consume_data(struct gprs_llc *llc, uint8_t *data, size_t len) { /* copy and increment index */ - memcpy(data, llc->frame + llc->m_index, len); + memcpy(data, llc->frame + llc->index, len); llc_consume(llc, len); } static inline bool llc_fits_in_current_frame(const struct gprs_llc *llc, uint8_t chunk_size) { - return llc->m_length + chunk_size <= LLC_MAX_LEN; + return llc->length + chunk_size <= LLC_MAX_LEN; } +/** + * I store the LLC frames that come from the SGSN. + */ +struct gprs_llc_prio_queue { + struct gprs_codel codel_state; + struct llist_head queue; /* queued LLC DL data. See enum gprs_llc_queue_prio. */ +}; +struct gprs_llc_queue { + struct GprsMs *ms; /* backpointer */ + uint32_t avg_queue_delay; /* Average delay of data going through the queue */ + size_t queue_size; + size_t queue_octets; + bool use_codel; + struct gprs_llc_prio_queue pq[_LLC_QUEUE_PRIO_SIZE]; /* queued LLC DL data. See enum gprs_llc_queue_prio. */ +}; + +void llc_queue_calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec, + struct timespec *tv); +bool llc_queue_is_frame_expired(const struct timespec *tv_now, const struct timespec *tv); + +void llc_queue_init(struct gprs_llc_queue *q, struct GprsMs *ms); +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, struct gprs_llc *llc); +void llc_queue_enqueue(struct gprs_llc_queue *q, struct msgb *llc_msg, 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) { - return q->m_queue_size; + return q->queue_size; } static inline size_t llc_queue_octets(const struct gprs_llc_queue *q) { - return q->m_queue_octets; + return q->queue_octets; } #ifdef __cplusplus |