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
This commit is contained in:
parent
b3f713bd7b
commit
6dbe822062
78
src/llc.cpp
78
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()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void gprs_llc_queue::init()
|
||||
{
|
||||
INIT_LLIST_HEAD(&m_queue);
|
||||
m_queue_size = 0;
|
||||
m_avg_queue_delay = 0;
|
||||
}
|
||||
|
||||
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(&queue))) {
|
||||
bts->llc_dropped_frame();
|
||||
while ((msg = msgb_dequeue(&m_queue))) {
|
||||
if (bts)
|
||||
bts->llc_dropped_frame();
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
m_queue_size = 0;
|
||||
}
|
||||
|
||||
void gprs_llc::init()
|
||||
{
|
||||
INIT_LLIST_HEAD(&queue);
|
||||
m_queue_size = 0;
|
||||
m_avg_queue_delay = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
32
src/llc.h
32
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
14
src/tbf.h
14
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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue