From 6dbe822062d54a6c765c6fa7e2c6b79a5dff29b1 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 29 May 2015 10:37:09 +0200 Subject: llc: Separate LLC queue handling from gprs_llc Currently the gprs_llc class handles both LLC queueing and the partition into smaller pieces for RLC/MAC encapsulation. This hinders the separation of TBF and MS related data, since LLC queueing belongs to the MS related code while the RLC/MAC encoding/decoding belongs to the TBF layer. This commits takes the LLC queueing related methods and members and puts them into a new class gprs_llc_queue. It puts the queueing object into gprs_rlcmac_tbf and adds accessor functions. The implementation in tbf.cpp and tbf_dl.cpp is adapted accordingly. Ticket: #1674 Sponsored-by: On-Waves ehf --- src/llc.cpp | 76 ++++++++++++++++++++++++++++++---------------------------- src/llc.h | 32 +++++++++++++++++++------ src/tbf.cpp | 3 ++- src/tbf.h | 14 +++++++++++ src/tbf_dl.cpp | 20 ++++++++-------- 5 files changed, 91 insertions(+), 54 deletions(-) diff --git a/src/llc.cpp b/src/llc.cpp index 9c5581fb..09242a55 100644 --- a/src/llc.cpp +++ b/src/llc.cpp @@ -42,12 +42,6 @@ void gprs_llc::reset_frame_space() m_index = 0; } -void gprs_llc::enqueue(struct msgb *llc_msg) -{ - m_queue_size += 1; - msgb_enqueue(&queue, llc_msg); -} - /* Put an Unconfirmed Information (UI) Dummy command, see GSM 44.064, 6.4.2.2 */ void gprs_llc::put_dummy_frame(size_t req_len) { @@ -82,36 +76,62 @@ void gprs_llc::append_frame(const uint8_t *data, size_t len) m_length += len; } -void gprs_llc::clear(BTS *bts) +void gprs_llc::init() { - struct msgb *msg; + reset(); +} - while ((msg = msgb_dequeue(&queue))) { - bts->llc_dropped_frame(); - msgb_free(msg); - } +bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len) +{ + if (len < 2) + return false; - m_queue_size = 0; + if ((data[0] & 0x0f) == 1 /* GPRS_SAPI_GMM */) + return false; + + if ((data[0] & 0x0e) != 0xc0 /* LLC UI */) + /* It is not an LLC UI frame */ + return false; + + return true; } -void gprs_llc::init() +void gprs_llc_queue::init() { - INIT_LLIST_HEAD(&queue); + INIT_LLIST_HEAD(&m_queue); m_queue_size = 0; m_avg_queue_delay = 0; - reset(); +} + +void gprs_llc_queue::enqueue(struct msgb *llc_msg) +{ + m_queue_size += 1; + msgb_enqueue(&m_queue, llc_msg); +} + +void gprs_llc_queue::clear(BTS *bts) +{ + struct msgb *msg; + + while ((msg = msgb_dequeue(&m_queue))) { + if (bts) + bts->llc_dropped_frame(); + msgb_free(msg); + } + + m_queue_size = 0; } #define ALPHA 0.5f -struct msgb *gprs_llc::dequeue() +struct msgb *gprs_llc_queue::dequeue() { struct msgb *msg; struct timeval *tv, tv_now, tv_result; uint32_t lifetime; - msg = msgb_dequeue(&queue); + msg = msgb_dequeue(&m_queue); if (!msg) return NULL; @@ -128,8 +148,7 @@ struct msgb *gprs_llc::dequeue() return msg; } - -void gprs_llc::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv) +void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv) { uint16_t delay_csec; if (bts->bts_data()->force_llc_lifetime) @@ -152,7 +171,7 @@ void gprs_llc::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeradd(&now, &csec, tv); } -bool gprs_llc::is_frame_expired(struct timeval *tv_now, struct timeval *tv) +bool gprs_llc_queue::is_frame_expired(struct timeval *tv_now, struct timeval *tv) { /* Timeout is infinite */ if (tv->tv_sec == 0 && tv->tv_usec == 0) @@ -160,18 +179,3 @@ bool gprs_llc::is_frame_expired(struct timeval *tv_now, struct timeval *tv) return timercmp(tv_now, tv, >); } - -bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len) -{ - if (len < 2) - return false; - - if ((data[0] & 0x0f) == 1 /* GPRS_SAPI_GMM */) - return false; - - if ((data[0] & 0x0e) != 0xc0 /* LLC UI */) - /* It is not an LLC UI frame */ - return false; - - return true; -} diff --git a/src/llc.h b/src/llc.h index 11a0c7ed..251712a3 100644 --- a/src/llc.h +++ b/src/llc.h @@ -27,24 +27,18 @@ * I represent the LLC data to a MS */ struct gprs_llc { - static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv); - static bool is_frame_expired(struct timeval *now, struct timeval *tv); static bool is_user_data_frame(uint8_t *data, size_t len); void init(); void reset(); void reset_frame_space(); - void enqueue(struct msgb *llc_msg); - struct msgb *dequeue(); - 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); void consume(size_t len); void consume(uint8_t *data, size_t len); - void clear(BTS *bts); uint16_t chunk_size() const; uint16_t remaining_space() const; @@ -55,12 +49,31 @@ struct gprs_llc { 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 */ - struct llist_head queue; /* queued LLC DL data */ +}; + +/** + * I store the LLC frames that come from the SGSN. + */ +struct gprs_llc_queue { + static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv); + static bool is_frame_expired(struct timeval *now, struct timeval *tv); + static bool is_user_data_frame(uint8_t *data, size_t len); + + void init(); + + void enqueue(struct msgb *llc_msg); + struct msgb *dequeue(); + void clear(BTS *bts); + size_t size() const; +private: uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */ size_t m_queue_size; + struct llist_head m_queue; /* queued LLC DL data */ + }; + inline uint16_t gprs_llc::chunk_size() const { return m_length - m_index; @@ -92,3 +105,8 @@ inline bool gprs_llc::fits_in_current_frame(uint8_t chunk_size) const { return m_length + chunk_size <= LLC_MAX_LEN; } + +inline size_t gprs_llc_queue::size() const +{ + return this ? m_queue_size : 0; +} diff --git a/src/tbf.cpp b/src/tbf.cpp index 8501b161..dc26cc70 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -219,7 +219,7 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf) tbf_name(tbf)); tbf->stop_timer(); #warning "TODO: Could/Should generate bssgp_tx_llc_discarded" - tbf->m_llc.clear(tbf->bts); + tbf->llc_queue()->clear(tbf->bts); tbf_unlink_pdch(tbf); llist_del(&tbf->list.list); @@ -451,6 +451,7 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts, gettimeofday(&tbf->meas.rssi_tv, NULL); tbf->m_llc.init(); + tbf->llc_queue()->init(); return 0; } diff --git a/src/tbf.h b/src/tbf.h index d288669d..2a403c65 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -151,6 +151,8 @@ struct gprs_rlcmac_tbf { void assign_imsi(const char *imsi); uint8_t ta() const; void set_ta(uint8_t); + gprs_llc_queue *llc_queue(); + const gprs_llc_queue *llc_queue() const; time_t created_ts() const; @@ -229,6 +231,8 @@ protected: /* Field to take the TA value if no MS is associated */ uint8_t m_ta; + + gprs_llc_queue m_llc_queue; private: mutable char m_name_buf[60]; }; @@ -285,6 +289,16 @@ inline GprsMs *gprs_rlcmac_tbf::ms() return m_ms; } +inline gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() +{ + return &m_llc_queue; +} + +inline const gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() const +{ + return &m_llc_queue; +} + inline bool gprs_rlcmac_tbf::is_tlli_valid() const { return tlli() != 0; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 2289e3f0..5b9c06ca 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -122,11 +122,11 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class, if (!llc_msg) return -ENOMEM; tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); - gprs_llc::calc_pdu_lifetime(bts, pdu_delay_csec, tv); + gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, tv); tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); gettimeofday(tv, NULL); memcpy(msgb_put(llc_msg, len), data, len); - m_llc.enqueue(llc_msg); + llc_queue()->enqueue(llc_msg); tbf_update_ms_class(this, ms_class); start_llc_timer(); } @@ -253,7 +253,7 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx) gettimeofday(&tv_now, NULL); timeradd(&tv_now, &hyst_delta, &tv_now2); - while ((msg = m_llc.dequeue())) { + while ((msg = llc_queue()->dequeue())) { tv_disc = (struct timeval *)msg->data; msgb_pull(msg, sizeof(*tv_disc)); tv_recv = (struct timeval *)msg->data; @@ -262,11 +262,11 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx) gprs_bssgp_update_queue_delay(tv_recv, &tv_now); /* Is the age below the low water mark? */ - if (!gprs_llc::is_frame_expired(&tv_now2, tv_disc)) + if (!gprs_llc_queue::is_frame_expired(&tv_now2, tv_disc)) break; /* Is the age below the high water mark */ - if (!gprs_llc::is_frame_expired(&tv_now, tv_disc)) { + if (!gprs_llc_queue::is_frame_expired(&tv_now, tv_disc)) { /* Has the previous message not been dropped? */ if (frames == 0) break; @@ -297,7 +297,7 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx) LOGP(DRLCMACDL, LOGL_NOTICE, "%s Discarding LLC PDU " "because lifetime limit reached, " "count=%u new_queue_size=%zu\n", - tbf_name(this), frames, m_llc.m_queue_size); + tbf_name(this), frames, llc_queue()->size()); if (frames > 0xff) frames = 0xff; if (octets > 0xffffff) @@ -463,7 +463,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t break; } /* if FINAL chunk would fit precisely in space left */ - if (chunk == space && llist_empty(&m_llc.queue) && !keep_open(fn)) + if (chunk == space && llc_queue()->size() == 0 && !keep_open(fn)) { LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d " "would exactly fit into space (%d): because " @@ -794,8 +794,8 @@ void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len) new_tbf->m_llc.put_frame(data, len); bts->llc_frame_sched(); - while ((msg = m_llc.dequeue())) - new_tbf->m_llc.enqueue(msg); + while ((msg = llc_queue()->dequeue())) + new_tbf->llc_queue()->enqueue(msg); /* reset rlc states */ m_tx_counter = 0; @@ -836,7 +836,7 @@ bool gprs_rlcmac_dl_tbf::need_control_ts() const bool gprs_rlcmac_dl_tbf::have_data() const { - return m_llc.chunk_size() > 0 || !llist_empty(&m_llc.queue); + return m_llc.chunk_size() > 0 || llc_queue()->size() > 0; } int gprs_rlcmac_dl_tbf::frames_since_last_poll(unsigned fn) const -- cgit v1.2.3