EGPRS support MCS1 to MCS9 in UL and DL

This release contains our EGPRS development done from December 2015 till
February 2016. It includes rebase from Jan 2016 Master branch of Git but
not the latest master available on date 22nd Feb 2016.

The code has been Unit tested. It has not been tested in any integration
environment.
For details on the feature changes please refer the README.
This commit is contained in:
Saurabh Sharan 2016-02-24 17:59:47 +05:30
parent f3f1bde4fc
commit bb549f4341
50 changed files with 18669 additions and 7008 deletions

22
README
View File

@ -2,6 +2,27 @@ This is an implementation of Packet Control Unit (PCU) according to TS 04.60
The PCU is part of BSS, so it connects directly to SGSN.
This release contains our EGPRS development done from December 2015 till February 2016. Please note that rebase from Master branch of Git was done on January 2016 so Latest submission on Master date 22nd February is not in our code base.
Main features added with important files where modification were done.
1) EGPRS MCS1 to MCS9 both in UL and DL.
rlc.h, rlc.cpp, tbf_dl.cpp, tbf_ul.cpp.
2) RLC retransmission, re-segmentation and split block support for both UL and DL.
rlc.cpp, tbf_ul.cpp, tbf_dl.cpp.
3) Selection of appropriate CPS for retransmission including padding of 6 octets case.
gprs_coding_scheme.cpp.
4) For encoding/decoding of compressed rbb in EGPRS ack/nack, implemented algorithm based on code word trees.
encoding.cpp, rlc.cpp.
5) Fix for length of descriptor in EPDAN bitmap.
gsm_rlcmac.h, gsm_rlcmac.cpp, bts.cpp.
6) Transmission/Reception of data flow for MCS1 to MCS9.
tbf_dl.cpp, tbf_ul.cpp, decoding.cpp.
7) Fix for encoding of padding bits.
csn1.cpp
8) Unit testing of the above implementation.
EdgeTest.cpp.
== Current limitations ==
@ -17,4 +38,3 @@ The PCU is part of BSS, so it connects directly to SGSN.
* No TA loop
* No power loop
* No CS loop
* No EGPRS

View File

@ -117,21 +117,3 @@ int bitvec_write_field(struct bitvec *bv, unsigned& write_index, uint64_t val, u
write_index += len;
return 0;
}
int bitvec_write_field_lh(struct bitvec *bv, unsigned& write_index,
uint64_t val, unsigned len)
{
unsigned int i;
int rc;
bv->cur_bit = write_index;
for (i = 0; i < len; i++) {
bit_value bit = L;
if (val & ((uint64_t)1 << (len - i - 1)))
bit = H;
rc = bitvec_set_bit(bv, bit);
if (rc)
return rc;
}
write_index += len;
return 0;
}

View File

@ -39,7 +39,6 @@ unsigned int bitvec_pack(struct bitvec *bv, uint8_t *buffer);
unsigned int bitvec_unpack(struct bitvec *bv, uint8_t *buffer);
uint64_t bitvec_read_field(struct bitvec *bv, unsigned& read_index, unsigned len);
int bitvec_write_field(struct bitvec *bv, unsigned& write_index, uint64_t val, unsigned len);
int bitvec_write_field_lh(struct bitvec *bv, unsigned& write_index, uint64_t val, unsigned len);
/*! }@ */

View File

@ -52,14 +52,11 @@ static BTS s_bts;
static const struct rate_ctr_desc bts_ctr_description[] = {
{ "tbf.dl.alloc", "TBF DL Allocated "},
{ "tbf.dl.freed", "TBF DL Freed "},
{ "tbf.dl.aborted", "TBF DL Aborted "},
{ "tbf.ul.alloc", "TBF UL Allocated "},
{ "tbf.ul.freed", "TBF UL Freed "},
{ "tbf.ul.aborted", "TBF UL Aborted "},
{ "tbf.reused", "TBF Reused "},
{ "tbf.alloc.algo-a", "TBF Alloc Algo A "},
{ "tbf.alloc.algo-b", "TBF Alloc Algo B "},
{ "tbf.failed.egprs-only", "TBF Failed EGPRS-only"},
{ "rlc.sent", "RLC Sent "},
{ "rlc.resent", "RLC Resent "},
{ "rlc.restarted", "RLC Restarted "},
@ -130,6 +127,8 @@ BTS::BTS()
, m_ms_store(this)
{
memset(&m_bts, 0, sizeof(m_bts));
INIT_LLIST_HEAD(&m_bts.ul_tbfs);
INIT_LLIST_HEAD(&m_bts.dl_tbfs);
m_bts.bts = this;
/* initialize back pointers */
@ -147,16 +146,17 @@ BTS::BTS()
m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 0);
m_statg = osmo_stat_item_group_alloc(tall_pcu_ctx, &bts_statg_desc, 0);
this->ones_list = (Node*)malloc(sizeof(Node));
this->zeros_list = (Node*)malloc(sizeof(Node));
build_codeword(this->ones_list, one_run_len_code_list);
build_codeword(this->zeros_list, zero_run_len_code_list);
}
BTS::~BTS()
{
/* this can cause counter updates and must not be left to the
* m_ms_store's destructor */
m_ms_store.cleanup();
rate_ctr_group_free(m_ratectrs);
osmo_stat_item_group_free(m_statg);
}
@ -177,6 +177,61 @@ void BTS::set_current_frame_number(int fn)
m_pollController.expireTimedout(m_cur_fn, max_delay);
}
void BTS::build_codeword(Node *root, const uint8_t* cdwd[])
{
Node *iter; /* iterate the node on the tree */
int len; /* length of the code word */
int i; /* iterater */
uint16_t idx; /* interate index of the code word table */
root->left = NULL;
root->right = NULL;
root->run_length = NULL;
for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) {
len = strlen((const char *)cdwd[idx]);
iter = root;
for ( i = 0; i < len; i ++) {
if (cdwd[idx][i] == '0') {
if (iter->left == NULL) {
iter->left = (Node*)malloc(sizeof(Node));
/* create a clean node */
iter->left->left = NULL;
iter->left->right = NULL;
iter->left->run_length = NULL;
}
iter = iter->left;
}
else if (cdwd[idx][i] == '1') {
if (iter->right == NULL) {
iter->right = (Node*)malloc(sizeof(Node));
/* create a clean node */
iter->right->left = NULL;
iter->right->right = NULL;
iter->right->run_length = NULL;
}
iter = iter->right;
}
}
/* iter = (Node*)malloc(sizeof(Node));
iter->left = NULL;
iter->right = NULL; */
if (iter != NULL)
{
iter->run_length = (uint16_t*)malloc(sizeof(uint16_t));
*(iter->run_length) = (uint16_t)NULL;
if (idx < 64)
*(iter->run_length) = idx;
else
*(iter->run_length) = (idx - 63) * 64;
}
else
{
}
}
} //build_codeword
void BTS::set_current_block_frame_number(int fn, unsigned max_delay)
{
int delay = 0;
@ -215,14 +270,14 @@ int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
{
uint8_t l, trx, ts, any_tbf = 0;
struct gprs_rlcmac_tbf *tbf;
LListHead<gprs_rlcmac_tbf> *pos;
struct llist_pods *lpods;
struct gprs_rlcmac_paging *pag;
uint8_t slot_mask[8];
int8_t first_ts; /* must be signed */
LListHead<gprs_rlcmac_tbf> *tbfs_lists[] = {
&m_ul_tbfs,
&m_dl_tbfs,
llist_head *tbfs_lists[] = {
&m_bts.ul_tbfs,
&m_bts.dl_tbfs,
NULL
};
@ -236,8 +291,7 @@ int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
* Don't mark, if TBF uses a different slot that is already marked. */
memset(slot_mask, 0, sizeof(slot_mask));
for (l = 0; tbfs_lists[l]; l++) {
llist_for_each(pos, tbfs_lists[l]) {
tbf = pos->entry();
llist_pods_for_each_entry(tbf, tbfs_lists[l], list, lpods) {
first_ts = -1;
for (ts = 0; ts < 8; ts++) {
if (tbf->pdch[ts]) {
@ -298,17 +352,16 @@ int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
gprs_rlcmac_dl_tbf *BTS::dl_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
{
struct gprs_rlcmac_dl_tbf *tbf;
LListHead<gprs_rlcmac_tbf> *pos;
struct llist_pods *lpods;
/* only one TBF can poll on specific TS/FN, because scheduler can only
* schedule one downlink control block (with polling) at a FN per TS */
llist_for_each(pos, &m_dl_tbfs) {
tbf = as_dl_tbf(pos->entry());
llist_pods_for_each_entry(tbf, &m_bts.dl_tbfs, list, lpods) {
if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
&& tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
&& tbf->poll_fn == fn && tbf->trx->trx_no == trx
&& tbf->poll_ts == ts) {
return tbf;
&& tbf->control_ts == ts) {
return static_cast<gprs_rlcmac_dl_tbf *>(tbf);
}
}
return NULL;
@ -316,17 +369,16 @@ gprs_rlcmac_dl_tbf *BTS::dl_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
gprs_rlcmac_ul_tbf *BTS::ul_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
{
struct gprs_rlcmac_ul_tbf *tbf;
LListHead<gprs_rlcmac_tbf> *pos;
struct llist_pods *lpods;
/* only one TBF can poll on specific TS/FN, because scheduler can only
* schedule one downlink control block (with polling) at a FN per TS */
llist_for_each(pos, &m_ul_tbfs) {
tbf = as_ul_tbf(pos->entry());
llist_pods_for_each_entry(tbf, &m_bts.ul_tbfs, list, lpods) {
if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
&& tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
&& tbf->poll_fn == fn && tbf->trx->trx_no == trx
&& tbf->poll_ts == ts) {
return tbf;
&& tbf->control_ts == ts) {
return static_cast<gprs_rlcmac_ul_tbf *>(tbf);
}
}
return NULL;
@ -466,10 +518,7 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
uint8_t sb = 0;
uint32_t sb_fn = 0;
int rc;
int plen;
uint8_t usf = 7;
uint8_t tsc;
uint16_t ta;
uint8_t plen;
rach_frame();
@ -488,11 +537,8 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
qta = 0;
if (qta > 252)
qta = 252;
ta = qta >> 2;
if (sb) {
rc = sba()->alloc(&trx_no, &ts_no, &sb_fn, ta);
rc = sba()->alloc(&trx_no, &ts_no, &sb_fn, qta >> 2);
if (rc < 0)
return rc;
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] RACH qbit-ta=%d "
@ -502,7 +548,6 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
sb_fn);
LOGP(DRLCMAC, LOGL_INFO, "TX: Immediate Assignment Uplink "
"(AGCH)\n");
tsc = m_bts.trx[trx_no].pdch[ts_no].tsc;
} else {
// Create new TBF
#warning "Copy and pate with other routines.."
@ -513,7 +558,7 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
/* FIXME: send reject */
return -EBUSY;
}
tbf->set_ta(ta);
tbf->set_ta(qta >> 2);
tbf->set_state(GPRS_RLCMAC_FLOW);
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
tbf_timer_start(tbf, 3169, m_bts.t3169, 0);
@ -525,31 +570,21 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
LOGP(DRLCMAC, LOGL_INFO, "%s TX: START Immediate "
"Assignment Uplink (AGCH)\n", tbf_name(tbf));
trx_no = tbf->trx->trx_no;
ts_no = tbf->first_ts;
usf = tbf->m_usf[ts_no];
tsc = tbf->tsc();
}
bitvec *immediate_assignment = bitvec_alloc(22) /* without plen */;
bitvec_unhex(immediate_assignment,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
LOGP(DRLCMAC, LOGL_DEBUG,
" - TRX=%d (%d) TS=%d TA=%d TSC=%d TFI=%d USF=%d\n",
trx_no, m_bts.trx[trx_no].arfcn, ts_no, ta, tsc,
tbf ? tbf->tfi() : -1, usf);
plen = Encoding::write_immediate_assignment(
tbf, immediate_assignment, 0, ra, Fn, ta,
m_bts.trx[trx_no].arfcn, ts_no, tsc, usf, 0, sb_fn,
m_bts.alpha, m_bts.gamma, -1);
if (plen >= 0) {
pcu_l1if_tx_agch(immediate_assignment, plen);
if (tbf)
tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN);
}
if (sb)
plen = Encoding::write_immediate_assignment(&m_bts, immediate_assignment, 0, ra,
Fn, qta >> 2, m_bts.trx[trx_no].arfcn, ts_no,
m_bts.trx[trx_no].pdch[ts_no].tsc, 0, 0, 0, 0, sb_fn, 1,
m_bts.alpha, m_bts.gamma, -1, 0);
else
plen = Encoding::write_immediate_assignment(&m_bts, immediate_assignment, 0, ra,
Fn, tbf->ta(), tbf->trx->arfcn, tbf->first_ts, tbf->tsc(),
tbf->tfi(), tbf->m_usf[tbf->first_ts], 0, 0, 0, 0,
m_bts.alpha, m_bts.gamma, -1, -1);
pcu_l1if_tx_agch(immediate_assignment, plen);
bitvec_free(immediate_assignment);
return 0;
@ -573,8 +608,7 @@ void BTS::trigger_dl_ass(
/* change state */
dl_tbf->set_state(GPRS_RLCMAC_ASSIGN);
if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
/* start timer */
tbf_timer_start(dl_tbf, 0, Tassign_pacch);
} else {
@ -592,24 +626,17 @@ void BTS::trigger_dl_ass(
void BTS::snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi)
{
int plen;
unsigned int ts = tbf->first_ts;
LOGP(DRLCMAC, LOGL_INFO, "TX: START %s Immediate Assignment Downlink (PCH)\n", tbf_name(tbf));
bitvec *immediate_assignment = bitvec_alloc(22); /* without plen */
bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
/* use request reference that has maximum distance to current time,
* so the assignment will not conflict with possible RACH requests. */
LOGP(DRLCMAC, LOGL_DEBUG, " - TRX=%d (%d) TS=%d TA=%d pollFN=%d\n",
tbf->trx->trx_no, tbf->trx->arfcn,
ts, tbf->ta(), poll ? tbf->poll_fn : -1);
plen = Encoding::write_immediate_assignment(tbf, immediate_assignment, 1, 125,
(tbf->pdch[ts]->last_rts_fn + 21216) % 2715648, tbf->ta(),
tbf->trx->arfcn, ts, tbf->tsc(), 7, poll,
tbf->poll_fn, m_bts.alpha, m_bts.gamma, -1);
if (plen >= 0) {
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN);
}
plen = Encoding::write_immediate_assignment(&m_bts, immediate_assignment, 1, 125,
(tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta(),
tbf->trx->arfcn, tbf->first_ts, tbf->tsc(), tbf->tfi(), 0, tbf->tlli(), poll,
tbf->poll_fn, 0, m_bts.alpha, m_bts.gamma, -1, tbf->is_egprs_enabled());
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
bitvec_free(immediate_assignment);
}
@ -804,19 +831,9 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
"TBF is gone TLLI=0x%08x\n", tlli);
return;
}
if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE) &&
tbf->direction == new_tbf->direction)
if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE))
tbf_free(tbf);
if ((new_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) {
/* We now know that the PACCH really existed */
LOGP(DRLCMAC, LOGL_INFO,
"The TBF has been confirmed on the PACCH, "
"changed type from CCCH to PACCH for %s\n",
tbf_name(new_tbf));
new_tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
new_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
}
new_tbf->set_state(GPRS_RLCMAC_FLOW);
/* stop pending assignment timer */
new_tbf->stop_timer();
@ -842,8 +859,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
"TBF is gone TLLI=0x%08x\n", tlli);
return;
}
if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE) &&
tbf->direction == new_tbf->direction)
if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE))
tbf_free(tbf);
new_tbf->set_state(GPRS_RLCMAC_FLOW);
@ -924,18 +940,121 @@ static void get_meas(struct pcu_l1_meas *meas,
}
}
}
static void get_meas(struct pcu_l1_meas *meas,
EGPRS_ChannelQualityReport_t *qr)
{
int8_t i;
EGPRS_TimeslotLinkQualityMeasurements_t *tslqmeas;
EGPRS_BEP_LinkQualityMeasurements_t *beplqmeas;
tslqmeas = &qr->EGPRS_TimeslotLinkQualityMeasurements;
beplqmeas = &qr->EGPRS_BEP_LinkQualityMeasurements;
//TODO: need to check if manipulation required
if (beplqmeas->Exist_MEAN_CV_BEP_GMSK) {
meas->set_mean_cv_bep_gmsk(beplqmeas->MEAN_BEP_GMSK, beplqmeas->CV_BEP_GMSK);
}
if (beplqmeas->Exist_MEAN_CV_BEP_8PSK) {
meas->set_mean_cv_bep_8psk(beplqmeas->MEAN_BEP_8PSK, beplqmeas->CV_BEP_8PSK);
}
meas->set_ms_c_value(qr->C_VALUE);
if(tslqmeas->Exist_BEP_MEASUREMENTS) {
for(i = 0; i < 8; i++) {
if (tslqmeas->BEP_MEASUREMENTS[i].Exist) {
if (tslqmeas->BEP_MEASUREMENTS[i].UnionType == 0) {
meas->set_bep_mean_gmsk(
tslqmeas->BEP_MEASUREMENTS[i].u.MEAN_BEP_GMSK);
}
else {
meas->set_bep_mean_8psk(
tslqmeas->BEP_MEASUREMENTS[i].u.MEAN_BEP_8PSK);
}
}
}
}
if(tslqmeas->Exist_INTERFERENCE_MEASUREMENTS) {
for(i = 0; i < 8; i++) {
if (tslqmeas->INTERFERENCE_MEASUREMENTS[i].Exist) {
LOGP(DRLCMAC, LOGL_INFO,
"EGPRS Channel quality report: i_level[%d] = %d\n",
i, tslqmeas->INTERFERENCE_MEASUREMENTS[i].I_LEVEL);
meas->set_ms_i_level(i, -2 * tslqmeas->INTERFERENCE_MEASUREMENTS[i].I_LEVEL);
}
}
}
}
void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nack, uint32_t fn)
{
int8_t tfi = 0; /* must be signed */
struct gprs_rlcmac_dl_tbf *tbf;
int rc;
struct pcu_l1_meas meas;
tfi = ack_nack->DOWNLINK_TFI;
tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
"unknown FN=%u TFI=%d (TRX %d TS %d)\n",
fn, tfi, trx_no(), ts_no);
return;
}
if (tbf->tfi() != tfi) {
LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
"wrong TFI=%d, ignoring!\n", tfi);
return;
}
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_DL_ACK);
if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
LOGP(DRLCMAC, LOGL_NOTICE, "Recovered downlink ack "
"for %s\n", tbf_name(tbf));
}
/* reset N3105 */
tbf->n3105 = 0;
tbf->stop_t3191();
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s EGPRS Packet Downlink Ack/Nack\n", tbf_name(tbf));
tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
if (ack_nack->UnionType == 0)
rc = tbf->rcvd_egprs_dl_ack(&ack_nack->u.EGPRS_AckNack.Desc, 0);
else
rc = tbf->rcvd_egprs_dl_ack(&ack_nack->u.EGPRS_AckNack_len.Desc,
ack_nack->u.EGPRS_AckNack_len.LENGTH);
if (rc == 1) {
tbf_free(tbf);
return;
}
/* check for channel request */
if (ack_nack->Exist_ChannelRequestDescription) {
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
"message, so we provide one:\n");
/* This call will register the new TBF with the MS on success */
tbf_alloc_ul(bts_data(), tbf->trx->trx_no,
tbf->ms_class(), tbf->ms()->egprs_ms_class(),
tbf->tlli(), tbf->ta(), tbf->ms());
/* schedule uplink assignment */
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
}
/* get measurements */
if ((tbf->ms()) && ack_nack->Exist_EGPRS_ChannelQualityReport) {
get_meas(&meas, &ack_nack->EGPRS_ChannelQualityReport);
//TODO: Need to update these into MS context
//tbf->ms()->update_egprs_l1_meas(&meas);
}
}
void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_nack, uint32_t fn)
{
int8_t tfi = 0; /* must be signed */
struct gprs_rlcmac_dl_tbf *tbf;
int rc;
struct pcu_l1_meas meas;
int num_blocks;
uint8_t bits_data[RLC_GPRS_WS/8];
bitvec bits;
int bsn_begin, bsn_end;
char show_bits[RLC_GPRS_WS + 1];
tfi = ack_nack->DOWNLINK_TFI;
tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
@ -962,24 +1081,10 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s Packet Downlink Ack/Nack\n", tbf_name(tbf));
tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
bits.data = bits_data;
bits.data_len = sizeof(bits_data);
bits.cur_bit = 0;
num_blocks = Decoding::decode_gprs_acknack_bits(
&ack_nack->Ack_Nack_Description, &bits,
&bsn_begin, &bsn_end, &tbf->m_window);
LOGP(DRLCMAC, LOGL_DEBUG,
"Got GPRS DL ACK bitmap: SSN: %d, BSN %d to %d - 1 (%d blocks), "
"\"%s\"\n",
ack_nack->Ack_Nack_Description.STARTING_SEQUENCE_NUMBER,
bsn_begin, bsn_end, num_blocks,
(Decoding::extract_rbb(&bits, show_bits), show_bits));
rc = tbf->rcvd_dl_ack(
ack_nack->Ack_Nack_Description.FINAL_ACK_INDICATION,
bsn_begin, &bits);
ack_nack->Ack_Nack_Description.STARTING_SEQUENCE_NUMBER,
ack_nack->Ack_Nack_Description.RECEIVED_BLOCK_BITMAP);
if (rc == 1) {
tbf_free(tbf);
return;
@ -1004,112 +1109,6 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
}
}
void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nack, uint32_t fn)
{
int8_t tfi = 0; /* must be signed */
struct gprs_rlcmac_dl_tbf *tbf;
struct pcu_l1_meas meas;
int rc;
int num_blocks;
uint8_t bits_data[RLC_EGPRS_MAX_WS/8];
char show_bits[RLC_EGPRS_MAX_WS + 1];
bitvec bits;
int bsn_begin, bsn_end;
tfi = ack_nack->DOWNLINK_TFI;
tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
"unknown FN=%u TFI=%d (TRX %d TS %d)\n",
fn, tfi, trx_no(), ts_no);
return;
}
if (tbf->tfi() != tfi) {
LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
"wrong TFI=%d, ignoring!\n", tfi);
return;
}
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_DL_ACK);
if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
LOGP(DRLCMAC, LOGL_NOTICE, "Recovered EGPRS downlink ack "
"for %s\n", tbf_name(tbf));
}
/* reset N3105 */
tbf->n3105 = 0;
tbf->stop_t3191();
LOGP(DRLCMAC, LOGL_DEBUG,
"RX: [PCU <- BTS] %s EGPRS Packet Downlink Ack/Nack\n",
tbf_name(tbf));
tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
LOGP(DRLCMAC, LOGL_DEBUG, "EGPRS ACK/NACK: "
"ut: %d, final: %d, bow: %d, eow: %d, ssn: %d, have_crbb: %d, "
"urbb_len:%d, %p, %p, %d, %d, win: %d-%d, urbb: %s\n",
(int)ack_nack->EGPRS_AckNack.UnionType,
(int)ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
(int)ack_nack->EGPRS_AckNack.Desc.BEGINNING_OF_WINDOW,
(int)ack_nack->EGPRS_AckNack.Desc.END_OF_WINDOW,
(int)ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
(int)ack_nack->EGPRS_AckNack.Desc.Exist_CRBB,
(int)ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH,
(void *)&ack_nack->EGPRS_AckNack.UnionType,
(void *)&ack_nack->EGPRS_AckNack.Desc,
(int)offsetof(EGPRS_AckNack_t, Desc),
(int)offsetof(EGPRS_AckNack_w_len_t, Desc),
tbf->m_window.v_a(),
tbf->m_window.v_s(),
osmo_hexdump((const uint8_t *)&ack_nack->EGPRS_AckNack.Desc.URBB,
sizeof(ack_nack->EGPRS_AckNack.Desc.URBB)));
bits.data = bits_data;
bits.data_len = sizeof(bits_data);
bits.cur_bit = 0;
num_blocks = Decoding::decode_egprs_acknack_bits(
&ack_nack->EGPRS_AckNack.Desc, &bits,
&bsn_begin, &bsn_end, &tbf->m_window);
LOGP(DRLCMAC, LOGL_DEBUG,
"Got EGPRS DL ACK bitmap: SSN: %d, BSN %d to %d - 1 (%d blocks), "
"\"%s\"\n",
ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
bsn_begin, bsn_end, num_blocks,
(Decoding::extract_rbb(&bits, show_bits), show_bits)
);
rc = tbf->rcvd_dl_ack(
ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
bsn_begin, &bits);
if (rc == 1) {
tbf_free(tbf);
return;
}
/* check for channel request */
if (ack_nack->Exist_ChannelRequestDescription) {
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
"message, so we provide one:\n");
/* This call will register the new TBF with the MS on success */
tbf_alloc_ul(bts_data(), tbf->trx->trx_no,
tbf->ms_class(), tbf->ms()->egprs_ms_class(),
tbf->tlli(), tbf->ta(), tbf->ms());
/* schedule uplink assignment */
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
}
/* get measurements */
if (tbf->ms()) {
/* TODO: Implement Measurements parsing for EGPRS */
/*
get_meas(&meas, &ack_nack->Channel_Quality_Report);
tbf->ms()->update_l1_meas(&meas);
*/
}
}
void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn)
{
struct gprs_rlcmac_sba *sba;
@ -1133,24 +1132,28 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
ta = ms->ta();
}
/* We got a RACH so the MS was in packet idle mode and thus
* didn't have any active TBFs */
if (ul_tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still "
"exists. Killing pending UL TBF\n",
tlli, tbf_name(ul_tbf));
/* The MS will not use the old TBF again, so we can
* safely throw it away immediately */
tbf_free(ul_tbf);
ul_tbf = NULL;
}
if (dl_tbf) {
/* TODO: There a chance that releasing dl_tbf can be
* avoided if this PDCH is the control TS of dl_tbf,
* but this needs to be checked with the spec. If an MS
* losed the DL TBF because of PDCH mismatches only,
* this check would make sense. */
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still exists. "
"Release pending DL TBF\n", tlli,
tbf_name(dl_tbf));
tbf_free(dl_tbf);
dl_tbf = NULL;
dl_tbf->release();
}
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
"in packet resource request of single "
@ -1287,133 +1290,120 @@ int gprs_rlcmac_pdch::rcv_control_block(
return 1;
}
int gprs_rlcmac_pdch::rcv_block_gprs(uint8_t *data, uint32_t fn,
struct pcu_l1_meas *meas, GprsCodingScheme cs)
{
unsigned payload = data[0] >> 6;
bitvec *block;
int rc = 0;
unsigned len = cs.maxBytesUL();
switch (payload) {
case GPRS_RLCMAC_DATA_BLOCK:
rc = rcv_data_data_block(data, fn, meas, cs);
break;
case GPRS_RLCMAC_CONTROL_BLOCK:
block = bitvec_alloc(len);
if (!block)
return -ENOMEM;
bitvec_unpack(block, data);
rc = rcv_control_block(block, fn);
bitvec_free(block);
break;
case GPRS_RLCMAC_CONTROL_BLOCK_OPT:
LOGP(DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n");
break;
default:
LOGP(DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload(%u).\n", payload);
rc = -EINVAL;
}
return rc;
}
int gprs_rlcmac_pdch::rcv_data_data_block(uint8_t *data, uint32_t fn,
struct pcu_l1_meas *meas, GprsCodingScheme cs)
{
int rc;
struct gprs_rlc_ul_header_generic rlc_dec;
struct gprs_rlcmac_ul_tbf *tbf;
unsigned len = cs.maxBytesUL();
/* These are always data blocks, since EGPRS still uses CS-1 for
* control blocks (see 44.060, section 10.3, 1st par.)
*/
if (cs.isEgprs()) {
if (!bts()->bts_data()->egprs_enabled) {
LOGP(DRLCMACUL, LOGL_ERROR,
"Got %s RLC block but EGPRS is not enabled\n",
cs.name());
return -EINVAL;
}
}
LOGP(DRLCMACUL, LOGL_DEBUG, " UL data: %s\n", osmo_hexdump(data, len));
rc = Decoding::rlc_parse_ul_data_header(&rlc_dec, data, cs);
if (rc == -ENOTSUP ) {
LOGP(DRLCMACUL, LOGL_ERROR,
"Got %s RLC block but header parsing has failed\n",
cs.name());
bts()->decode_error();
return rc;
}
LOGP(DRLCMACUL, LOGL_INFO,
"Got %s RLC block: "
"R=%d, SI=%d, TFI=%d, CPS=%d, RSB=%d\n",
cs.name(),
rlc_dec.r, rlc_dec.si, rlc_dec.tfi, rlc_dec.cps, rlc_dec.rsb
);
/* find TBF inst from given TFI */
tbf = ul_tbf_by_tfi(rlc_dec.tfi);
if (!tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
rlc_dec.tfi);
return 0;
}
return tbf->rcv_data_block_acknowledged(&rlc_dec, data, len, meas);
}
/* received RLC/MAC block from L1 */
int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
struct pcu_l1_meas *meas)
{
GprsCodingScheme cs = GprsCodingScheme::getBySizeUL(len);
if (!cs) {
bts()->decode_error();
LOGP(DRLCMACUL, LOGL_ERROR, "Dropping data block with invalid"
"length: %d)\n", len);
return -EINVAL;
}
LOGP(DRLCMACUL, LOGL_DEBUG, "Got RLC block, coding scheme: %s, "
"length: %d (%d))\n", cs.name(), len, cs.usedSizeUL());
if (cs.isGprs())
return rcv_block_gprs(data, fn, meas, cs);
if (cs.isEgprs())
return rcv_data_block(data, fn, meas, cs);
bts()->decode_error();
LOGP(DRLCMACUL, LOGL_ERROR, "Unsupported coding scheme %s\n",
cs.name());
return -EINVAL;
if (!cs) {
bts()->decode_error();
LOGP(DRLCMACUL, LOGL_ERROR, "Dropping data block with invalid"
"length: %d)\n", len);
return -EINVAL;
}
LOGP(DRLCMACUL, LOGL_DEBUG, "Got RLC block, coding scheme: %s, "
"length: %d (%d))\n", cs.name(), len, cs.maxBytesUL());
if (cs.isGprs())
return rcv_block_gprs(data, fn, meas, cs);
if (cs.isEgprs())
return rcv_data_data_block(data, fn, meas, cs);
bts()->decode_error();
LOGP(DRLCMACUL, LOGL_ERROR, "Unsupported coding scheme %s\n",
cs.name());
return -EINVAL;
}
int gprs_rlcmac_pdch::rcv_data_block(uint8_t *data, uint32_t fn,
struct pcu_l1_meas *meas, GprsCodingScheme cs)
{
int rc;
struct gprs_rlc_data_info rlc_dec;
struct gprs_rlcmac_ul_tbf *tbf;
unsigned len = cs.sizeUL();
/* These are always data blocks, since EGPRS still uses CS-1 for
* control blocks (see 44.060, section 10.3, 1st par.)
*/
if (cs.isEgprs()) {
if (!bts()->bts_data()->egprs_enabled) {
LOGP(DRLCMACUL, LOGL_ERROR,
"Got %s RLC block but EGPRS is not enabled\n",
cs.name());
return -EINVAL;
}
if (!cs.isEgprsGmsk()) {
LOGP(DRLCMACUL, LOGL_ERROR,
"Got %s RLC block but EGPRS is not implemented "
"for 8PSK yet\n",
cs.name());
bts()->decode_error();
return -EINVAL;
}
}
LOGP(DRLCMACUL, LOGL_DEBUG, " UL data: %s\n", osmo_hexdump(data, len));
rc = Decoding::rlc_parse_ul_data_header(&rlc_dec, data, cs);
if (rc < 0) {
LOGP(DRLCMACUL, LOGL_ERROR,
"Got %s RLC block but header parsing has failed\n",
cs.name());
bts()->decode_error();
return rc;
}
LOGP(DRLCMACUL, LOGL_INFO,
"Got %s RLC block: "
"R=%d, SI=%d, TFI=%d, CPS=%d, RSB=%d, "
"rc=%d\n",
cs.name(),
rlc_dec.r, rlc_dec.si, rlc_dec.tfi, rlc_dec.cps, rlc_dec.rsb,
rc);
/* find TBF inst from given TFI */
tbf = ul_tbf_by_tfi(rlc_dec.tfi);
if (!tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
rlc_dec.tfi);
return 0;
}
return tbf->rcv_data_block_acknowledged(&rlc_dec, data, meas);
}
int gprs_rlcmac_pdch::rcv_block_gprs(uint8_t *data, uint32_t fn,
struct pcu_l1_meas *meas, GprsCodingScheme cs)
{
unsigned payload = data[0] >> 6;
bitvec *block;
int rc = 0;
unsigned len = cs.maxBytesUL();
switch (payload) {
case GPRS_RLCMAC_DATA_BLOCK:
rc = rcv_data_block(data, fn, meas, cs);
break;
case GPRS_RLCMAC_CONTROL_BLOCK:
block = bitvec_alloc(len);
if (!block)
return -ENOMEM;
bitvec_unpack(block, data);
rc = rcv_control_block(block, fn);
bitvec_free(block);
break;
case GPRS_RLCMAC_CONTROL_BLOCK_OPT:
LOGP(DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n");
break;
default:
LOGP(DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload(%u).\n", payload);
rc = -EINVAL;
}
return rc;
}
gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(
LListHead<gprs_rlcmac_tbf> *tbf_list, uint8_t tfi,
gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(struct llist_head *tbf_list, uint8_t tfi,
enum gprs_rlcmac_tbf_direction dir)
{
gprs_rlcmac_tbf *tbf;
LListHead<gprs_rlcmac_tbf> *pos;
struct llist_pods *lpods;
llist_for_each(pos, tbf_list) {
tbf = pos->entry();
llist_pods_for_each_entry(tbf, tbf_list, list, lpods) {
if (tbf->tfi() != tfi)
continue;
if (!tbf->pdch[ts_no])
@ -1425,12 +1415,14 @@ gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(
gprs_rlcmac_ul_tbf *gprs_rlcmac_pdch::ul_tbf_by_tfi(uint8_t tfi)
{
return as_ul_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF));
return static_cast<gprs_rlcmac_ul_tbf *>(
tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF));
}
gprs_rlcmac_dl_tbf *gprs_rlcmac_pdch::dl_tbf_by_tfi(uint8_t tfi)
{
return as_dl_tbf(tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF));
return static_cast<gprs_rlcmac_dl_tbf *>(
tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF));
}
/* lookup TBF Entity (by TFI) */
@ -1466,7 +1458,7 @@ void gprs_rlcmac_pdch::attach_tbf(gprs_rlcmac_tbf *tbf)
m_num_tbfs[tbf->direction] += 1;
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
ul_tbf = as_ul_tbf(tbf);
ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
m_assigned_usf |= 1 << ul_tbf->m_usf[ts_no];
}
m_assigned_tfi[tbf->direction] |= 1UL << tbf->tfi();
@ -1486,7 +1478,7 @@ void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf)
m_num_tbfs[tbf->direction] -= 1;
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
ul_tbf = as_ul_tbf(tbf);
ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
m_assigned_usf &= ~(1 << ul_tbf->m_usf[ts_no]);
}
m_assigned_tfi[tbf->direction] &= ~(1UL << tbf->tfi());

View File

@ -27,7 +27,6 @@ extern "C" {
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/gsmtap.h>
}
#include "poll_controller.h"
@ -45,6 +44,20 @@ extern "C" {
struct BTS;
struct GprsMs;
#define MAX_CDWDTBL_LEN 79 /* total number of codewords */
#define BITS_TO_BYTES(X) (X ? (X/8):0)+1
#define MOD8(X) (((X)+8)&0x07)
#define MOD64(X) ((X + 64) & 0x3F)
extern const uint8_t* one_run_len_code_list[MAX_CDWDTBL_LEN];
extern const uint8_t* zero_run_len_code_list[MAX_CDWDTBL_LEN];
typedef struct node
{
struct node* left;
struct node* right;
uint16_t *run_length;
} Node;
/*
* PDCH instance
*/
@ -67,7 +80,7 @@ struct gprs_rlcmac_pdch {
struct pcu_l1_meas *meas);
int rcv_block_gprs(uint8_t *data, uint32_t fn,
struct pcu_l1_meas *meas, GprsCodingScheme cs);
int rcv_data_block(uint8_t *data, uint32_t fn,
int rcv_data_data_block(uint8_t *data, uint32_t fn,
struct pcu_l1_meas *meas, GprsCodingScheme cs);
gprs_rlcmac_bts *bts_data() const;
@ -108,11 +121,10 @@ private:
void rcv_control_ack(Packet_Control_Acknowledgement_t *, uint32_t fn);
void rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *, uint32_t fn);
void rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *, uint32_t fn);
void rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nack, uint32_t fn);
void rcv_resource_request(Packet_Resource_Request_t *t, uint32_t fn);
void rcv_measurement_report(Packet_Measurement_Report_t *t, uint32_t fn);
gprs_rlcmac_tbf *tbf_from_list_by_tfi(
LListHead<gprs_rlcmac_tbf> *tbf_list, uint8_t tfi,
gprs_rlcmac_tbf *tbf_from_list_by_tfi(struct llist_head *tbf_list, uint8_t tfi,
enum gprs_rlcmac_tbf_direction dir);
gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi,
enum gprs_rlcmac_tbf_direction dir);
@ -157,9 +169,7 @@ struct gprs_rlcmac_bts {
uint8_t cs3;
uint8_t cs4;
uint8_t initial_cs_dl, initial_cs_ul;
uint8_t initial_mcs_dl, initial_mcs_ul;
uint8_t max_cs_dl, max_cs_ul;
uint8_t max_mcs_dl, max_mcs_ul;
uint8_t force_cs; /* 0=use from BTS 1=use from VTY */
uint16_t force_llc_lifetime; /* overrides lifetime from SGSN */
uint32_t llc_discard_csec;
@ -173,7 +183,6 @@ struct gprs_rlcmac_bts {
uint8_t n3101;
uint8_t n3103;
uint8_t n3105;
struct gsmtap_inst *gsmtap;
struct gprs_rlcmac_trx trx[8];
int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts,
struct GprsMs *ms,
@ -183,6 +192,11 @@ struct gprs_rlcmac_bts {
uint8_t force_two_phase;
uint8_t alpha, gamma;
uint8_t egprs_enabled;
uint8_t initial_mcs_dl;
uint8_t initial_mcs_ul;
uint8_t max_mcs_dl;
uint8_t max_mcs_ul;
uint8_t force_mcs;
uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */
uint32_t ms_idle_sec;
uint8_t cs_adj_enabled;
@ -190,8 +204,12 @@ struct gprs_rlcmac_bts {
uint8_t cs_adj_lower_limit;
struct {int16_t low; int16_t high;} cs_lqual_ranges[4];
uint16_t cs_downgrade_threshold; /* downgrade if less packets left (DL) */
uint16_t ws_base;
uint16_t ws_pdch; /* increase WS by this value per PDCH */
/* TBF handling, make private or move into TBFController */
/* list of uplink TBFs */
struct llist_head ul_tbfs;
/* list of downlink TBFs */
struct llist_head dl_tbfs;
/* State for dynamic algorithm selection */
int multislot_disabled;
@ -214,14 +232,11 @@ public:
enum {
CTR_TBF_DL_ALLOCATED,
CTR_TBF_DL_FREED,
CTR_TBF_DL_ABORTED,
CTR_TBF_UL_ALLOCATED,
CTR_TBF_UL_FREED,
CTR_TBF_UL_ABORTED,
CTR_TBF_REUSED,
CTR_TBF_ALLOC_ALGO_A,
CTR_TBF_ALLOC_ALGO_B,
CTR_TBF_FAILED_EGPRS_ONLY,
CTR_RLC_SENT,
CTR_RLC_RESENT,
CTR_RLC_RESTARTED,
@ -272,6 +287,10 @@ public:
gprs_rlcmac_dl_tbf *dl_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts);
gprs_rlcmac_ul_tbf *ul_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts);
void build_codeword(Node *root, const uint8_t* cdwd[]);
Node *ones_list;
Node *zeros_list;
int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx);
int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn);
@ -290,14 +309,11 @@ public:
*/
void tbf_dl_created();
void tbf_dl_freed();
void tbf_dl_aborted();
void tbf_ul_created();
void tbf_ul_freed();
void tbf_ul_aborted();
void tbf_reused();
void tbf_alloc_algo_a();
void tbf_alloc_algo_b();
void tbf_failed_egprs_only();
void rlc_sent();
void rlc_resent();
void rlc_restarted();
@ -327,8 +343,6 @@ public:
struct rate_ctr_group *rate_counters() const;
struct osmo_stat_item_group *stat_items() const;
LListHead<gprs_rlcmac_tbf>& ul_tbfs();
LListHead<gprs_rlcmac_tbf>& dl_tbfs();
private:
int m_cur_fn;
int m_cur_blk_fn;
@ -340,11 +354,6 @@ private:
GprsMsStorage m_ms_store;
/* list of uplink TBFs */
LListHead<gprs_rlcmac_tbf> m_ul_tbfs;
/* list of downlink TBFs */
LListHead<gprs_rlcmac_tbf> m_dl_tbfs;
private:
/* disable copying to avoid slicing */
BTS(const BTS&);
@ -376,16 +385,6 @@ inline GprsMs *BTS::ms_by_imsi(const char *imsi)
return ms_store().get_ms(0, 0, imsi);
}
inline LListHead<gprs_rlcmac_tbf>& BTS::ul_tbfs()
{
return m_ul_tbfs;
}
inline LListHead<gprs_rlcmac_tbf>& BTS::dl_tbfs()
{
return m_dl_tbfs;
}
inline BTS *gprs_rlcmac_pdch::bts() const
{
return trx->bts;
@ -430,14 +429,11 @@ inline struct osmo_stat_item_group *BTS::stat_items() const
CREATE_COUNT_INLINE(tbf_dl_created, CTR_TBF_DL_ALLOCATED)
CREATE_COUNT_INLINE(tbf_dl_freed, CTR_TBF_DL_FREED)
CREATE_COUNT_INLINE(tbf_dl_aborted, CTR_TBF_DL_ABORTED)
CREATE_COUNT_INLINE(tbf_ul_created, CTR_TBF_UL_ALLOCATED)
CREATE_COUNT_INLINE(tbf_ul_freed, CTR_TBF_UL_FREED)
CREATE_COUNT_INLINE(tbf_ul_aborted, CTR_TBF_UL_ABORTED)
CREATE_COUNT_INLINE(tbf_reused, CTR_TBF_REUSED)
CREATE_COUNT_INLINE(tbf_alloc_algo_a, CTR_TBF_ALLOC_ALGO_A)
CREATE_COUNT_INLINE(tbf_alloc_algo_b, CTR_TBF_ALLOC_ALGO_B)
CREATE_COUNT_INLINE(tbf_failed_egprs_only, CTR_TBF_FAILED_EGPRS_ONLY)
CREATE_COUNT_INLINE(rlc_sent, CTR_RLC_SENT)
CREATE_COUNT_INLINE(rlc_resent, CTR_RLC_RESENT)
CREATE_COUNT_INLINE(rlc_restarted, CTR_RLC_RESTARTED)

View File

@ -549,7 +549,6 @@ csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsig
csnStreamInit(&arT, bit_offset, length);
arT.direction = 1;
LOGPC(DCSN1, LOGL_NOTICE, "ptr = %p | offset = %d | ", (void *)data, (int)pDescr->offset);
Status = serialize(&arT, vector, readIndex, pvDATA(data, pDescr->offset));
if (Status >= 0)
@ -2400,7 +2399,12 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
guint8 bits_to_handle = remaining_bits_len%8;
if (bits_to_handle > 0)
{
guint8 fl = filler&(0xff>>(8-bits_to_handle));
/*section 11 of 44.060
*The padding bits may be the 'null' string. Otherwise, the
*padding bits starts with bit '0', followed by 'spare padding'.
*< padding bits > ::= { null | 0 < spare padding > ! < Ignore : 1 bit** = < no string > > } ;
*/
guint8 fl = filler&(0xff>>(8-bits_to_handle + 1));
bitvec_write_field(vector, writeIndex, fl, bits_to_handle);
LOGPC(DCSN1, LOGL_NOTICE, "%u|", fl);
remaining_bits_len -= bits_to_handle;

View File

@ -21,11 +21,6 @@
#include <rlc.h>
#include <gprs_debug.h>
extern "C" {
#include <osmocom/core/utils.h>
#include <osmocom/core/bitcomp.h>
}
#include <arpa/inet.h>
#include <errno.h>
@ -72,6 +67,7 @@ static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len,
chunks[num_chunks].is_complete = true;
} else if (li->li == 0 && num_chunks == 0 && li->e == 1) {
/* TS 44.060, table 10.4.14a.1, row 4 */
// chunks[num_chunks].length = data_len - *offs - data_area;
chunks[num_chunks].length = LENGTH_TO_END;
chunks[num_chunks].is_complete = is_last_block;
} else if (li->li == 127 && li->e == 1) {
@ -100,8 +96,10 @@ static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len,
return -ENOSPC;
}
// chunks[num_chunks].length = data_len - *offs - data_area;
chunks[num_chunks].length = LENGTH_TO_END;
chunks[num_chunks].is_complete = is_last_block;
// data_area += chunks[num_chunks].length;
num_chunks += 1;
}
}
@ -117,6 +115,7 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
const struct rlc_li_field *li;
uint8_t m, e;
unsigned int num_chunks = 0;
// unsigned int data_area = 0;
e = 0;
while (!e) {
@ -156,12 +155,14 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
if (li->li == 0)
/* e is 1 here */
// chunks[num_chunks].length = data_len - *offs - data_area;
chunks[num_chunks].length = LENGTH_TO_END;
else
chunks[num_chunks].length = li->li;
chunks[num_chunks].is_complete = li->li || is_last_block;
// data_area += chunks[num_chunks].length;
num_chunks += 1;
if (e == 1 && m == 1) {
@ -171,6 +172,7 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
return -ENOSPC;
}
/* TS 44.060, 10.4.13.1, row 4 */
// chunks[num_chunks].length = data_len - *offs - data_area;
chunks[num_chunks].length = LENGTH_TO_END;
chunks[num_chunks].is_complete = is_last_block;
num_chunks += 1;
@ -181,13 +183,13 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
}
int Decoding::rlc_data_from_ul_data(
const struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
const struct gprs_rlc_ul_data_block_info *rdbi, GprsCodingScheme cs,
const uint8_t *data, RlcData *chunks, unsigned int chunks_size,
uint32_t *tlli)
{
uint8_t e;
unsigned int data_len = rdbi->data_len;
int num_chunks = 0, i;
unsigned int num_chunks = 0, i;
unsigned int offs = 0;
bool is_last_block = (rdbi->cv == 0);
@ -206,7 +208,7 @@ int Decoding::rlc_data_from_ul_data(
"but no more chunks possible\n");
return -ENOSPC;
}
} else if (cs.isEgprs()) {
} else if (true == cs.isEgprs()) {
/* if E is not set (LI follows), EGPRS */
num_chunks = parse_extensions_egprs(data, data_len, &offs,
is_last_block,
@ -218,9 +220,6 @@ int Decoding::rlc_data_from_ul_data(
chunks, chunks_size);
}
if (num_chunks < 0)
return num_chunks;
/* TLLI */
if (rdbi->ti) {
uint32_t tlli_enc;
@ -250,13 +249,8 @@ int Decoding::rlc_data_from_ul_data(
LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
"please disable in SYSTEM INFORMATION\n");
return -ENOTSUP;
/* TODO: Skip all extensions with E=0 (see TS 44.060, 10.4.11 */
}
if (chunks_size == 0)
return num_chunks;
/* LLC */
for (i = 0; i < num_chunks; i++) {
chunks[i].offset = offs;
@ -282,6 +276,47 @@ int Decoding::rlc_data_from_ul_data(
return num_chunks;
}
int Decoding::tlli_from_ul_data(const uint8_t *data, uint8_t len,
uint32_t *tlli)
{
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
struct rlc_li_field *li;
uint8_t e;
uint32_t _tlli;
if (!rh->ti)
return -EINVAL;
data += 3;
len -= 3;
e = rh->e;
/* if E is not set (LI follows) */
while (!e) {
if (!len) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
"but no more data\n");
return -EINVAL;
}
/* get new E */
li = (struct rlc_li_field *)data;
if (li->e == 0) /* if LI==0, E is interpreted as '1' */
e = 1;
else
e = li->e;
data++;
len--;
}
if (len < 4) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame "
"border\n");
return -EINVAL;
}
memcpy(&_tlli, data, 4);
*tlli = ntohl(_tlli);
return 0;
}
uint8_t Decoding::get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
{
int i;
@ -312,6 +347,18 @@ uint8_t Decoding::get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t
return 0;
}
void Decoding::extract_egprs_urbb(uint16_t urbb_length, const uint8_t *urbb, char *show_rbb)
{
for (int i = 0; i < urbb_length; i++) {
uint8_t bit;
bit = !!(urbb[i/8] & (1<<(7-i%8)));
show_rbb[i] = bit ? 'R' : 'I';
}
show_rbb[urbb_length] = '\0';
}
/**
* show_rbb needs to be an array with 65 elements
* The index of the array is the bit position in the rbb
@ -329,40 +376,26 @@ void Decoding::extract_rbb(const uint8_t *rbb, char *show_rbb)
show_rbb[64] = '\0';
}
void Decoding::extract_rbb(const struct bitvec *rbb, char *show_rbb)
{
unsigned int i;
for (i = 0; i < rbb->cur_bit; i++) {
uint8_t bit;
bit = bitvec_get_bit_pos(rbb, i);
show_rbb[i] = bit == 1 ? 'R' : 'I';
}
show_rbb[i] = '\0';
}
int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
const uint8_t *data, GprsCodingScheme cs)
{
const struct gprs_rlc_ul_header_egprs_3 *egprs3;
const struct rlc_ul_header *gprs;
unsigned int e_ti_header;
unsigned int cur_bit = 0;
int punct, punct2, with_padding, cps;
unsigned int offs;
unsigned int data_len = 0;
uint8_t pad_bytes = 6;
rlc->cs = cs;
data_len = cs.maxDataBlockBytes();
switch(cs.headerTypeData()) {
case GprsCodingScheme::HEADER_GPRS_DATA:
gprs = static_cast<struct rlc_ul_header *>
((void *)data);
gprs_rlc_data_info_init_ul(rlc, cs, false);
rlc->r = gprs->r;
rlc->si = gprs->si;
rlc->tfi = gprs->tfi;
rlc->cps = 0;
rlc->rsb = 0;
rlc->pani= 0;
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = gprs->cv;
@ -371,51 +404,126 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
rlc->block_info[0].e = gprs->e;
rlc->block_info[0].ti = gprs->ti;
rlc->block_info[0].spb = 0;
rlc->data_offs_bytes[0] = 3;
cur_bit += rlc->data_offs_bits[0];
rlc->block_info[0].data_len = data_len;
/* skip data area */
cur_bit += cs.maxDataBlockBytes() * 8;
break;
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3:
const struct gprs_rlc_ul_header_egprs_3 *egprs3;
egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *>
((void *)data);
((void *)data);
rlc->r = egprs3->r;
rlc->si = egprs3->si;
rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2);
rlc->cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2);
rlc->rsb = egprs3->rsb;
rlc->cv = egprs3->cv;
/* pani 0 for fanr inactive */
rlc->pani = 0;
cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2);
gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding);
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = egprs3->cv;
rlc->block_info[0].pi = egprs3->pi;
rlc->block_info[0].spb = egprs3->spb;
rlc->block_info[0].bsn =
(egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
rlc->r = egprs3->r;
rlc->si = egprs3->si;
rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2);
rlc->cps = cps;
rlc->rsb = egprs3->rsb;
rlc->block_info[0].e = (data[4] & 0x01);
rlc->block_info[0].ti = (data[4] & 0x02) >> 1;
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = egprs3->cv;
rlc->block_info[0].pi = egprs3->pi;
rlc->block_info[0].spb = egprs3->spb;
rlc->block_info[0].bsn =
(egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
rlc->block_info[0].data_len = data_len;
rlc->data_offs_bytes[0] = 5;
cur_bit += rlc->data_offs_bits[0] - 2;
if(rlc->block_info[0].spb == 2){
if(cs == GprsCodingScheme::MCS3){
if(rlc->cps == 6 || rlc->cps == 7 || rlc->cps == 8){
rlc->block_info[0].data_len -= pad_bytes;
rlc->data_offs_bytes[0] += pad_bytes;
rlc->block_info[0].e = (data[4 + pad_bytes] & 0x01);
rlc->block_info[0].ti = (data[4 + pad_bytes] & 0x02) >> 1;
}
}
}
break;
offs = rlc->data_offs_bits[0] / 8;
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 1);
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
const struct gprs_rlc_ul_header_egprs_2 *egprs2;
egprs2 = static_cast<struct gprs_rlc_ul_header_egprs_2 *>
((void *)data);
rlc->r = egprs2->r;
rlc->si = egprs2->si;
rlc->tfi = (egprs2->tfi_a << 0) | (egprs2->tfi_b << 2);
rlc->cps = (egprs2->cps_a << 0) | (egprs2->cps_b << 2);
rlc->rsb = egprs2->rsb;
rlc->cv = egprs2->cv;
/* pani 0 for fanr inactive */
rlc->pani = 0;
e_ti_header = (data[offs-1] + (data[offs] << 8)) >> 7;
rlc->block_info[0].e = !!(e_ti_header & 0x01);
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = egprs2->cv;
rlc->block_info[0].pi = egprs2->pi;
rlc->block_info[0].bsn =
(egprs2->bsn1_a << 0) | (egprs2->bsn1_b << 5);
/* skip data area */
cur_bit += cs.maxDataBlockBytes() * 8;
/* data base initialisation not from received block */
rlc->block_info[0].spb = 0;
rlc->block_info[0].e = (data[5] & 0x01);
rlc->block_info[0].ti = (data[5] & 0x02) >> 1;
rlc->block_info[0].data_len = data_len;
rlc->data_offs_bytes[0] = 6;
if(cs == GprsCodingScheme::MCS6){
if(rlc->cps == 2 || rlc->cps == 3 ){
rlc->block_info[0].data_len -= pad_bytes;
rlc->data_offs_bytes[0] += pad_bytes;
rlc->block_info[0].e = (data[5 + pad_bytes] & 0x01);
rlc->block_info[0].ti = (data[5 + pad_bytes] & 0x02) >> 1;
}
}
break;
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1:
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
/* TODO: Support both header types */
/* fall through */
const struct gprs_rlc_ul_header_egprs_1 *egprs1;
egprs1 = static_cast<struct gprs_rlc_ul_header_egprs_1 *>
((void *)data);
rlc->r = egprs1->r;
rlc->si = egprs1->si;
rlc->tfi = (egprs1->tfi_a << 0) | (egprs1->tfi_b << 2);
rlc->cps = egprs1->cps;
rlc->rsb = egprs1->rsb;
rlc->cv = egprs1->cv;
/* pani 0 for fanr inactive */
rlc->pani = 0;
rlc->num_data_blocks = 2;
rlc->block_info[0].cv = egprs1->cv;
rlc->block_info[0].pi = egprs1->pi;
rlc->block_info[0].bsn =
(egprs1->bsn1_a << 0) | (egprs1->bsn1_b << 5);
/* data base initialisation not from received block */
rlc->block_info[0].spb = 0;
rlc->block_info[1].cv = egprs1->cv;
rlc->block_info[1].pi = egprs1->pi;
rlc->block_info[1].bsn = rlc->block_info[0].bsn + ((egprs1->bsn2_a << 0) | (egprs1->bsn2_b << 2));
rlc->block_info[1].bsn = (rlc->block_info[1].bsn + 2048) % 2047;
rlc->block_info[0].e = (data[6] & 0x01);
rlc->block_info[0].ti = (data[6] & 0x02) >> 1;
rlc->block_info[1].e = (data[6 + data_len + 1] & 0x01);
rlc->block_info[1].ti = (data[6 + data_len + 1] & 0x02) >> 1;
rlc->block_info[1].spb = 0;
rlc->block_info[0].data_len = data_len;
rlc->block_info[1].data_len = data_len;
rlc->data_offs_bytes[0] = 7;
rlc->data_offs_bytes[1] = 7 + data_len + 1;
break;
default:
LOGP(DRLCMACDL, LOGL_ERROR,
"Decoding of uplink %s data blocks not yet supported.\n",
@ -423,7 +531,7 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
return -ENOTSUP;
};
return cur_bit;
return 0;
}
/**
@ -440,238 +548,18 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
* \returns the number of bytes copied
*/
unsigned int Decoding::rlc_copy_to_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
const struct gprs_rlc_ul_header_generic *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer)
{
unsigned int hdr_bytes;
unsigned int extra_bits;
unsigned int i;
uint8_t c, last_c;
uint8_t *dst;
const struct gprs_rlc_data_block_info *rdbi;
OSMO_ASSERT(data_block_idx < rlc->num_data_blocks);
const struct gprs_rlc_ul_data_block_info *rdbi;
rdbi = &rlc->block_info[data_block_idx];
hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
if (extra_bits == 0) {
/* It is aligned already */
memmove(buffer, src + hdr_bytes, rdbi->data_len);
return rdbi->data_len;
}
dst = buffer;
src = src + hdr_bytes;
last_c = *(src++);
for (i = 0; i < rdbi->data_len; i++) {
c = src[i];
*(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
last_c = c;
}
hdr_bytes = rlc->data_offs_bytes[data_block_idx] ;
/* It is aligned already */
memmove(buffer , src + hdr_bytes, rdbi->data_len);
return rdbi->data_len;
}
/**
* \brief Get a pointer to byte aligned RLC data.
*
* Since the RLC data may not be byte aligned to the RLC block data such that a
* single RLC data byte is spread over two RLC block bytes, this function
* eventually uses the provided buffer as data storage.
*
* \param src A pointer to the start of the RLC block (incl. the header)
* \param buffer A data area of a least the size of the RLC block
* \returns A pointer to the RLC data start within src if it is aligned, and
* buffer otherwise.
*/
const uint8_t *Decoding::rlc_get_data_aligned(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer)
{
unsigned int hdr_bytes;
unsigned int extra_bits;
OSMO_ASSERT(data_block_idx < ARRAY_SIZE(rlc->data_offs_bits));
hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
if (extra_bits == 0)
/* It is aligned already, return a pointer that refers to the
* original data. */
return src + hdr_bytes;
Decoding::rlc_copy_to_aligned_buffer(rlc, data_block_idx, src, buffer);
return buffer;
}
static int handle_final_ack(bitvec *bits, int *bsn_begin, int *bsn_end,
gprs_rlc_dl_window *window)
{
int num_blocks, i;
num_blocks = window->mod_sns(window->v_s() - window->v_a());
for (i = 0; i < num_blocks; i++)
bitvec_set_bit(bits, ONE);
*bsn_begin = window->v_a();
*bsn_end = window->mod_sns(*bsn_begin + num_blocks);
return num_blocks;
}
int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc,
bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window)
{
int urbb_len = desc->URBB_LENGTH;
int crbb_len = 0;
int num_blocks = 0;
struct bitvec urbb;
int i;
bool have_bitmap;
int implicitly_acked_blocks;
int ssn = desc->STARTING_SEQUENCE_NUMBER;
int rc;
if (desc->FINAL_ACK_INDICATION)
return handle_final_ack(bits, bsn_begin, bsn_end, window);
if (desc->Exist_CRBB)
crbb_len = desc->CRBB_LENGTH;
have_bitmap = (urbb_len + crbb_len) > 0;
/*
* bow & bitmap present:
* V(A)-> [ 11111...11111 0 SSN-> BBBBB...BBBBB ] (SSN+Nbits) .... V(S)
* bow & not bitmap present:
* V(A)-> [ 11111...11111 ] . SSN .... V(S)
* not bow & bitmap present:
* V(A)-> ... [ 0 SSN-> BBBBB...BBBBB ](SSN+N) .... V(S)
* not bow & not bitmap present:
* V(A)-> ... [] . SSN .... V(S)
*/
if (desc->BEGINNING_OF_WINDOW) {
implicitly_acked_blocks = window->mod_sns(ssn - 1 - window->v_a());
for (i = 0; i < implicitly_acked_blocks; i++)
bitvec_set_bit(bits, ONE);
num_blocks += implicitly_acked_blocks;
}
if (!have_bitmap)
goto aborted;
/* next bit refers to V(Q) and thus is always zero (and not
* transmitted) */
bitvec_set_bit(bits, ZERO);
num_blocks += 1;
if (crbb_len > 0) {
int old_len = bits->cur_bit;
struct bitvec crbb;
crbb.data = (uint8_t *)desc->CRBB;
crbb.data_len = sizeof(desc->CRBB);
crbb.cur_bit = desc->CRBB_LENGTH;
rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE,
bits);
if (rc < 0) {
LOGP(DRLCMACUL, LOGL_NOTICE,
"Failed to decode CRBB: "
"length %d, data '%s'\n",
desc->CRBB_LENGTH,
osmo_hexdump(crbb.data, crbb.data_len));
/* We don't know the SSN offset for the URBB,
* return what we have so far and assume the
* bitmap has stopped here */
goto aborted;
}
LOGP(DRLCMACDL, LOGL_DEBUG,
"CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n",
desc->CRBB_LENGTH, bits->cur_bit - old_len,
desc->CRBB_STARTING_COLOR_CODE,
osmo_hexdump(
desc->CRBB, (desc->CRBB_LENGTH + 7)/8)
);
num_blocks += (bits->cur_bit - old_len);
}
urbb.cur_bit = 0;
urbb.data = (uint8_t *)desc->URBB;
urbb.data_len = sizeof(desc->URBB);
for (i = urbb_len; i > 0; i--) {
/*
* Set bit at the appropriate position (see 3GPP TS
* 44.060 12.3.1)
*/
int is_ack = bitvec_get_bit_pos(&urbb, i-1);
bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO);
}
num_blocks += urbb_len;
aborted:
*bsn_begin = window->v_a();
*bsn_end = window->mod_sns(*bsn_begin + num_blocks);
return num_blocks;
}
int Decoding::decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc,
bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window)
{
int urbb_len = RLC_GPRS_WS;
int num_blocks;
struct bitvec urbb;
if (desc->FINAL_ACK_INDICATION)
return handle_final_ack(bits, bsn_begin, bsn_end, window);
*bsn_begin = window->v_a();
*bsn_end = desc->STARTING_SEQUENCE_NUMBER;
num_blocks = window->mod_sns(*bsn_end - *bsn_begin);
if (num_blocks < 0 || num_blocks > urbb_len) {
*bsn_end = *bsn_begin;
LOGP(DRLCMACUL, LOGL_NOTICE,
"Invalid GPRS Ack/Nack window %d:%d (length %d)\n",
*bsn_begin, *bsn_end, num_blocks);
return -EINVAL;
}
urbb.cur_bit = 0;
urbb.data = (uint8_t *)desc->RECEIVED_BLOCK_BITMAP;
urbb.data_len = sizeof(desc->RECEIVED_BLOCK_BITMAP);
/*
* TS 44.060, 12.3:
* BSN = (SSN - bit_number) modulo 128, for bit_number = 1 to 64.
* The BSN values represented range from (SSN - 1) mod 128 to (SSN - 64) mod 128.
*
* We are only interested in the range from V(A) to SSN-1 which is
* num_blocks large. The RBB is laid out as
* [SSN-1] [SSN-2] ... [V(A)] ... [SSN-64]
* so we want to start with [V(A)] and go backwards until we reach
* [SSN-1] to get the needed BSNs in an increasing order. Note that
* the bit numbers are counted from the end of the buffer.
*/
for (int i = num_blocks; i > 0; i--) {
int is_ack = bitvec_get_bit_pos(&urbb, urbb_len - i);
bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO);
}
return num_blocks;
}

View File

@ -20,12 +20,10 @@
#pragma once
#include <gsm_rlcmac.h>
#include "gprs_coding_scheme.h"
#include "rlc.h"
#include <stdint.h>
struct bitvec;
class Decoding {
public:
struct RlcData {
@ -34,32 +32,26 @@ public:
bool is_complete;
};
static int tlli_from_ul_data(const uint8_t *data, uint8_t len,
uint32_t *tlli);
static int rlc_data_from_ul_data(
const struct gprs_rlc_data_block_info *rdbi,
const struct gprs_rlc_ul_data_block_info *rdbi,
GprsCodingScheme cs, const uint8_t *data, RlcData *chunks,
unsigned int chunks_size, uint32_t *tlli);
static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
static uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
static void extract_rbb(const uint8_t *rbb, char *extracted_rbb);
static void extract_rbb(const struct bitvec *rbb, char *show_rbb);
static void extract_egprs_urbb(uint16_t urbb_length, const uint8_t *urbb, char *show_rbb);
static uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
static int rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
static int rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
const uint8_t *data, GprsCodingScheme cs);
static unsigned int rlc_copy_to_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
const struct gprs_rlc_ul_header_generic *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer);
const uint8_t *src,uint8_t *block);
static const uint8_t *rlc_get_data_aligned(
const struct gprs_rlc_data_info *rlc,
const struct gprs_rlc_ul_header_egprs *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer);
static int decode_egprs_acknack_bits(
const EGPRS_AckNack_Desc_t *desc,
struct bitvec *bits, int *bsn_begin, int *bsn_end,
struct gprs_rlc_dl_window *window);
static int decode_gprs_acknack_bits(
const Ack_Nack_Description_t *desc,
bitvec *bits, int *bsn_begin, int *bsn_end,
gprs_rlc_dl_window *window);
};

File diff suppressed because it is too large Load Diff

View File

@ -22,13 +22,10 @@
#include <stdint.h>
#include <gsm_rlcmac.h>
#include <gprs_coding_scheme.h>
struct gprs_rlcmac_bts;
struct gprs_rlcmac_tbf;
struct bitvec;
struct gprs_llc;
struct gprs_rlc_data_block_info;
/**
* I help with encoding data into CSN1 messages.
@ -39,58 +36,34 @@ struct gprs_rlc_data_block_info;
class Encoding {
public:
static int write_immediate_assignment(
struct gprs_rlcmac_tbf *tbf,
bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts,
uint8_t tsc, uint8_t usf, uint8_t polling,
uint32_t fn, uint8_t alpha, uint8_t gamma,
int8_t ta_idx);
struct gprs_rlcmac_bts *bts,
bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling,
uint32_t fn, uint8_t single_block, uint8_t alpha, uint8_t gamma,
int8_t ta_idx, int8_t use_egprs);
static void write_packet_uplink_assignment(
struct gprs_rlcmac_bts *bts,
bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
struct gprs_rlcmac_ul_tbf *tbf, uint8_t poll, uint8_t rrbp,
uint8_t alpha, uint8_t gamma, int8_t ta_idx,
int8_t use_egprs);
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
struct gprs_rlcmac_ul_tbf *tbf, uint8_t poll, uint8_t alpha,
uint8_t gamma, int8_t ta_idx, int8_t use_egprs);
static void write_packet_downlink_assignment(RlcMacDownlink_t * block,
bool old_tfi_is_valid, uint8_t old_tfi, uint8_t old_downlink,
struct gprs_rlcmac_tbf *tbf, uint8_t poll, uint8_t rrbp,
uint8_t alpha, uint8_t gamma,
int8_t ta_idx, uint8_t ta_ts, bool use_egprs);
static void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll,
uint8_t alpha, uint8_t gamma, int8_t ta_idx, uint8_t ta_ts,
uint16_t window_size);
static void encode_rbb(const char *show_rbb, uint8_t *rbb);
static void write_packet_uplink_ack(
static void write_packet_uplink_ack(
struct gprs_rlcmac_bts *bts, bitvec * dest,
struct gprs_rlcmac_ul_tbf *tbf, bool is_final,
uint8_t rrbp);
struct gprs_rlcmac_ul_tbf *tbf, bool is_final);
static int write_paging_request(bitvec * dest, uint8_t *ptmsi, uint16_t ptmsi_len);
static unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len,
uint8_t *identity, uint8_t chan_needed);
static unsigned write_packet_paging_request(bitvec * dest);
static int rlc_write_dl_data_header(
const struct gprs_rlc_data_info *rlc,
uint8_t *data);
static unsigned int rlc_copy_from_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
uint8_t *dst, const uint8_t *buffer);
enum AppendResult {
AR_NEED_MORE_BLOCKS,
AR_COMPLETED_SPACE_LEFT,
AR_COMPLETED_BLOCK_FILLED,
};
static AppendResult rlc_data_to_dl_append(
struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
gprs_llc *llc, int *offset, int *num_chunks,
uint8_t *data,
bool is_final);
};

View File

@ -23,7 +23,6 @@
#include <pcu_l1_if.h>
#include <bts.h>
#include <tbf.h>
#include <decoding.h>
#define BSSGP_TIMER_T1 30 /* Guards the (un)blocking procedures */
#define BSSGP_TIMER_T2 30 /* Guards the reset procedure */
@ -74,32 +73,87 @@ static int parse_imsi(struct tlv_parsed *tp, char *imsi)
return 0;
}
static int parse_ra_cap(struct tlv_parsed *tp, MS_Radio_Access_capability_t *rac)
static int parse_ra_cap_ms_class(struct tlv_parsed *tp)
{
bitvec *block;
unsigned rp = 0;
uint8_t ms_class = 0;
uint8_t cap_len;
uint8_t *cap;
memset(rac, 0, sizeof(*rac));
if (!TLVP_PRESENT(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP))
return -EINVAL;
return ms_class;
cap_len = TLVP_LEN(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP);
cap = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP);
LOGP(DBSSGP, LOGL_DEBUG, "Got BSSGP RA Capability of size %d\n", cap_len);
block = bitvec_alloc(cap_len);
bitvec_unpack(block, cap);
/* TS 24.008, 10.5.5.12a */
decode_gsm_ra_cap(block, rac);
bitvec_read_field(block, rp, 4); // Access Technology Type
bitvec_read_field(block, rp, 7); // Length of Access Capabilities
bitvec_read_field(block, rp, 3); // RF Power Capability
if (bitvec_read_field(block, rp, 1)) // A5 Bits Present
bitvec_read_field(block, rp, 7); // A5 Bits
bitvec_read_field(block, rp, 1); // ES IND
bitvec_read_field(block, rp, 1); // PS
bitvec_read_field(block, rp, 1); // VGCS
bitvec_read_field(block, rp, 1); // VBS
if (bitvec_read_field(block, rp, 1)) { // Multislot Cap Present
if (bitvec_read_field(block, rp, 1)) // HSCSD Present
bitvec_read_field(block, rp, 5); // Class
if (bitvec_read_field(block, rp, 1)) { // GPRS Present
ms_class = bitvec_read_field(block, rp, 5); // Class
bitvec_read_field(block, rp, 1); // Ext.
}
if (bitvec_read_field(block, rp, 1)) // SMS Present
bitvec_read_field(block, rp, 4); // SMS Value
}
bitvec_free(block);
return 0;
return ms_class;
}
static int parse_egprs_ra_cap_ms_class(struct tlv_parsed *tp)
{
bitvec *block;
unsigned rp = 0;
uint8_t egprs_ms_class = 0;
uint8_t cap_len;
uint8_t *cap;
if (!TLVP_PRESENT(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP))
return egprs_ms_class;
cap_len = TLVP_LEN(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP);
cap = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP);
block = bitvec_alloc(cap_len);
bitvec_unpack(block, cap);
bitvec_read_field(block, rp, 4); // Access Technology Type
bitvec_read_field(block, rp, 7); // Length of Access Capabilities
bitvec_read_field(block, rp, 3); // RF Power Capability
if (bitvec_read_field(block, rp, 1)) // A5 Bits Present
bitvec_read_field(block, rp, 7); // A5 Bits
bitvec_read_field(block, rp, 1); // ES IND
bitvec_read_field(block, rp, 1); // PS
bitvec_read_field(block, rp, 1); // VGCS
bitvec_read_field(block, rp, 1); // VBS
if (bitvec_read_field(block, rp, 1)) { // Multislot Cap Present
if (bitvec_read_field(block, rp, 1)) // HSCSD Present
bitvec_read_field(block, rp, 5); // Class
if (bitvec_read_field(block, rp, 1)) { // GPRS Present
bitvec_read_field(block, rp, 5);
}
if (bitvec_read_field(block, rp, 1)) // SMS Present
bitvec_read_field(block, rp, 4); // SMS Value
if (bitvec_read_field(block, rp, 1)) // ECSD_multislot_class Present
bitvec_read_field(block, rp, 5); // ECSD MSC Value
if (bitvec_read_field(block, rp, 1)) { // EGPRS Present
egprs_ms_class = bitvec_read_field(block, rp, 5); //EGPRS multi slot class value
}
}
bitvec_free(block);
return egprs_ms_class;
}
static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
@ -109,11 +163,6 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
uint8_t *data;
uint16_t len;
char imsi[16] = "000";
uint8_t ms_class = 0;
uint8_t egprs_ms_class = 0;
#if 0
MS_Radio_Access_capability_t rac;
#endif
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
tlli = ntohl(budh->tlli);
@ -138,17 +187,10 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
* will listen to all paging blocks. */
parse_imsi(tp, imsi);
#if 0 /* Do not rely on this IE. TODO: make this configurable */
/* parse ms radio access capability */
if (parse_ra_cap(tp, &rac) >= 0) {
/* Get the EGPRS class from the RA capability */
ms_class = Decoding::get_ms_class_by_capability(&rac);
egprs_ms_class =
Decoding::get_egprs_ms_class_by_capability(&rac);
LOGP(DBSSGP, LOGL_DEBUG, "Got downlink MS class %d/%d\n",
ms_class, egprs_ms_class);
}
#endif
uint8_t ms_class = parse_ra_cap_ms_class(tp);
/* parse egprs ms radio access capability */
uint8_t egprs_ms_class = parse_egprs_ra_cap_ms_class(tp);
/* get lifetime */
uint16_t delay_csec = 0xffff;
@ -178,7 +220,6 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
}
LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len);
return gprs_rlcmac_dl_tbf::handle(the_pcu.bts, tlli, tlli_old, imsi,
ms_class, egprs_ms_class, delay_csec, data, len);
}
@ -533,12 +574,19 @@ static unsigned count_pdch(const struct gprs_rlcmac_bts *bts)
return num_pdch;
}
static uint32_t gprs_bssgp_max_leak_rate(GprsCodingScheme cs, int num_pdch)
static uint32_t gprs_bssgp_max_leak_rate(unsigned cs, int num_pdch)
{
int bytes_per_rlc_block = cs.maxDataBlockBytes() * cs.numDataBlocks();
static const uint32_t max_lr_per_ts[4] = {
20 * (1000 / 20), /* CS-1: 20 byte payload per 20ms */
30 * (1000 / 20), /* CS-2: 30 byte payload per 20ms */
36 * (1000 / 20), /* CS-3: 36 byte payload per 20ms */
50 * (1000 / 20), /* CS-4: 50 byte payload per 20ms */
};
/* n byte payload per 20ms */
return bytes_per_rlc_block * (1000 / 20) * num_pdch;
if (cs > ARRAY_SIZE(max_lr_per_ts))
cs = 1;
return max_lr_per_ts[cs-1] * num_pdch;
}
static uint32_t compute_bucket_size(struct gprs_rlcmac_bts *bts,
@ -611,45 +659,6 @@ static int get_and_reset_measured_leak_rate(int *usage_by_1000, unsigned num_pdc
return rate;
}
static GprsCodingScheme max_coding_scheme_dl(struct gprs_rlcmac_bts *bts)
{
int num;
if (bts->egprs_enabled) {
if (!bts->cs_adj_enabled) {
if (bts->initial_mcs_dl)
num = bts->initial_mcs_dl;
else
num = 1;
} else if (bts->max_mcs_dl) {
num = bts->max_mcs_dl;
} else {
num = 9;
}
return GprsCodingScheme::getEgprsByNum(num);
}
if (!bts->cs_adj_enabled) {
if (bts->initial_cs_dl)
num = bts->initial_cs_dl;
else if (bts->cs4)
num = 4;
else if (bts->cs3)
num = 3;
else if (bts->cs2)
num = 2;
else
num = 1;
} else if (bts->max_cs_dl) {
num = bts->max_cs_dl;
} else {
num = 4;
}
return GprsCodingScheme::getGprsByNum(num);
}
int gprs_bssgp_tx_fc_bvc(void)
{
struct gprs_rlcmac_bts *bts;
@ -659,7 +668,7 @@ int gprs_bssgp_tx_fc_bvc(void)
uint32_t ms_leak_rate; /* oct/s */
uint32_t avg_delay_ms;
int num_pdch = -1;
GprsCodingScheme max_cs_dl;
int max_cs_dl;
if (!the_pcu.bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
@ -667,7 +676,21 @@ int gprs_bssgp_tx_fc_bvc(void)
}
bts = bts_main_data();
max_cs_dl = max_coding_scheme_dl(bts);
if (bts->cs_adj_enabled) {
max_cs_dl = bts->max_cs_dl;
if (!max_cs_dl) {
if (bts->cs4)
max_cs_dl = 4;
else if (bts->cs3)
max_cs_dl = 3;
else if (bts->cs2)
max_cs_dl = 2;
else
max_cs_dl = 1;
}
} else {
max_cs_dl = bts->initial_cs_dl;
}
bucket_size = bts->fc_bvc_bucket_size;
leak_rate = bts->fc_bvc_leak_rate;
@ -701,8 +724,8 @@ int gprs_bssgp_tx_fc_bvc(void)
leak_rate = gprs_bssgp_max_leak_rate(max_cs_dl, num_pdch);
LOGP(DBSSGP, LOGL_DEBUG,
"Computed BVC leak rate = %d, num_pdch = %d, cs = %s\n",
leak_rate, num_pdch, max_cs_dl.name());
"Computed BVC leak rate = %d, num_pdch = %d, cs = %d\n",
leak_rate, num_pdch, max_cs_dl);
};
if (ms_leak_rate == 0) {
@ -724,9 +747,8 @@ int gprs_bssgp_tx_fc_bvc(void)
* should be derived from the max number of PDCH TS per TRX.
*/
LOGP(DBSSGP, LOGL_DEBUG,
"Computed MS default leak rate = %d, ms_num_pdch = %d, "
"cs = %s\n",
ms_leak_rate, ms_num_pdch, max_cs_dl.name());
"Computed MS default leak rate = %d, ms_num_pdch = %d, cs = %d\n",
ms_leak_rate, ms_num_pdch, max_cs_dl);
};
/* TODO: Force leak_rate to 0 on buffer bloat */
@ -890,33 +912,28 @@ struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts
void gprs_bssgp_destroy(void)
{
struct gprs_ns_inst *nsi = bssgp_nsi;
if (!nsi)
if (!bssgp_nsi)
return;
bssgp_nsi = NULL;
osmo_timer_del(&the_pcu.bvc_timer);
osmo_signal_unregister_handler(SS_L_NS, nsvc_signal_cb, NULL);
the_pcu.nsvc = NULL;
/* FIXME: move this to libgb: btsctx_free() */
llist_del(&the_pcu.bctx->list);
talloc_free(the_pcu.bctx);
the_pcu.bctx = NULL;
/* FIXME: blocking... */
the_pcu.nsvc_unblocked = 0;
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.bvc_unblocked = 0;
gprs_ns_destroy(nsi);
/* FIXME: move this to libgb: btsctx_free() */
llist_del(&the_pcu.bctx->list);
#warning "This causes ASAN to complain. It is not critical for normal operation but should be fixed nevertheless"
#if 0
talloc_free(the_pcu.bctx);
#endif
the_pcu.bctx = NULL;
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
}
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)

View File

@ -25,62 +25,111 @@ static struct {
struct {
unsigned int bytes;
unsigned int ext_bits;
unsigned int data_header_bits;
} uplink, downlink;
unsigned int data_bytes;
unsigned int optional_padding_bits;
const char *name;
GprsCodingScheme::HeaderType data_hdr;
GprsCodingScheme::Family family;
} mcs_info[GprsCodingScheme::NUM_SCHEMES] = {
{{0, 0}, {0, 0}, 0, 0, "UNKNOWN",
GprsCodingScheme::HEADER_INVALID, GprsCodingScheme::FAMILY_INVALID},
{{23, 0}, {23, 0}, 20, 0, "CS-1",
GprsCodingScheme::HEADER_GPRS_DATA, GprsCodingScheme::FAMILY_INVALID},
{{33, 7}, {33, 7}, 30, 0, "CS-2",
GprsCodingScheme::HEADER_GPRS_DATA, GprsCodingScheme::FAMILY_INVALID},
{{39, 3}, {39, 3}, 36, 0, "CS-3",
GprsCodingScheme::HEADER_GPRS_DATA, GprsCodingScheme::FAMILY_INVALID},
{{53, 7}, {53, 7}, 50, 0, "CS-4",
GprsCodingScheme::HEADER_GPRS_DATA, GprsCodingScheme::FAMILY_INVALID},
{{26, 1}, {26, 1}, 22, 0, "MCS-1",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, GprsCodingScheme::FAMILY_C},
{{32, 1}, {32, 1}, 28, 0, "MCS-2",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, GprsCodingScheme::FAMILY_B},
{{41, 1}, {41, 1}, 37, 48, "MCS-3",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, GprsCodingScheme::FAMILY_A},
{{48, 1}, {48, 1}, 44, 0, "MCS-4",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, GprsCodingScheme::FAMILY_C},
{{60, 7}, {59, 6}, 56, 0, "MCS-5",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2, GprsCodingScheme::FAMILY_B},
{{78, 7}, {77, 6}, 74, 48, "MCS-6",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2, GprsCodingScheme::FAMILY_A},
{{118, 2}, {117, 4}, 56, 0, "MCS-7",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1, GprsCodingScheme::FAMILY_B},
{{142, 2}, {141, 4}, 68, 0, "MCS-8",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1, GprsCodingScheme::FAMILY_A},
{{154, 2}, {153, 4}, 74, 0, "MCS-9",
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1, GprsCodingScheme::FAMILY_A},
};
static struct {
struct {
int data_header_bits;
} uplink, downlink;
unsigned int data_block_header_bits;
unsigned int num_blocks;
const char *name;
} hdr_type_info[GprsCodingScheme::NUM_HEADER_TYPES] = {
{{0}, {0}, 0, 0, "INVALID"},
{{1*8 + 0}, {1*8 + 0}, 0, 0, "CONTROL"},
{{3*8 + 0}, {3*8 + 0}, 0, 1, "GPRS_DATA"},
{{5*8 + 6}, {5*8 + 0}, 2, 2, "EGPRS_DATA_TYPE1"},
{{4*8 + 5}, {3*8 + 4}, 2, 1, "EGPRS_DATA_TYPE2"},
{{3*8 + 7}, {3*8 + 7}, 2, 1, "EGPRS_DATA_TYPE3"},
GprsCodingScheme::HeaderType data_hdr;
} mcs_info[GprsCodingScheme::NUM_SCHEMES] = {
{{0, 0}, {0, 0}, 0, 0, "UNKNOWN", GprsCodingScheme::HEADER_INVALID},
{{23, 0}, {23, 0}, 20, 1, "CS-1", GprsCodingScheme::HEADER_GPRS_DATA},
{{33, 7}, {33, 7}, 30, 1, "CS-2", GprsCodingScheme::HEADER_GPRS_DATA},
{{39, 3}, {39, 3}, 36, 1, "CS-3", GprsCodingScheme::HEADER_GPRS_DATA},
{{53, 7}, {53, 7}, 50, 1, "CS-4", GprsCodingScheme::HEADER_GPRS_DATA},
{{26, 1}, {26, 1}, 22, 1, "MCS-1", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3},
{{32, 1}, {32, 1}, 28, 1, "MCS-2", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3},
{{41, 1}, {41, 1}, 37, 1, "MCS-3", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3},
{{48, 1}, {48, 1}, 44, 1, "MCS-4", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3},
{{60, 7}, {59, 6}, 56, 1, "MCS-5", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2},
{{78, 7}, {77, 6}, 74, 1, "MCS-6", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2},
{{118, 2}, {117, 4}, 56, 2, "MCS-7", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1},
{{142, 2}, {141, 4}, 68, 2, "MCS-8", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1},
{{154, 2}, {153, 4}, 74, 2, "MCS-9", GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1},
};
/* CPS table for Header Type 3 */
static uint8_t cps_header_type3[5][3] = /* 1st index: MCS; 2nd index: PS */
{{11, 12, 255}, /* MCS-1 */
{ 9, 10, 255}, /* MCS-2 */
{ 3, 4, 5}, /* MCS-3 */
{ 0, 1, 2}, /* MCS-4 */
{ 6, 7, 8}}; /* MCS-3 with padding (MCS-8 retransmission) */
/* CPS table for Header Type 2 */
static uint8_t cps_header_type2[3][2] = /* 1st index: MCS; 2nd index: PS */
{
{4, 5}, /* MCS-5 */
{0, 1}, /* MCS-6 */
{2, 3} /* MCS-6 with padding (MCS-8 retransmission) */
};
/* CPS table for Header Type 1 */
uint8_t cps_header_type1[3][3][3] =
{{{20,21,22}, /* MCS-7 / P1 / PX */
{23,24,25}, /* MCS-7 / P2 / PX */
{26,27,28} /* MCS-7 / P3 / PX */
},
{{11,12,13}, /* MCS-8 / P1 / PX */
{14,15,26}, /* MCS-8 / P2 / PX */
{17,18,19} /* MCS-8 / P3 / PX */
},
{{0,1,2}, /* MCS-9 / P1 / PX */
{4,5,6}, /* MCS-9 / P2 / PX */
{8,9,10} /* MCS-9 / P3 / PX */
}
};
/* MCS retransmission table */
/*
first indexing is for commanded, second indexing is for
mcs of last transmission
*/
GprsCodingScheme::Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ]
[MAX_NUM_MCS] [MAX_NUM_MCS] =
{{{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS3},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS3},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS3},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS3},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS3,GprsCodingScheme::MCS5,GprsCodingScheme::MCS3,GprsCodingScheme::GprsCodingScheme::MCS3},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6}
},
{{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6},
{GprsCodingScheme::MCS1,GprsCodingScheme::MCS2,GprsCodingScheme::MCS3,GprsCodingScheme::MCS4,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS5,GprsCodingScheme::MCS6,GprsCodingScheme::MCS6}
}
};
uint8_t GprsCodingScheme::get_cps(uint8_t ps, bool is_padding)
{
if(this->headerTypeData() == GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1){
return cps_header_type1[this->m_scheme - MCS1 ][ps][ps];
}else if(this->headerTypeData() == GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2){
if((this->m_scheme == GprsCodingScheme::MCS6) && true == is_padding){
return cps_header_type2[this->m_scheme - MCS5 + 1][ps];
}else{
return cps_header_type2[this->m_scheme - MCS5 ][ps];
}
}else if(this->headerTypeData() == GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3){
if( this->m_scheme == GprsCodingScheme::MCS3 && true == is_padding){
return cps_header_type3[this->m_scheme - MCS1 + 2][ps];
}else{
return cps_header_type3[this->m_scheme -MCS1][ps];
}
}
return 255;
}
GprsCodingScheme GprsCodingScheme::getBySizeUL(unsigned size)
{
switch (size) {
@ -92,11 +141,11 @@ GprsCodingScheme GprsCodingScheme::getBySizeUL(unsigned size)
case 42: return GprsCodingScheme(MCS3);
case 49: return GprsCodingScheme(MCS4);
case 54: return GprsCodingScheme(CS4);
case 61: return GprsCodingScheme(MCS5);
case 79: return GprsCodingScheme(MCS6);
case 119: return GprsCodingScheme(MCS7);
case 143: return GprsCodingScheme(MCS8);
case 155: return GprsCodingScheme(MCS9);
case 62: return GprsCodingScheme(MCS5);
case 80: return GprsCodingScheme(MCS6);
case 120: return GprsCodingScheme(MCS7);
case 144: return GprsCodingScheme(MCS8);
case 156: return GprsCodingScheme(MCS9);
}
return GprsCodingScheme(UNKNOWN);
@ -104,15 +153,7 @@ GprsCodingScheme GprsCodingScheme::getBySizeUL(unsigned size)
unsigned int GprsCodingScheme::sizeUL() const
{
return mcs_info[m_scheme].uplink.bytes + (spareBitsUL() ? 1 : 0);
}
unsigned int GprsCodingScheme::usedSizeUL() const
{
if (mcs_info[m_scheme].data_hdr == HEADER_GPRS_DATA)
return mcs_info[m_scheme].uplink.bytes;
else
return sizeUL();
return maxBytesUL() + (spareBitsUL() ? 1 : 0);
}
unsigned int GprsCodingScheme::maxBytesUL() const
@ -127,15 +168,7 @@ unsigned int GprsCodingScheme::spareBitsUL() const
unsigned int GprsCodingScheme::sizeDL() const
{
return mcs_info[m_scheme].downlink.bytes + (spareBitsDL() ? 1 : 0);
}
unsigned int GprsCodingScheme::usedSizeDL() const
{
if (mcs_info[m_scheme].data_hdr == HEADER_GPRS_DATA)
return mcs_info[m_scheme].downlink.bytes;
else
return sizeDL();
return maxBytesDL() + (spareBitsDL() ? 1 : 0);
}
unsigned int GprsCodingScheme::maxBytesDL() const
@ -153,29 +186,14 @@ unsigned int GprsCodingScheme::maxDataBlockBytes() const
return mcs_info[m_scheme].data_bytes;
}
unsigned int GprsCodingScheme::optionalPaddingBits() const
{
return mcs_info[m_scheme].optional_padding_bits;
}
unsigned int GprsCodingScheme::numDataBlocks() const
{
return hdr_type_info[headerTypeData()].num_blocks;
return mcs_info[m_scheme].num_blocks;
}
unsigned int GprsCodingScheme::numDataHeaderBitsUL() const
GprsCodingScheme::Scheme GprsCodingScheme::coding_scheme() const
{
return hdr_type_info[headerTypeData()].uplink.data_header_bits;
}
unsigned int GprsCodingScheme::numDataHeaderBitsDL() const
{
return hdr_type_info[headerTypeData()].downlink.data_header_bits;
}
unsigned int GprsCodingScheme::numDataBlockHeaderBits() const
{
return hdr_type_info[headerTypeData()].data_block_header_bits;
return m_scheme;
}
const char *GprsCodingScheme::name() const
@ -188,99 +206,8 @@ GprsCodingScheme::HeaderType GprsCodingScheme::headerTypeData() const
return mcs_info[m_scheme].data_hdr;
}
GprsCodingScheme::Family GprsCodingScheme::family() const
GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs(GprsCodingScheme *current_mcs) const
{
return mcs_info[m_scheme].family;
}
void GprsCodingScheme::inc(Mode mode)
{
if (!isCompatible(mode))
/* This should not happen. TODO: Use assert? */
return;
Scheme new_cs(Scheme(m_scheme + 1));
if (!GprsCodingScheme(new_cs).isCompatible(mode))
/* Clipping, do not change the value */
return;
m_scheme = new_cs;
}
void GprsCodingScheme::dec(Mode mode)
{
if (!isCompatible(mode))
/* This should not happen. TODO: Use assert? */
return;
Scheme new_cs(Scheme(m_scheme - 1));
if (!GprsCodingScheme(new_cs).isCompatible(mode))
/* Clipping, do not change the value */
return;
m_scheme = new_cs;
}
void GprsCodingScheme::inc()
{
if (isGprs() && m_scheme == CS4)
return;
if (isEgprs() && m_scheme == MCS9)
return;
if (!isValid())
return;
m_scheme = Scheme(m_scheme + 1);
}
void GprsCodingScheme::dec()
{
if (isGprs() && m_scheme == CS1)
return;
if (isEgprs() && m_scheme == MCS1)
return;
if (!isValid())
return;
m_scheme = Scheme(m_scheme - 1);
}
const char *GprsCodingScheme::modeName(Mode mode)
{
switch (mode) {
case GPRS: return "GPRS";
case EGPRS_GMSK: return "EGPRS_GMSK-only";
case EGPRS: return "EGPRS";
default: return "???";
}
}
bool GprsCodingScheme::isFamilyCompatible(GprsCodingScheme o) const
{
if (*this == o)
return true;
if (family() == FAMILY_INVALID)
return false;
return family() == o.family();
}
bool GprsCodingScheme::isCombinable(GprsCodingScheme o) const
{
return numDataBlocks() == o.numDataBlocks();
}
void GprsCodingScheme::decToSingleBlock(bool *needStuffing)
{
switch (m_scheme) {
case MCS7: *needStuffing = false; m_scheme = MCS5; break;
case MCS8: *needStuffing = true; m_scheme = MCS6; break;
case MCS9: *needStuffing = false; m_scheme = MCS6; break;
default: *needStuffing = false; break;
}
return egprs_mcs_retx_tbl[EGPRS_ARQ1][current_mcs->coding_scheme()- GprsCodingScheme::MCS1]
[this->m_scheme - GprsCodingScheme::MCS1];
}

View File

@ -23,20 +23,42 @@
#include <stdint.h>
#include <stddef.h>
#define MAX_NUM_ARQ 2 /* max. number of ARQ */
#define MAX_NUM_MCS 9 /* max. number of MCS */
#define MAX_NUM_PS 3 /* max. number of puncturing schemes */
#define EGPRS_ARQ1 0x0
#define EGPRS_ARQ2 0x1
struct egprs_ps_sel_tbl{
uint8_t next_ps; /* next puncturing scheme */
uint8_t action; /* action to be taken on counter */
};
enum PsTypes{
EGPRS_PS_TYPE_2,
EGPRS_PS_TYPE_3,
};
enum PsValues {
EGPRS_PS1 = 0,
EGPRS_PS2,
EGPRS_PS3,
};
class GprsCodingScheme {
public:
enum Scheme {
UNKNOWN,
CS1, CS2, CS3, CS4,
MCS1, MCS2, MCS3, MCS4,
MCS5, MCS6, MCS7, MCS8, MCS9,
MCS1,MCS2, MCS3, MCS4,
MCS5,MCS6, MCS7, MCS8, MCS9,
NUM_SCHEMES
};
enum Mode {
GPRS,
EGPRS_GMSK,
EGPRS,
};
@ -47,170 +69,110 @@ public:
HEADER_EGPRS_DATA_TYPE_1,
HEADER_EGPRS_DATA_TYPE_2,
HEADER_EGPRS_DATA_TYPE_3,
NUM_HEADER_TYPES
};
enum Family {
FAMILY_INVALID,
FAMILY_A,
FAMILY_B,
FAMILY_C,
};
GprsCodingScheme(Scheme s = UNKNOWN);
GprsCodingScheme(Scheme s = UNKNOWN,Mode scheme_type = GPRS);
operator bool() const {return m_scheme != UNKNOWN;}
operator Scheme() const {return m_scheme;}
unsigned int to_num() const;
GprsCodingScheme& operator =(Scheme s);
GprsCodingScheme& operator =(GprsCodingScheme o);
operator int() const {return (int)m_scheme;}
void operator =(Scheme s);
GprsCodingScheme operator + (Scheme scheme);
GprsCodingScheme operator -(Scheme scheme);
void operator =(GprsCodingScheme o);
void operator =(int o);
bool operator ==(Scheme o);
bool operator >= (Scheme o);
bool isValid() const {return UNKNOWN <= m_scheme && m_scheme <= MCS9;}
bool isGprs() const {return CS1 <= m_scheme && m_scheme <= CS4;}
bool isEgprs() const {return m_scheme >= MCS1;}
bool isEgprsGmsk() const {return isEgprs() && m_scheme <= MCS4;}
bool isCompatible(Mode mode) const;
bool isCompatible(GprsCodingScheme o) const;
bool isFamilyCompatible(GprsCodingScheme o) const;
bool isCombinable(GprsCodingScheme o) const;
void inc(Mode mode);
void dec(Mode mode);
void inc();
void dec();
void decToSingleBlock(bool *needStuffing);
uint8_t get_cps(uint8_t ps, bool is_mcs8_retx = false);
unsigned int sizeUL() const;
unsigned int sizeDL() const;
unsigned int usedSizeUL() const;
unsigned int usedSizeDL() const;
unsigned int maxBytesUL() const;
unsigned int maxBytesDL() const;
unsigned int spareBitsUL() const;
unsigned int spareBitsDL() const;
unsigned int maxDataBlockBytes() const;
unsigned int numDataBlocks() const;
unsigned int numDataHeaderBitsUL() const;
unsigned int numDataHeaderBitsDL() const;
unsigned int numDataBlockHeaderBits() const;
unsigned int optionalPaddingBits() const;
Scheme coding_scheme() const;
const char *name() const;
HeaderType headerTypeData() const;
HeaderType headerTypeControl() const;
Family family() const;
static GprsCodingScheme getBySizeUL(unsigned size);
static GprsCodingScheme getGprsByNum(unsigned num);
static GprsCodingScheme getEgprsByNum(unsigned num);
Scheme get_retx_mcs(GprsCodingScheme *current_mcs) const;
static const char *modeName(Mode mode);
private:
GprsCodingScheme(int s); /* fail on use */
GprsCodingScheme& operator =(int s); /* fail on use */
enum Scheme m_scheme;
enum Mode m_scheme_type;
};
inline unsigned int GprsCodingScheme::to_num() const
{
if (isGprs())
return (m_scheme - CS1) + 1;
if (isEgprs())
return (m_scheme - MCS1) + 1;
return 0;
}
struct egprs_mcs_ps{
GprsCodingScheme::Scheme mcs; /* GprsCodingScheme::MCS */
uint8_t ps; /* MEAN_BEP */
};
inline bool GprsCodingScheme::isCompatible(Mode mode) const
{
switch (mode) {
case GPRS: return isGprs();
case EGPRS_GMSK: return isEgprsGmsk();
case EGPRS: return isEgprs();
}
return false;
}
inline bool GprsCodingScheme::isCompatible(GprsCodingScheme o) const
{
return (isGprs() && o.isGprs()) || (isEgprs() && o.isEgprs());
}
inline GprsCodingScheme::HeaderType GprsCodingScheme::headerTypeControl() const
{
return HEADER_GPRS_CONTROL;
}
inline GprsCodingScheme::GprsCodingScheme(Scheme s)
: m_scheme(s)
inline GprsCodingScheme::GprsCodingScheme(Scheme s, Mode scheme_type )
: m_scheme(s), m_scheme_type(scheme_type)
{
if (!isValid())
m_scheme = UNKNOWN;
}
inline GprsCodingScheme& GprsCodingScheme::operator =(Scheme s)
inline void GprsCodingScheme::operator =(Scheme s)
{
m_scheme = s;
if (!isValid())
m_scheme = UNKNOWN;
return *this;
}
inline GprsCodingScheme& GprsCodingScheme::operator =(GprsCodingScheme o)
inline void GprsCodingScheme::operator =(GprsCodingScheme o)
{
m_scheme = o.m_scheme;
return *this;
m_scheme_type = o.m_scheme_type;
}
inline GprsCodingScheme GprsCodingScheme::getGprsByNum(unsigned num)
inline bool GprsCodingScheme::operator ==(Scheme o)
{
if (num < 1 || num > 4)
return GprsCodingScheme();
return GprsCodingScheme(Scheme(CS1 + (num - 1)));
if( this->m_scheme != o)
{
return false;
}
return true;
}
inline GprsCodingScheme GprsCodingScheme::getEgprsByNum(unsigned num)
inline GprsCodingScheme GprsCodingScheme::operator + (Scheme o)
{
if (num < 1 || num > 9)
return GprsCodingScheme();
return GprsCodingScheme(Scheme(MCS1 + (num - 1)));
GprsCodingScheme cs((Scheme)(this->m_scheme + o));
return (cs);
}
/* The coding schemes form a partial ordering */
inline bool operator ==(GprsCodingScheme a, GprsCodingScheme b)
inline GprsCodingScheme GprsCodingScheme::operator - (Scheme o)
{
return GprsCodingScheme::Scheme(a) == GprsCodingScheme::Scheme(b);
GprsCodingScheme cs((Scheme)(this->m_scheme - o));
return (cs);
}
inline bool operator !=(GprsCodingScheme a, GprsCodingScheme b)
inline bool GprsCodingScheme::operator >= (Scheme o)
{
return !(a == b);
if(this->m_scheme >= o){
return true;
}
return false;
}
inline bool operator <(GprsCodingScheme a, GprsCodingScheme b)
{
return a.isCompatible(b) &&
GprsCodingScheme::Scheme(a) < GprsCodingScheme::Scheme(b);
}
inline bool operator >(GprsCodingScheme a, GprsCodingScheme b)
{
return b < a;
}
inline bool operator <=(GprsCodingScheme a, GprsCodingScheme b)
{
return a == b || a < b;
}
inline bool operator >=(GprsCodingScheme a, GprsCodingScheme b)
{
return a == b || a > b;
}

View File

@ -25,7 +25,6 @@
#include "tbf.h"
#include "gprs_debug.h"
#include "gprs_codel.h"
#include "pcu_utils.h"
#include <time.h>
@ -98,6 +97,8 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
m_ta(0),
m_ms_class(0),
m_egprs_ms_class(0),
m_current_cs_ul(1),
m_current_cs_dl(1),
m_is_idle(true),
m_ref(0),
m_list(this),
@ -106,8 +107,7 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
m_reserved_dl_slots(0),
m_reserved_ul_slots(0),
m_current_trx(NULL),
m_codel_state(NULL),
m_mode(GprsCodingScheme::GPRS)
m_codel_state(NULL)
{
int codel_interval = LLC_CODEL_USE_DEFAULT;
@ -117,11 +117,17 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
memset(&m_timer, 0, sizeof(m_timer));
m_timer.cb = GprsMs::timeout;
m_llc_queue.init();
if (m_bts) {
m_current_cs_ul = m_bts->bts_data()->initial_cs_ul;
if (m_current_cs_ul < 1)
m_current_cs_ul = 1;
set_mode(m_mode);
m_current_cs_dl = m_bts->bts_data()->initial_cs_dl;
if (m_current_cs_dl < 1)
m_current_cs_dl = 1;
if (m_bts)
codel_interval = m_bts->bts_data()->llc_codel_interval_msec;
}
if (codel_interval) {
if (codel_interval == LLC_CODEL_USE_DEFAULT)
@ -209,53 +215,12 @@ void GprsMs::stop_timer()
unref();
}
void GprsMs::set_mode(GprsCodingScheme::Mode mode)
{
m_mode = mode;
if (!m_bts)
return;
switch (m_mode) {
case GprsCodingScheme::GPRS:
if (!m_current_cs_ul.isGprs()) {
m_current_cs_ul = GprsCodingScheme::getGprsByNum(
m_bts->bts_data()->initial_cs_ul);
if (!m_current_cs_ul.isValid())
m_current_cs_ul = GprsCodingScheme::CS1;
}
if (!m_current_cs_dl.isGprs()) {
m_current_cs_dl = GprsCodingScheme::getGprsByNum(
m_bts->bts_data()->initial_cs_dl);
if (!m_current_cs_dl.isValid())
m_current_cs_dl = GprsCodingScheme::CS1;
}
break;
case GprsCodingScheme::EGPRS_GMSK:
case GprsCodingScheme::EGPRS:
if (!m_current_cs_ul.isEgprs()) {
m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
m_bts->bts_data()->initial_mcs_ul);
if (!m_current_cs_dl.isValid())
m_current_cs_ul = GprsCodingScheme::MCS1;
}
if (!m_current_cs_dl.isEgprs()) {
m_current_cs_dl = GprsCodingScheme::getEgprsByNum(
m_bts->bts_data()->initial_mcs_dl);
if (!m_current_cs_dl.isValid())
m_current_cs_dl = GprsCodingScheme::MCS1;
}
break;
}
}
void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
{
if (tbf->direction == GPRS_RLCMAC_DL_TBF)
attach_dl_tbf(as_dl_tbf(tbf));
attach_dl_tbf(static_cast<gprs_rlcmac_dl_tbf *>(tbf));
else
attach_ul_tbf(as_ul_tbf(tbf));
attach_ul_tbf(static_cast<gprs_rlcmac_ul_tbf *>(tbf));
}
void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
@ -482,7 +447,6 @@ void GprsMs::set_ms_class(uint8_t ms_class_)
m_ms_class = ms_class_;
}
void GprsMs::set_egprs_ms_class(uint8_t ms_class_)
{
if (ms_class_ == m_egprs_ms_class)
@ -494,14 +458,13 @@ void GprsMs::set_egprs_ms_class(uint8_t ms_class_)
m_egprs_ms_class = ms_class_;
}
void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
{
struct gprs_rlcmac_bts *bts_data;
int64_t now;
GprsCodingScheme max_cs_dl = this->max_cs_dl();
uint8_t max_cs_dl = 4;
OSMO_ASSERT(max_cs_dl);
OSMO_ASSERT(m_bts != NULL);
bts_data = m_bts->bts_data();
if (error_rate < 0)
@ -509,30 +472,32 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
now = now_msec();
if (bts_data->max_cs_dl)
max_cs_dl = bts_data->max_cs_dl;
/* TODO: Check for TBF direction */
/* TODO: Support different CS values for UL and DL */
m_nack_rate_dl = error_rate;
if (error_rate > bts_data->cs_adj_upper_limit) {
if (m_current_cs_dl.to_num() > 1) {
m_current_cs_dl.dec(mode());
if (m_current_cs_dl > 1) {
m_current_cs_dl -= 1;
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): High error rate %d%%, "
"reducing CS level to %s\n",
imsi(), error_rate, m_current_cs_dl.name());
"reducing CS level to %d\n",
imsi(), error_rate, m_current_cs_dl);
m_last_cs_not_low = now;
}
} else if (error_rate < bts_data->cs_adj_lower_limit) {
if (m_current_cs_dl < max_cs_dl) {
if (now - m_last_cs_not_low > 1000) {
m_current_cs_dl.inc(mode());
m_current_cs_dl += 1;
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): Low error rate %d%%, "
"increasing DL CS level to %s\n",
imsi(), error_rate,
m_current_cs_dl.name());
"increasing DL CS level to %d\n",
imsi(), error_rate, m_current_cs_dl);
m_last_cs_not_low = now;
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
@ -549,124 +514,45 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
}
}
GprsCodingScheme GprsMs::max_cs_ul() const
{
struct gprs_rlcmac_bts *bts_data;
OSMO_ASSERT(m_bts != NULL);
bts_data = m_bts->bts_data();
if (m_current_cs_ul.isGprs()) {
if (!bts_data->max_cs_ul)
return GprsCodingScheme(GprsCodingScheme::CS4);
return GprsCodingScheme::getGprsByNum(bts_data->max_cs_ul);
}
if (!m_current_cs_ul.isEgprs())
return GprsCodingScheme(); /* UNKNOWN */
if (bts_data->max_mcs_ul)
return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_ul);
else if (bts_data->max_cs_ul)
return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_ul);
return GprsCodingScheme(GprsCodingScheme::MCS4);
}
GprsCodingScheme GprsMs::max_cs_dl() const
{
struct gprs_rlcmac_bts *bts_data;
OSMO_ASSERT(m_bts != NULL);
bts_data = m_bts->bts_data();
if (m_current_cs_dl.isGprs()) {
if (!bts_data->max_cs_dl)
return GprsCodingScheme(GprsCodingScheme::CS4);
return GprsCodingScheme::getGprsByNum(bts_data->max_cs_dl);
}
if (!m_current_cs_dl.isEgprs())
return GprsCodingScheme(); /* UNKNOWN */
if (bts_data->max_mcs_dl)
return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_dl);
else if (bts_data->max_cs_dl)
return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_dl);
return GprsCodingScheme(GprsCodingScheme::MCS4);
}
void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
{
struct gprs_rlcmac_bts *bts_data;
GprsCodingScheme max_cs_ul = this->max_cs_ul();
int old_link_qual;
int low;
int high;
GprsCodingScheme new_cs_ul = m_current_cs_ul;
unsigned current_cs_num = m_current_cs_ul.to_num();
bts_data = m_bts->bts_data();
if (!max_cs_ul) {
LOGP(DRLCMACDL, LOGL_ERROR,
"max_cs_ul cannot be derived (current UL CS: %s)\n",
m_current_cs_ul.name());
return;
}
if (!m_current_cs_ul)
return;
if (!meas->have_link_qual)
return;
old_link_qual = meas->link_qual;
if (m_current_cs_ul.isGprs()) {
low = bts_data->cs_lqual_ranges[current_cs_num-1].low;
high = bts_data->cs_lqual_ranges[current_cs_num-1].high;
} else if (m_current_cs_ul.isEgprs()) {
/* TODO, use separate table */
if (current_cs_num > 4)
current_cs_num = 4;
low = bts_data->cs_lqual_ranges[current_cs_num-1].low;
high = bts_data->cs_lqual_ranges[current_cs_num-1].high;
} else {
return;
}
if (m_l1_meas.have_link_qual)
old_link_qual = m_l1_meas.link_qual;
if (meas->link_qual < low && old_link_qual < low)
new_cs_ul.dec(mode());
else if (meas->link_qual > high && old_link_qual > high &&
m_current_cs_ul < max_cs_ul)
new_cs_ul.inc(mode());
if (m_current_cs_ul != new_cs_ul) {
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): "
"Link quality %ddB (%ddB) left window [%d, %d], "
"modifying uplink CS level: %s -> %s\n",
imsi(), meas->link_qual, old_link_qual,
low, high,
m_current_cs_ul.name(), new_cs_ul.name());
m_current_cs_ul = new_cs_ul;
}
}
void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
{
struct gprs_rlcmac_bts *bts_data;
uint8_t max_cs_ul = 4;
unsigned i;
update_cs_ul(meas);
OSMO_ASSERT(m_bts != NULL);
bts_data = m_bts->bts_data();
if (bts_data->max_cs_ul)
max_cs_ul = bts_data->max_cs_ul;
if (meas->have_link_qual) {
int old_link_qual = meas->link_qual;
int low = bts_data->cs_lqual_ranges[current_cs_ul()-1].low;
int high = bts_data->cs_lqual_ranges[current_cs_ul()-1].high;
uint8_t new_cs_ul = m_current_cs_ul;
if (m_l1_meas.have_link_qual)
old_link_qual = m_l1_meas.link_qual;
if (meas->link_qual < low && old_link_qual < low)
new_cs_ul = m_current_cs_ul - 1;
else if (meas->link_qual > high && old_link_qual > high &&
m_current_cs_ul < max_cs_ul)
new_cs_ul = m_current_cs_ul + 1;
if (m_current_cs_ul != new_cs_ul) {
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): "
"Link quality %ddB (%ddB) left window [%d, %d], "
"modifying uplink CS level: %d -> %d\n",
imsi(), meas->link_qual, old_link_qual,
low, high,
m_current_cs_ul, new_cs_ul);
m_current_cs_ul = new_cs_ul;
}
}
if (meas->have_rssi)
m_l1_meas.set_rssi(meas->rssi);
@ -694,9 +580,20 @@ void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
}
}
GprsCodingScheme GprsMs::current_cs_dl() const
void GprsMs::set_current_cs_dl(uint8_t mcs)
{
GprsCodingScheme cs = m_current_cs_dl;
m_current_cs_dl = mcs;
}
void GprsMs::set_current_cs_ul(uint8_t mcs)
{
m_current_cs_ul = mcs;
}
uint8_t GprsMs::current_cs_dl() const
{
uint8_t cs = m_current_cs_dl;
size_t unencoded_octets;
if (!m_bts)
@ -706,7 +603,7 @@ GprsCodingScheme GprsMs::current_cs_dl() const
/* If the DL TBF is active, add number of unencoded chunk octets */
if (m_dl_tbf)
unencoded_octets += m_dl_tbf->m_llc.chunk_size();
unencoded_octets = m_dl_tbf->m_llc.chunk_size();
/* There are many unencoded octets, don't reduce */
if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
@ -717,11 +614,11 @@ GprsCodingScheme GprsMs::current_cs_dl() const
return cs;
/* The throughput would probably be better if the CS level was reduced */
cs.dec(mode());
cs -= 1;
/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
if (cs == GprsCodingScheme(GprsCodingScheme::CS2))
cs.dec(mode());
if (cs == 2)
cs -= 1;
return cs;
}
@ -763,31 +660,6 @@ uint8_t GprsMs::ul_slots() const
return slots;
}
uint8_t GprsMs::current_pacch_slots() const
{
uint8_t slots = 0;
bool is_dl_active = m_dl_tbf && m_dl_tbf->is_tfi_assigned();
bool is_ul_active = m_ul_tbf && m_ul_tbf->is_tfi_assigned();
if (!is_dl_active && !is_ul_active)
return 0;
/* see TS 44.060, 8.1.1.2.2 */
if (is_dl_active && !is_ul_active)
slots = m_dl_tbf->dl_slots();
else if (!is_dl_active && is_ul_active)
slots = m_ul_tbf->ul_slots();
else
slots = m_ul_tbf->ul_slots() & m_dl_tbf->dl_slots();
/* Assume a multislot class 1 device */
/* TODO: For class 2 devices, this could be removed */
slots = pcu_lsb(slots);
return slots;
}
void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots)
{

View File

@ -74,8 +74,6 @@ public:
bool check_tlli(uint32_t tlli);
void reset();
GprsCodingScheme::Mode mode() const;
void set_mode(GprsCodingScheme::Mode mode);
const char *imsi() const;
void set_imsi(const char *imsi);
@ -83,21 +81,19 @@ public:
uint8_t ta() const;
void set_ta(uint8_t ta);
uint8_t ms_class() const;
void set_egprs_ms_class(uint8_t ms_class);
uint8_t egprs_ms_class() const;
void set_ms_class(uint8_t ms_class);
void set_egprs_ms_class(uint8_t ms_class);
GprsCodingScheme current_cs_ul() const;
GprsCodingScheme current_cs_dl() const;
GprsCodingScheme max_cs_ul() const;
GprsCodingScheme max_cs_dl() const;
uint8_t current_cs_ul() const;
uint8_t current_cs_dl() const;
void set_current_cs_ul(uint8_t mcs);
void set_current_cs_dl(uint8_t mcs);
int first_common_ts() const;
uint8_t dl_slots() const;
uint8_t ul_slots() const;
uint8_t reserved_dl_slots() const;
uint8_t reserved_ul_slots() const;
uint8_t current_pacch_slots() const;
gprs_rlcmac_trx *current_trx() const;
void set_reserved_slots(gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots);
@ -127,6 +123,7 @@ public:
const LListHead<gprs_rlcmac_tbf>& old_tbfs() const {return m_old_tbfs;}
void update_l1_meas(const pcu_l1_meas *meas);
void update_egprs_l1_meas(const pcu_l1_meas *meas);
const pcu_l1_meas* l1_meas() const {return &m_l1_meas;};
unsigned nack_rate_dl() const;
@ -139,7 +136,6 @@ protected:
void unref();
void start_timer();
void stop_timer();
void update_cs_ul(const pcu_l1_meas*);
private:
BTS *m_bts;
@ -156,10 +152,11 @@ private:
char m_imsi[16];
uint8_t m_ta;
uint8_t m_ms_class;
uint8_t m_egprs_ms_class;
/* current coding scheme */
GprsCodingScheme m_current_cs_ul;
GprsCodingScheme m_current_cs_dl;
uint8_t m_current_cs_ul;
uint8_t m_current_cs_dl;
gprs_llc_queue m_llc_queue;
@ -178,7 +175,6 @@ private:
gprs_rlcmac_trx *m_current_trx;
struct gprs_codel *m_codel_state;
GprsCodingScheme::Mode m_mode;
};
inline bool GprsMs::is_idle() const
@ -221,22 +217,15 @@ inline uint8_t GprsMs::ms_class() const
{
return m_ms_class;
}
inline uint8_t GprsMs::egprs_ms_class() const
{
return m_egprs_ms_class;
}
inline GprsCodingScheme GprsMs::current_cs_ul() const
inline uint8_t GprsMs::current_cs_ul() const
{
return m_current_cs_ul;
}
inline GprsCodingScheme::Mode GprsMs::mode() const
{
return m_mode;
}
inline void GprsMs::set_timeout(unsigned secs)
{
m_delay = secs;

View File

@ -33,11 +33,6 @@ GprsMsStorage::GprsMsStorage(BTS *bts) :
}
GprsMsStorage::~GprsMsStorage()
{
cleanup();
}
void GprsMsStorage::cleanup()
{
LListHead<GprsMs> *pos, *tmp;

View File

@ -33,8 +33,6 @@ public:
GprsMsStorage(BTS *bts);
~GprsMsStorage();
void cleanup();
virtual void ms_idle(class GprsMs *);
virtual void ms_active(class GprsMs *);

View File

@ -25,7 +25,7 @@
#include "pcu_utils.h"
static uint32_t sched_poll(BTS *bts,
static uint32_t sched_poll(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr,
struct gprs_rlcmac_tbf **poll_tbf,
struct gprs_rlcmac_tbf **ul_ass_tbf,
@ -34,7 +34,7 @@ static uint32_t sched_poll(BTS *bts,
{
struct gprs_rlcmac_ul_tbf *ul_tbf;
struct gprs_rlcmac_dl_tbf *dl_tbf;
LListHead<gprs_rlcmac_tbf> *pos;
struct llist_pods *lpods;
uint32_t poll_fn;
/* check special TBF for events */
@ -42,11 +42,9 @@ static uint32_t sched_poll(BTS *bts,
if ((block_nr % 3) == 2)
poll_fn ++;
poll_fn = poll_fn % 2715648;
llist_for_each(pos, &bts->ul_tbfs()) {
ul_tbf = as_ul_tbf(pos->entry());
OSMO_ASSERT(ul_tbf);
llist_pods_for_each_entry(ul_tbf, &bts->ul_tbfs, list, lpods) {
/* this trx, this ts */
if (ul_tbf->trx->trx_no != trx || !ul_tbf->is_control_ts(ts))
if (ul_tbf->trx->trx_no != trx || ul_tbf->control_ts != ts)
continue;
/* polling for next uplink block */
if (ul_tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
@ -60,11 +58,9 @@ static uint32_t sched_poll(BTS *bts,
*ul_ass_tbf = ul_tbf;
#warning "Is this supposed to be fair? The last TBF for each wins? Maybe use llist_add_tail and skip once we have all states?"
}
llist_for_each(pos, &bts->dl_tbfs()) {
dl_tbf = as_dl_tbf(pos->entry());
OSMO_ASSERT(dl_tbf);
llist_pods_for_each_entry(dl_tbf, &bts->dl_tbfs, list, lpods) {
/* this trx, this ts */
if (dl_tbf->trx->trx_no != trx || !dl_tbf->is_control_ts(ts))
if (dl_tbf->trx->trx_no != trx || dl_tbf->control_ts != ts)
continue;
/* polling for next uplink block */
if (dl_tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
@ -130,18 +126,14 @@ static struct msgb *sched_select_ctrl_msg(
if (!tbf)
continue;
/*
* Assignments for the same direction have lower precedence,
* because they may kill the TBF when the CONTOL ACK is
* received, thus preventing the others from being processed.
*/
if (tbf == ul_ass_tbf && tbf->direction == GPRS_RLCMAC_DL_TBF)
msg = ul_ass_tbf->create_ul_ass(fn, ts);
else if (tbf == dl_ass_tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
msg = dl_ass_tbf->create_dl_ass(fn, ts);
if (tbf == ul_ass_tbf)
msg = ul_ass_tbf->create_ul_ass(fn);
else if (tbf == dl_ass_tbf)
msg = dl_ass_tbf->create_dl_ass(fn);
else if (tbf == ul_ack_tbf)
msg = ul_ack_tbf->create_ul_ack(fn, ts);
msg = ul_ack_tbf->create_ul_ack(fn);
else
abort();
if (!msg) {
tbf = NULL;
@ -153,21 +145,6 @@ static struct msgb *sched_select_ctrl_msg(
break;
}
if (!msg) {
/*
* If one of these is left, the response (CONTROL ACK) from the
* MS will kill the current TBF, only one of them can be
* non-NULL
*/
if (dl_ass_tbf) {
tbf = dl_ass_tbf;
msg = dl_ass_tbf->create_dl_ass(fn, ts);
} else if (ul_ass_tbf) {
tbf = ul_ass_tbf;
msg = ul_ass_tbf->create_ul_ass(fn, ts);
}
}
/* any message */
if (msg) {
tbf->rotate_in_list();
@ -315,7 +292,7 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
/* store last frame number of RTS */
pdch->last_rts_fn = fn;
poll_fn = sched_poll(bts->bts, trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf,
poll_fn = sched_poll(bts, trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf,
&dl_ass_tbf, &ul_ack_tbf);
/* check uplink resource for polling */
if (poll_tbf)
@ -353,7 +330,6 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
/* msg is now available */
/* set USF */
OSMO_ASSERT(msgb_length(msg) > 0);
msg->data[0] = (msg->data[0] & 0xf8) | usf;
/* Used to measure the leak rate, count all blocks */

View File

@ -24,7 +24,6 @@
#include <bts.h>
#include <tbf.h>
#include <gprs_ms.h>
#include <pcu_utils.h>
#include <errno.h>
#include <values.h>
@ -81,6 +80,20 @@ static const struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = {
/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
};
static unsigned lsb(unsigned x)
{
return x & -x;
}
static unsigned bitcount(unsigned x)
{
unsigned count = 0;
for (count = 0; x; count += 1)
x &= x - 1;
return count;
}
static char *set_flag_chars(char *buf, uint8_t val, char set_char, char unset_char = 0)
{
int i;
@ -467,12 +480,14 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
/* The allocation will be successful, so the system state and tbf_/ms_
* may be modified from now on. */
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf_);
struct gprs_rlcmac_ul_tbf *ul_tbf =
static_cast<gprs_rlcmac_ul_tbf *>(tbf_);
LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink TS=%d TFI=%d USF=%d\n",
ts, tfi, usf);
assign_uplink_tbf_usf(pdch, ul_tbf, tfi, usf);
} else {
struct gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf_);
struct gprs_rlcmac_dl_tbf *dl_tbf =
static_cast<gprs_rlcmac_dl_tbf *>(tbf_);
LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d TFI=%d\n",
ts, tfi);
assign_dlink_tbf(pdch, dl_tbf, tfi);
@ -490,7 +505,7 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
static int find_multi_slots(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_trx *trx,
const GprsMs *ms, uint8_t *ul_slots, uint8_t *dl_slots)
const GprsMs *ms, uint8_t *ul_slots, uint8_t *dl_slots, const gprs_rlcmac_tbf *tbf)
{
const struct gprs_ms_multislot_class *ms_class;
uint8_t Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
@ -514,8 +529,12 @@ static int find_multi_slots(struct gprs_rlcmac_bts *bts,
ms->ms_class());
return -EINVAL;
}
if (ms->ms_class()) {
if (tbf->is_egprs_enabled()) {
ms_class = &gprs_ms_multislot_class[ms->egprs_ms_class()];
LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for "
"class %d\n", ms->egprs_ms_class());
}
else if(ms->ms_class()) {
ms_class = &gprs_ms_multislot_class[ms->ms_class()];
LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for "
"class %d\n", ms->ms_class());
@ -627,7 +646,7 @@ static int find_multi_slots(struct gprs_rlcmac_bts *bts,
if ((tx_window & (1 << ((ul_ts+num_tx-1) % 8))) == 0)
continue;
tx_slot_count = pcu_bitcount(tx_window);
tx_slot_count = bitcount(tx_window);
max_rx = OSMO_MIN(ms_class->rx, ms_class->sum - num_tx);
rx_valid_win = (1 << max_rx) - 1;
@ -656,7 +675,7 @@ static int find_multi_slots(struct gprs_rlcmac_bts *bts,
* testing */
rx_window = rx_good & rx_valid_win;
rx_slot_count = pcu_bitcount(rx_window);
rx_slot_count = bitcount(rx_window);
#if 0
LOGP(DRLCMAC, LOGL_DEBUG, "n_tx=%d, n_rx=%d, mask_sel=%d, "
@ -721,7 +740,7 @@ static int find_multi_slots(struct gprs_rlcmac_bts *bts,
continue;
/* Check number of common slots according to TS 54.002, 6.4.2.2 */
common_slot_count = pcu_bitcount(tx_window & rx_window);
common_slot_count = bitcount(tx_window & rx_window);
req_common_slots = OSMO_MIN(tx_slot_count, rx_slot_count);
if (ms_class->type == 1)
req_common_slots = OSMO_MIN(req_common_slots, 2);
@ -858,7 +877,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
trx = &bts->trx[trx_no];
if (!dl_slots || !ul_slots) {
rc = find_multi_slots(bts, trx, ms, &ul_slots, &dl_slots);
rc = find_multi_slots(bts, trx, ms, &ul_slots, &dl_slots, tbf);
if (rc < 0)
return rc;
@ -878,7 +897,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
dl_slots & ul_slots, compute_usage_by_num_tbfs,
NULL, NULL);
if (ts < 0)
ul_slots = dl_slots = pcu_lsb(dl_slots & ul_slots);
ul_slots = dl_slots = lsb(dl_slots & ul_slots);
else
ul_slots = dl_slots = (dl_slots & ul_slots) & (1<<ts);
}
@ -907,9 +926,9 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
"available\n");
return -EINVAL;
}
slotcount = pcu_bitcount(dl_slots);
slotcount = bitcount(dl_slots);
first_ts = ffs(dl_slots) - 1;
avail_count = pcu_bitcount(reserved_dl_slots);
avail_count = bitcount(reserved_dl_slots);
} else {
int free_usf = -1;
@ -945,7 +964,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
/* We will stick to that single UL slot, unreserve the others */
reserved_ul_slots = ul_slots;
avail_count = pcu_bitcount(reserved_ul_slots);
avail_count = bitcount(reserved_ul_slots);
}
first_common_ts = ffs(dl_slots & ul_slots) - 1;
@ -995,7 +1014,8 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
tbf_->first_ts = first_ts;
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
struct gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf_);
struct gprs_rlcmac_dl_tbf *dl_tbf =
static_cast<gprs_rlcmac_dl_tbf *>(tbf_);
for (ts = 0; ts < 8; ts++) {
if (!(dl_slots & (1 << ts)))
continue;
@ -1005,7 +1025,8 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
assign_dlink_tbf(&trx->pdch[ts], dl_tbf, tfi);
}
} else {
struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf_);
struct gprs_rlcmac_ul_tbf *ul_tbf =
static_cast<gprs_rlcmac_ul_tbf *>(tbf_);
for (ts = 0; ts < 8; ts++) {
if (!(ul_slots & (1 << ts)))

View File

@ -197,16 +197,23 @@ gint16 Egprs_Ack_Nack_Desc_w_len_Dissector(csnStream_t* ar, bitvec *vector, unsi
}
/* this intermediate structure is only required because M_SERIALIZE cannot be used as a member of M_UNION */
/*< EGPRS Ack/Nack Description struct >*/
static const
CSN_DESCR_BEGIN (EGPRS_AckNack_w_len_t)
M_UINT (EGPRS_AckNack_w_len_t, LENGTH, 8),
M_TYPE (EGPRS_AckNack_w_len_t, Desc, EGPRS_AckNack_Desc_t),
CSN_DESCR_END (EGPRS_AckNack_w_len_t)
#if 0
static const
CSN_DESCR_BEGIN(EGPRS_AckNack_w_len_t)
M_SERIALIZE (EGPRS_AckNack_w_len_t, Desc, 8, Egprs_Ack_Nack_Desc_w_len_Dissector),
CSN_DESCR_END (EGPRS_AckNack_w_len_t)
#endif
static const
CSN_DESCR_BEGIN(EGPRS_AckNack_t)
M_UNION (EGPRS_AckNack_t, 2),
M_TYPE (EGPRS_AckNack_t, Desc, EGPRS_AckNack_Desc_t),
M_TYPE (EGPRS_AckNack_t, Desc, EGPRS_AckNack_w_len_t),
CSN_DESCR_END (EGPRS_AckNack_t)
/*<P1 Rest Octets>*/
@ -1297,8 +1304,10 @@ CSN_DESCR_BEGIN(EGPRS_PD_AckNack_t)
M_NEXT_EXIST (EGPRS_PD_AckNack_t, Exist_ExtensionBits, 1),
M_TYPE (EGPRS_PD_AckNack_t, ExtensionBits, Extension_Bits_t),
M_TYPE (EGPRS_PD_AckNack_t, EGPRS_AckNack, EGPRS_AckNack_t),
/* M_CALLBACK (EGPRS_PD_AckNack_t, (void*)24, EGPRS_AckNack, EGPRS_AckNack), */
M_UNION (EGPRS_PD_AckNack_t, 2),
M_TYPE (EGPRS_PD_AckNack_t, u.EGPRS_AckNack, EGPRS_AckNack_t),
M_TYPE (EGPRS_PD_AckNack_t, u.EGPRS_AckNack_len,EGPRS_AckNack_w_len_t ),
/*M_CALLBACK (EGPRS_PD_AckNack_t, (void*)24, EGPRS_AckNack, EGPRS_AckNack), */
M_PADDING_BITS(EGPRS_PD_AckNack_t),
CSN_DESCR_END (EGPRS_PD_AckNack_t)
@ -1621,9 +1630,9 @@ CSN_DESCR_BEGIN(Dynamic_Allocation_t)
M_NEXT_EXIST (Dynamic_Allocation_t, Exist_UPLINK_TFI_ASSIGNMENT, 1),
M_UINT (Dynamic_Allocation_t, UPLINK_TFI_ASSIGNMENT, 5),
M_NEXT_EXIST (Dynamic_Allocation_t, Exist_RLC_DATA_BLOCKS_GRANTED, 1),
M_UINT (Dynamic_Allocation_t, RLC_DATA_BLOCKS_GRANTED, 8),
M_FIXED (Dynamic_Allocation_t, 1, 0x00), /* Message Escape */
//M_NEXT_EXIST (Dynamic_Allocation_t, Exist_RLC_DATA_BLOCKS_GRANTED, 1),
//M_UINT (Dynamic_Allocation_t, RLC_DATA_BLOCKS_GRANTED, 8),
M_NEXT_EXIST (Dynamic_Allocation_t, Exist_TBF_Starting_Time, 1),
M_TYPE (Dynamic_Allocation_t, TBF_Starting_Time, Starting_Frame_Number_t),
@ -1806,6 +1815,7 @@ CSN_DESCR_BEGIN (PUA_EGPRS_00_t)
M_UINT (PUA_EGPRS_00_t, RESEGMENT, 1),
M_UINT (PUA_EGPRS_00_t, EGPRS_WindowSize, 5),
M_NEXT_EXIST (PUA_EGPRS_00_t, Exist_AccessTechnologyType, 1),
M_REC_ARRAY (PUA_EGPRS_00_t, AccessTechnologyType, NrOfAccessTechnologies, 4),
M_UINT (PUA_EGPRS_00_t, ARAC_RETRANSMISSION_REQUEST, 1),
@ -2163,9 +2173,6 @@ CSN_DESCR_BEGIN(TRDynamic_Allocation_t)
M_UINT (TRDynamic_Allocation_t, USF_GRANULARITY, 1),
M_NEXT_EXIST (TRDynamic_Allocation_t, Exist_RLC_DATA_BLOCKS_GRANTED, 1),
M_UINT (TRDynamic_Allocation_t, RLC_DATA_BLOCKS_GRANTED, 8),
M_NEXT_EXIST (TRDynamic_Allocation_t, Exist_TBF_Starting_Time, 1),
M_TYPE (TRDynamic_Allocation_t, TBF_Starting_Time, Starting_Frame_Number_t),
@ -5509,11 +5516,3 @@ void encode_gsm_rlcmac_downlink_data(bitvec * vector, RlcMacDownlinkDataBlock_t
LOGPC(DRLCMACDATA, LOGL_NOTICE, "\n");
}
}
void decode_gsm_ra_cap(bitvec * vector, MS_Radio_Access_capability_t *data)
{
csnStream_t ar;
unsigned readIndex = 0;
csnStreamInit(&ar, 0, 8 * vector->data_len);
/*ret =*/ csnStreamDecoder(&ar, CSNDESCR(MS_Radio_Access_capability_t), vector, readIndex, data);
}

View File

@ -450,7 +450,8 @@ typedef struct
*/
#define EGPRS_ACK_NACK_MAX_BITS 0x0FF /* 255 bits/32 bytes */
#define CRBB_MAX_BITS 0x07F /* 127 bits/16 bytes */
#define URBB_MAX_BITS 0x150 /* 336 bits/42 bytes */
#define URBB_MAX_BITS 0x0A8 /* 168 bits/21 bytes */
#define UNCOMP_MAX_BITS 0x400 /* 1024 bits/128 bytes */
typedef struct
{
@ -470,13 +471,12 @@ typedef struct
typedef struct
{
guint8 UnionType;
EGPRS_AckNack_Desc_t Desc;
} EGPRS_AckNack_t;
typedef struct
{
/* guint8 LENGTH; */
guint8 LENGTH;
EGPRS_AckNack_Desc_t Desc;
} EGPRS_AckNack_w_len_t;
@ -1689,7 +1689,13 @@ typedef struct
gboolean Exist_ExtensionBits;
Extension_Bits_t ExtensionBits;
EGPRS_AckNack_t EGPRS_AckNack;
guint8 UnionType;
union
{
EGPRS_AckNack_t EGPRS_AckNack;
EGPRS_AckNack_w_len_t EGPRS_AckNack_len ;
} u;
} EGPRS_PD_AckNack_t;
/* < Packet Uplink Ack/Nack message content 04.60 sec.11.2.28 > */
@ -1861,9 +1867,6 @@ typedef struct
guint8 Exist_UPLINK_TFI_ASSIGNMENT;
guint8 UPLINK_TFI_ASSIGNMENT;
guint8 Exist_RLC_DATA_BLOCKS_GRANTED;
guint8 RLC_DATA_BLOCKS_GRANTED;
guint8 Exist_TBF_Starting_Time;
Starting_Frame_Number_t TBF_Starting_Time;
@ -2008,6 +2011,7 @@ typedef struct
guint8 RESEGMENT;
guint8 EGPRS_WindowSize;
guint8 Exist_AccessTechnologyType;
guint8 NrOfAccessTechnologies; /* will hold the number of list elements */
guint8 AccessTechnologyType[MAX_ACCESS_TECHOLOGY_TYPES]; /* for max size of array see 24.008/Table 10.5.146 */
@ -2041,9 +2045,9 @@ typedef struct
union
{
PUA_EGPRS_00_t PUA_EGPRS_00;
guint8 PUA_EGPRS_01;
guint8 PUA_EGPRS_10;
guint8 PUA_EGPRS_11;
guint8 PUA_EGPRS_01;//Dual carrier
guint8 PUA_EGPRS_10;//Multi Carrier
guint8 PUA_EGPRS_11;//
} u;
} PUA_EGPRS_t;
@ -2150,7 +2154,7 @@ typedef struct
guint8 PERSISTENCE_LEVEL[4];
PacketDownlinkID_t ID;
gboolean message_escape;
guint8 MAC_MODE;
guint8 RLC_MODE;
guint8 CONTROL_ACK;
@ -4943,7 +4947,7 @@ typedef struct
Packet_Cell_Change_Failure_t Packet_Cell_Change_Failure;
Packet_Control_Acknowledgement_t Packet_Control_Acknowledgement;
Packet_Downlink_Ack_Nack_t Packet_Downlink_Ack_Nack;
EGPRS_PD_AckNack_t Egprs_Packet_Downlink_Ack_Nack;
EGPRS_PD_AckNack_t Egprs_Packet_Downlink_Ack_Nack;
Packet_Uplink_Dummy_Control_Block_t Packet_Uplink_Dummy_Control_Block;
Packet_Measurement_Report_t Packet_Measurement_Report;
Packet_Resource_Request_t Packet_Resource_Request;
@ -5136,5 +5140,4 @@ typedef struct
void encode_gsm_rlcmac_uplink(bitvec * vector, RlcMacUplink_t * data);
void decode_gsm_rlcmac_uplink_data(bitvec * vector, RlcMacUplinkDataBlock_t * data);
void encode_gsm_rlcmac_downlink_data(bitvec * vector, RlcMacDownlinkDataBlock_t * data);
void decode_gsm_ra_cap(bitvec * vector, MS_Radio_Access_capability_t * data);
#endif /* __PACKET_GSM_RLCMAC_H__ */

View File

@ -49,6 +49,8 @@ struct gprs_llc {
void consume(size_t len);
void consume(uint8_t *data, size_t len);
uint16_t get_mindex() const;
uint16_t chunk_size() const;
uint16_t remaining_space() const;
uint16_t frame_length() const;
@ -113,6 +115,12 @@ inline void gprs_llc::consume(size_t len)
m_index += len;
}
inline uint16_t gprs_llc::get_mindex() const
{
return m_index ;
}
inline void gprs_llc::consume(uint8_t *data, size_t len)
{
/* copy and increment index */

View File

@ -30,8 +30,6 @@ extern "C" {
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/gsmtap.h>
}
#include <gprs_rlcmac.h>
@ -44,7 +42,7 @@ extern "C" {
// FIXME: move this, when changed from c++ to c.
extern "C" {
void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap);
void *l1if_open_pdch(void *priv, uint32_t hlayer1);
int l1if_connect_pdch(void *obj, uint8_t ts);
int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len);
@ -126,18 +124,15 @@ static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi,
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr)
{
#ifdef ENABLE_SYSMODSP
struct gprs_rlcmac_bts *bts = bts_main_data();
#ifdef ENABLE_SYSMODSP
if (bts->trx[trx].fl1h) {
if (bts->trx[trx].fl1h)
l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr,
msg->data, msg->len);
msgb_free(msg);
return;
}
else
#endif
gsmtap_send(bts->gsmtap, arfcn, ts, GSMTAP_CHANNEL_PACCH, 0, fn, 0, 0, msg->data, msg->len);
pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr,
pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr,
msg->data, msg->len);
msgb_free(msg);
}
@ -145,18 +140,15 @@ void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr)
{
#ifdef ENABLE_SYSMODSP
struct gprs_rlcmac_bts *bts = bts_main_data();
#ifdef ENABLE_SYSMODSP
if (bts->trx[trx].fl1h) {
if (bts->trx[trx].fl1h)
l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr,
msg->data, msg->len);
msgb_free(msg);
return;
}
else
#endif
gsmtap_send(bts->gsmtap, arfcn, ts, GSMTAP_CHANNEL_PACCH, 0, fn, 0, 0, msg->data, msg->len);
pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr,
pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr,
msg->data, msg->len);
msgb_free(msg);
}
@ -208,9 +200,9 @@ extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *dat
return pdch->rcv_block(data, len, fn, meas);
}
static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind, struct gsmtap_inst *gsmtap)
static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
{
int rc;
int rc = 0;
pcu_l1_meas meas;
meas.set_rssi(data_ind->rssi);
@ -219,13 +211,6 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind, struct gsmtap_inst
data_ind->arfcn, data_ind->block_nr,
osmo_hexdump(data_ind->data, data_ind->len));
rc = gsmtap_send(gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr,
GSMTAP_CHANNEL_PACCH, 0, data_ind->fn, 0, 0, data_ind->data, data_ind->len);
if (rc < 0)
LOGP(DL1IF, LOGL_ERROR, "Sending RX data via GSMTAP failed: %d\n", rc);
rc = 0;
switch (data_ind->sapi) {
case PCU_IF_SAPI_PDTCH:
rc = pcu_rx_data_ind_pdtch(data_ind->trx_nr, data_ind->ts_nr,
@ -451,8 +436,7 @@ bssgp_failed:
if (!bts->trx[trx].fl1h)
bts->trx[trx].fl1h = l1if_open_pdch(
(void *)trx,
info_ind->trx[trx].hlayer1,
bts->gsmtap);
info_ind->trx[trx].hlayer1);
if (!bts->trx[trx].fl1h) {
LOGP(DL1IF, LOGL_FATAL, "Failed to open direct "
"DSP access for PDCH.\n");
@ -523,11 +507,10 @@ static int pcu_rx_pag_req(struct gsm_pcu_if_pag_req *pag_req)
int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
{
int rc = 0;
struct gprs_rlcmac_bts *bts = bts_main_data();
switch (msg_type) {
case PCU_IF_MSG_DATA_IND:
rc = pcu_rx_data_ind(&pcu_prim->u.data_ind, bts->gsmtap);
rc = pcu_rx_data_ind(&pcu_prim->u.data_ind);
break;
case PCU_IF_MSG_DATA_CNF:
rc = pcu_rx_data_cnf(&pcu_prim->u.data_cnf);

View File

@ -62,6 +62,12 @@ struct pcu_l1_meas {
unsigned have_ms_c_value:1;
unsigned have_ms_sign_var:1;
unsigned have_ms_i_level:1;
unsigned have_mean_bep_gmsk:1;
unsigned have_cv_bep_gmsk:1;
unsigned have_mean_bep_8psk:1;
unsigned have_cv_bep_8psk:1;
unsigned have_bep_mean_gmsk:1;
unsigned have_bep_mean_8psk:1;
int8_t rssi; /* RSSI in dBm */
uint8_t ber; /* Bit error rate in % */
@ -70,6 +76,13 @@ struct pcu_l1_meas {
int16_t ms_rx_qual; /* MS RXQUAL value in % */
int16_t ms_c_value; /* C value in dB */
int16_t ms_sign_var; /* SIGN_VAR in dB */
int8_t ms_mean_bep_gmsk; /* MEAN_BEP_GMSK */
int8_t ms_cv_bep_gmsk; /* CV_BEP_GMSK */
int8_t ms_mean_bep_8psk; /* MEAN_BEP_GMSK */
int8_t ms_cv_bep_8psk; /* CV_BEP_GMSK */
int8_t ms_bep_mean_gmsk; /* MEAN_BEP_GMSK BEP measurements */
int8_t ms_bep_mean_8psk; /* MEAN_BEP_8PSK Measurements*/
struct pcu_l1_meas_ts ts[8];
@ -92,6 +105,20 @@ struct pcu_l1_meas {
pcu_l1_meas& set_ms_i_level(size_t idx, int16_t v) {
ts[idx].set_ms_i_level(v); have_ms_i_level = 1; return *this;
}
pcu_l1_meas& set_mean_cv_bep_gmsk(int8_t v, int8_t w) {
ms_mean_bep_gmsk = v; have_mean_bep_gmsk = 1; return *this;
ms_cv_bep_gmsk = w; have_cv_bep_gmsk = 1; return *this;
}
pcu_l1_meas& set_mean_cv_bep_8psk(int8_t v, int8_t w) {
ms_mean_bep_8psk = v; have_mean_bep_8psk = 1; return *this;
ms_cv_bep_8psk = w; have_cv_bep_8psk = 1; return *this;
}
pcu_l1_meas& set_bep_mean_gmsk(int8_t v) {
ms_bep_mean_gmsk = v; have_bep_mean_gmsk = 1; return *this;
}
pcu_l1_meas& set_bep_mean_8psk(int8_t v) {
ms_bep_mean_8psk = v; have_bep_mean_8psk = 1; return *this;
}
pcu_l1_meas() :
have_rssi(0),
have_ber(0),
@ -100,7 +127,13 @@ struct pcu_l1_meas {
have_ms_rx_qual(0),
have_ms_c_value(0),
have_ms_sign_var(0),
have_ms_i_level(0)
have_ms_i_level(0),
have_mean_bep_gmsk(0),
have_cv_bep_gmsk(0),
have_mean_bep_8psk(0),
have_cv_bep_8psk(0),
have_bep_mean_gmsk(0),
have_bep_mean_8psk(0)
{}
#endif
};

View File

@ -33,8 +33,6 @@ extern "C" {
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/gsmtap_util.h>
}
extern struct gprs_nsvc *nsvc;
@ -46,7 +44,6 @@ void *tall_pcu_ctx;
extern void *bv_tall_ctx;
static int quit = 0;
static int rt_prio = -1;
static char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead
static void print_help()
{
@ -58,10 +55,8 @@ static void print_help()
"provided by BTS\n"
" -n --mnc MNC use given MNC instead of value "
"provided by BTS\n"
" -V --version print version\n"
" -r --realtime PRIO Use SCHED_RR with the specified "
"priority\n"
" -i --gsmtap-ip The destination IP used for GSMTAP.\n"
);
}
@ -78,11 +73,10 @@ static void handle_options(int argc, char **argv)
{ "version", 0, 0, 'V' },
{ "realtime", 1, 0, 'r' },
{ "exit", 0, 0, 'e' },
{ "gsmtap-ip", 1, 0, 'i' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "hc:m:n:Vr:e:i:",
c = getopt_long(argc, argv, "hc:m:n:Vr:e",
long_options, &option_idx);
if (c == -1)
break;
@ -107,9 +101,6 @@ static void handle_options(int argc, char **argv)
print_version(1);
exit(0);
break;
case 'i':
gsmtap_addr = optarg;
break;
case 'r':
rt_prio = atoi(optarg);
break;
@ -172,7 +163,6 @@ int main(int argc, char *argv[])
bts = bts_main_data();
bts->fc_interval = 1;
bts->initial_cs_dl = bts->initial_cs_ul = 1;
bts->initial_mcs_dl = bts->initial_mcs_ul = 1;
bts->cs1 = 1;
bts->t3142 = 20;
bts->t3169 = 5;
@ -189,8 +179,10 @@ int main(int argc, char *argv[])
bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
bts->max_cs_ul = 4;
bts->max_cs_dl = 4;
bts->max_mcs_ul = 4;
bts->max_mcs_dl = 4;
bts->initial_mcs_dl = 1;
bts->initial_mcs_ul = 1;
bts->max_mcs_ul = 9;
bts->max_mcs_dl = 9;
/* CS-1 to CS-4 */
bts->cs_lqual_ranges[0].low = -256;
bts->cs_lqual_ranges[0].high = 6;
@ -202,10 +194,6 @@ int main(int argc, char *argv[])
bts->cs_lqual_ranges[3].high = 256;
bts->cs_downgrade_threshold = 200;
/* TODO: increase them when CRBB decoding is implemented */
bts->ws_base = 64;
bts->ws_pdch = 0;
bts->llc_codel_interval_msec = LLC_CODEL_USE_DEFAULT;
bts->dl_tbf_idle_msec = 2000;
bts->llc_idle_ack_csec = 10;
@ -227,13 +215,6 @@ int main(int argc, char *argv[])
exit(0);
}
bts->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1);
if (bts->gsmtap)
gsmtap_source_add_sink(bts->gsmtap);
else
fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr);
rc = vty_read_config_file(config_file, NULL);
if (rc < 0 && config_given) {
fprintf(stderr, "Failed to parse the config file: '%s'\n",

View File

@ -24,19 +24,3 @@ inline void csecs_to_timeval(unsigned csecs, struct timeval *tv) {
tv->tv_sec = csecs / 100;
tv->tv_usec = (csecs % 100) * 10000;
}
template <typename T>
inline unsigned int pcu_bitcount(T x)
{
unsigned int count = 0;
for (count = 0; x; count += 1)
x &= x - 1;
return count;
}
template <typename T>
inline T pcu_lsb(T x)
{
return x & -x;
}

View File

@ -55,7 +55,9 @@ static int config_write_pcu(struct vty *vty)
vty_out(vty, "pcu%s", VTY_NEWLINE);
if (bts->egprs_enabled)
vty_out(vty, " egprs only%s", VTY_NEWLINE);
vty_out(vty, " egprs%s", VTY_NEWLINE);
else
vty_out(vty, " no egprs%s", VTY_NEWLINE);
vty_out(vty, " flow-control-interval %d%s", bts->fc_interval,
VTY_NEWLINE);
@ -85,7 +87,23 @@ static int config_write_pcu(struct vty *vty)
VTY_NEWLINE);
else
vty_out(vty, " cs max %d %d%s", bts->max_cs_dl,
bts->max_cs_ul, VTY_NEWLINE);
bts->max_cs_ul, VTY_NEWLINE);
}
if (bts->force_mcs) {
if (bts->initial_mcs_ul == bts->initial_mcs_dl)
vty_out(vty, " mcs %d%s", bts->initial_mcs_dl,
VTY_NEWLINE);
else
vty_out(vty, " mcs %d %d%s", bts->initial_mcs_dl,
bts->initial_mcs_ul, VTY_NEWLINE);
}
if (bts->max_mcs_dl && bts->max_mcs_ul) {
if (bts->max_mcs_ul == bts->max_mcs_dl)
vty_out(vty, " mcs max %d%s", bts->max_mcs_dl,
VTY_NEWLINE);
else
vty_out(vty, " mcs max %d %d%s", bts->max_mcs_dl,
bts->max_mcs_ul, VTY_NEWLINE);
}
if (bts->cs_adj_enabled)
vty_out(vty, " cs threshold %d %d%s",
@ -109,26 +127,6 @@ static int config_write_pcu(struct vty *vty)
bts->cs_lqual_ranges[3].low,
VTY_NEWLINE);
if (bts->initial_mcs_dl != 1 && bts->initial_mcs_ul != 1) {
if (bts->initial_mcs_ul == bts->initial_mcs_dl)
vty_out(vty, " mcs %d%s", bts->initial_mcs_dl,
VTY_NEWLINE);
else
vty_out(vty, " mcs %d %d%s", bts->initial_mcs_dl,
bts->initial_mcs_ul, VTY_NEWLINE);
}
if (bts->max_mcs_dl && bts->max_mcs_ul) {
if (bts->max_mcs_ul == bts->max_mcs_dl)
vty_out(vty, " mcs max %d%s", bts->max_mcs_dl,
VTY_NEWLINE);
else
vty_out(vty, " mcs max %d %d%s", bts->max_mcs_dl,
bts->max_mcs_ul, VTY_NEWLINE);
}
vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch,
VTY_NEWLINE);
if (bts->force_llc_lifetime == 0xffff)
vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE);
else if (bts->force_llc_lifetime)
@ -180,18 +178,13 @@ DEFUN(cfg_pcu,
DEFUN(cfg_pcu_egprs,
cfg_pcu_egprs_cmd,
"egprs only",
EGPRS_STR "Use EGPRS and disable plain GPRS\n")
"egprs",
EGPRS_STR)
{
struct gprs_rlcmac_bts *bts = bts_main_data();
bts->egprs_enabled = 1;
vty_out(vty, "%%Note that EGPRS support is in an experimental state "
"and the PCU will currently fail to use a TBF if the MS is capable "
"to do EGPRS. You may want to disable this feature by entering "
"the \"no egprs\" command. "
"Do not use this in production!%s", VTY_NEWLINE);
vty_out(vty, "%%EGPRS is enabled %s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@ -379,12 +372,11 @@ DEFUN(cfg_pcu_no_cs,
return CMD_SUCCESS;
}
#define CS_MAX_STR "Set maximum values for adaptive CS selection (overrides BTS config)\n"
DEFUN(cfg_pcu_cs_max,
cfg_pcu_cs_max_cmd,
"cs max <1-4> [<1-4>]",
CS_STR
CS_MAX_STR
"Set maximum values for adaptive CS selection (overrides BTS config)\n"
"Maximum CS value to be used\n"
"Use a different maximum CS value for the uplink")
{
@ -403,7 +395,8 @@ DEFUN(cfg_pcu_cs_max,
DEFUN(cfg_pcu_no_cs_max,
cfg_pcu_no_cs_max_cmd,
"no cs max",
NO_STR CS_STR CS_MAX_STR)
NO_STR CS_STR
"Set maximum values for adaptive CS selection (overrides BTS config)\n")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
@ -413,23 +406,24 @@ DEFUN(cfg_pcu_no_cs_max,
return CMD_SUCCESS;
}
#define MCS_STR "Modulation and Coding Scheme configuration (EGPRS)\n"
#define MCS_STR "EGPRS Coding Scheme configuration\n"
DEFUN(cfg_pcu_mcs,
cfg_pcu_mcs_cmd,
"mcs <1-9> [<1-9>]",
MCS_STR
"Initial MCS value to be used (default 1)\n"
"Initial MCS value to be used (overrides BTS config)\n"
"Use a different initial MCS value for the uplink")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
uint8_t cs = atoi(argv[0]);
uint8_t mcs = atoi(argv[0]);
bts->initial_mcs_dl = cs;
bts->force_mcs = 1;
bts->initial_mcs_dl = mcs;
if (argc > 1)
bts->initial_mcs_ul = atoi(argv[1]);
else
bts->initial_mcs_ul = cs;
bts->initial_mcs_ul = mcs;
return CMD_SUCCESS;
}
@ -441,8 +435,7 @@ DEFUN(cfg_pcu_no_mcs,
{
struct gprs_rlcmac_bts *bts = bts_main_data();
bts->initial_mcs_dl = 1;
bts->initial_mcs_ul = 1;
bts->force_mcs = 0;
return CMD_SUCCESS;
}
@ -451,7 +444,7 @@ DEFUN(cfg_pcu_mcs_max,
cfg_pcu_mcs_max_cmd,
"mcs max <1-9> [<1-9>]",
MCS_STR
CS_MAX_STR
"Set maximum values for adaptive MCS selection (overrides BTS config)\n"
"Maximum MCS value to be used\n"
"Use a different maximum MCS value for the uplink")
{
@ -470,7 +463,8 @@ DEFUN(cfg_pcu_mcs_max,
DEFUN(cfg_pcu_no_mcs_max,
cfg_pcu_no_mcs_max_cmd,
"no mcs max",
NO_STR MCS_STR CS_MAX_STR)
NO_STR MCS_STR
"Set maximum values for adaptive MCS selection (overrides BTS config)\n")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
@ -480,26 +474,6 @@ DEFUN(cfg_pcu_no_mcs_max,
return CMD_SUCCESS;
}
DEFUN(cfg_pcu_window_size,
cfg_pcu_window_size_cmd,
"window-size <0-1024> [<0-256>]",
"Window size configuration (b + N_PDCH * f)\n"
"Base value (b)\n"
"Factor for number of PDCH (f)")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
uint16_t b = atoi(argv[0]);
bts->ws_base = b;
if (argc > 1) {
uint16_t f = atoi(argv[1]);
bts->ws_pdch = f;
}
return CMD_SUCCESS;
}
#define QUEUE_STR "Packet queue options\n"
#define LIFETIME_STR "Set lifetime limit of LLC frame in centi-seconds " \
"(overrides the value given by SGSN)\n"
@ -880,7 +854,19 @@ DEFUN(show_tbf,
SHOW_STR "information about TBFs\n" "All TBFs\n")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
return pcu_vty_show_tbf_all(vty, bts);
struct llist_head *tbf;
vty_out(vty, "UL TBFs%s", VTY_NEWLINE);
llist_for_each(tbf, &bts->ul_tbfs) {
tbf_print_vty_info(vty, tbf);
}
vty_out(vty, "%sDL TBFs%s", VTY_NEWLINE, VTY_NEWLINE);
llist_for_each(tbf, &bts->dl_tbfs) {
tbf_print_vty_info(vty, tbf);
}
return CMD_SUCCESS;
}
DEFUN(show_ms_all,
@ -948,16 +934,15 @@ int pcu_vty_init(const struct log_info *cat)
install_element(PCU_NODE, &cfg_pcu_no_cs_cmd);
install_element(PCU_NODE, &cfg_pcu_cs_max_cmd);
install_element(PCU_NODE, &cfg_pcu_no_cs_max_cmd);
install_element(PCU_NODE, &cfg_pcu_mcs_cmd);
install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd);
install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd);
install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd);
install_element(PCU_NODE, &cfg_pcu_cs_err_limits_cmd);
install_element(PCU_NODE, &cfg_pcu_no_cs_err_limits_cmd);
install_element(PCU_NODE, &cfg_pcu_cs_downgrade_thrsh_cmd);
install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd);
install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd);
install_element(PCU_NODE, &cfg_pcu_mcs_cmd);
install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd);
install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd);
install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd);
install_element(PCU_NODE, &cfg_pcu_window_size_cmd);
install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd);
install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd);
install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);

View File

@ -39,61 +39,6 @@ int pcu_vty_config_write_pcu_ext(struct vty *vty)
return CMD_SUCCESS;
}
static void tbf_print_vty_info(struct vty *vty, gprs_rlcmac_tbf *tbf)
{
gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf);
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf);
vty_out(vty, "TBF: TFI=%d TLLI=0x%08x (%s) DIR=%s IMSI=%s%s", tbf->tfi(),
tbf->tlli(), tbf->is_tlli_valid() ? "valid" : "invalid",
tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
tbf->imsi(), VTY_NEWLINE);
vty_out(vty, " created=%lu state=%08x 1st_TS=%d 1st_cTS=%d ctrl_TS=%d "
"MS_CLASS=%d/%d%s",
tbf->created_ts(), tbf->state_flags, tbf->first_ts,
tbf->first_common_ts, tbf->control_ts,
tbf->ms_class(),
tbf->ms() ? tbf->ms()->egprs_ms_class() : -1,
VTY_NEWLINE);
vty_out(vty, " TS_alloc=");
for (int i = 0; i < 8; i++) {
bool is_ctrl = tbf->is_control_ts(i);
if (tbf->pdch[i])
vty_out(vty, "%d%s ", i, is_ctrl ? "!" : "");
}
vty_out(vty, " CS=%s WS=%d",
tbf->current_cs().name(), tbf->window()->ws());
if (ul_tbf) {
gprs_rlc_ul_window *win = &ul_tbf->m_window;
vty_out(vty, " V(Q)=%d V(R)=%d",
win->v_q(), win->v_r());
}
if (dl_tbf) {
gprs_rlc_dl_window *win = &dl_tbf->m_window;
vty_out(vty, " V(A)=%d V(S)=%d nBSN=%d%s",
win->v_a(), win->v_s(), win->resend_needed(),
win->window_stalled() ? " STALLED" : "");
}
vty_out(vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
}
int pcu_vty_show_tbf_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
{
BTS *bts = bts_data->bts;
LListHead<gprs_rlcmac_tbf> *ms_iter;
vty_out(vty, "UL TBFs%s", VTY_NEWLINE);
llist_for_each(ms_iter, &bts->ul_tbfs())
tbf_print_vty_info(vty, ms_iter->entry());
vty_out(vty, "%sDL TBFs%s", VTY_NEWLINE, VTY_NEWLINE);
llist_for_each(ms_iter, &bts->dl_tbfs())
tbf_print_vty_info(vty, ms_iter->entry());
return CMD_SUCCESS;
}
int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
{
BTS *bts = bts_data->bts;
@ -102,11 +47,10 @@ int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
llist_for_each(ms_iter, &bts->ms_store().ms_list()) {
GprsMs *ms = ms_iter->entry();
vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%s, CS-DL=%s, LLC=%d, "
vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%d, CS-DL=%d, LLC=%d, "
"IMSI=%s%s",
ms->tlli(),
ms->ta(), ms->current_cs_ul().name(),
ms->current_cs_dl().name(),
ms->ta(), ms->current_cs_ul(), ms->current_cs_dl(),
ms->llc_queue()->size(),
ms->imsi(),
VTY_NEWLINE);
@ -118,24 +62,15 @@ static int show_ms(struct vty *vty, GprsMs *ms)
{
unsigned i;
LListHead<gprs_rlcmac_tbf> *i_tbf;
uint8_t slots;
vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE);
vty_out(vty, " Timing advance (TA): %d%s", ms->ta(), VTY_NEWLINE);
vty_out(vty, " Coding scheme uplink: %s%s", ms->current_cs_ul().name(),
vty_out(vty, " Coding scheme uplink: CS-%d%s", ms->current_cs_ul(),
VTY_NEWLINE);
vty_out(vty, " Coding scheme downlink: %s%s", ms->current_cs_dl().name(),
vty_out(vty, " Coding scheme downlink: CS-%d%s", ms->current_cs_dl(),
VTY_NEWLINE);
vty_out(vty, " Mode: %s%s",
GprsCodingScheme::modeName(ms->mode()), VTY_NEWLINE);
vty_out(vty, " MS class: %d%s", ms->ms_class(), VTY_NEWLINE);
vty_out(vty, " EGPRS MS class: %d%s", ms->egprs_ms_class(), VTY_NEWLINE);
vty_out(vty, " PACCH: ");
slots = ms->current_pacch_slots();
for (int i = 0; i < 8; i++)
if (slots & (1 << i))
vty_out(vty, "%d ", i);
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " LLC queue length: %d%s", ms->llc_queue()->size(),
VTY_NEWLINE);
vty_out(vty, " LLC queue octets: %d%s", ms->llc_queue()->octets(),

View File

@ -28,7 +28,6 @@ struct vty;
struct gprs_rlcmac_bts;
int pcu_vty_config_write_pcu_ext(struct vty *vty);
int pcu_vty_show_tbf_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data);
int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data);
int pcu_vty_show_ms_by_tlli(struct vty *vty, struct gprs_rlcmac_bts *bts_data,
uint32_t tlli);

View File

@ -30,14 +30,14 @@ PollController::PollController(BTS& bts)
void PollController::expireTimedout(int frame_number, unsigned max_delay)
{
struct gprs_rlcmac_bts *bts = m_bts.bts_data();
struct gprs_rlcmac_dl_tbf *dl_tbf;
struct gprs_rlcmac_ul_tbf *ul_tbf;
struct gprs_rlcmac_sba *sba, *sba2;
LListHead<gprs_rlcmac_tbf> *pos;
struct llist_pods *lpods;
uint32_t elapsed;
llist_for_each(pos, &m_bts.ul_tbfs()) {
ul_tbf = as_ul_tbf(pos->entry());
llist_pods_for_each_entry(ul_tbf, &bts->ul_tbfs, list, lpods) {
if (ul_tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
elapsed = (frame_number + 2715648 - ul_tbf->poll_fn)
% 2715648;
@ -45,8 +45,7 @@ void PollController::expireTimedout(int frame_number, unsigned max_delay)
ul_tbf->poll_timeout();
}
}
llist_for_each(pos, &m_bts.dl_tbfs()) {
dl_tbf = as_dl_tbf(pos->entry());
llist_pods_for_each_entry(dl_tbf, &bts->dl_tbfs, list, lpods) {
if (dl_tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
elapsed = (frame_number + 2715648 - dl_tbf->poll_fn)
% 2715648;

View File

@ -20,26 +20,313 @@
#include "bts.h"
#include "gprs_debug.h"
#include <errno.h>
extern "C" {
#include <osmocom/core/utils.h>
}
const uint8_t* one_run_len_code_list[MAX_CDWDTBL_LEN] = {
(uint8_t*)"00110101", (uint8_t*)"000111", (uint8_t*)"0111", (uint8_t*)"1000",
(uint8_t*) "1011", (uint8_t*)"1100", (uint8_t*)"1110", (uint8_t*)"1111",
(uint8_t*)"10011", (uint8_t*)"10100", (uint8_t*)"00111", (uint8_t*)"01000",
(uint8_t*)"001000", (uint8_t*)"000011", (uint8_t*)"110100", (uint8_t*)"110101",
(uint8_t*)"101010", (uint8_t*)"101011", (uint8_t*)"0100111", (uint8_t*)"0001100",
(uint8_t*)"0001000", (uint8_t*)"0010111", (uint8_t*)"0000011", (uint8_t*)"0000100",
(uint8_t*)"0101000", (uint8_t*)"0101011", (uint8_t*)"0010011", (uint8_t*)"0100100",
(uint8_t*)"0011000", (uint8_t*)"00000010", (uint8_t*)"00000011", (uint8_t*)"00011010",
(uint8_t*)"00011011", (uint8_t*)"00010010", (uint8_t*)"00010011", (uint8_t*)"00010100",
(uint8_t*)"00010101", (uint8_t*)"00010110", (uint8_t*)"00010111", (uint8_t*)"00101000",
(uint8_t*)"00101001", (uint8_t*)"00101010", (uint8_t*)"00101011", (uint8_t*)"00101100",
(uint8_t*)"00101101", (uint8_t*)"00000100", (uint8_t*)"00000101", (uint8_t*)"00001010",
(uint8_t*)"00001011", (uint8_t*)"01010010", (uint8_t*)"01010011", (uint8_t*)"01010100",
(uint8_t*)"01010101", (uint8_t*)"00100100", (uint8_t*)"00100101", (uint8_t*)"01011000",
(uint8_t*)"01011001", (uint8_t*)"01011010", (uint8_t*)"01011011", (uint8_t*)"01001010",
(uint8_t*)"01001011", (uint8_t*)"00110010", (uint8_t*)"00110011", (uint8_t*)"00110100",
(uint8_t*)"11011", (uint8_t*)"10010", (uint8_t*)"010111", (uint8_t*)"0110111",
(uint8_t*)"00110110", (uint8_t*)"00110111", (uint8_t*)"01100100", (uint8_t*)"01100101",
(uint8_t*)"01101000", (uint8_t*)"01100111", (uint8_t*)"011001100",(uint8_t*)"011001101",
(uint8_t*)"011010010", (uint8_t*)"011010011",(uint8_t*)"011010100"
};
const uint8_t* zero_run_len_code_list[MAX_CDWDTBL_LEN] = {
(uint8_t*)"0000110111", (uint8_t*)"10", (uint8_t*)"11", (uint8_t*)"010",
(uint8_t*)"011", (uint8_t*)"0011", (uint8_t*)"0010", (uint8_t*)"00011",
(uint8_t*)"000101", (uint8_t*)"000100", (uint8_t*)"0000100", (uint8_t*)"0000101",
(uint8_t*)"0000111", (uint8_t*)"00000100", (uint8_t*)"00000111", (uint8_t*)"000011000",
(uint8_t*)"0000010111", (uint8_t*)"0000011000", (uint8_t*)"0000001000", (uint8_t*)"00001100111",
(uint8_t*)"00001101000", (uint8_t*)"00001101100", (uint8_t*)"00000110111", (uint8_t*)"00000101000",
(uint8_t*)"00000010111", (uint8_t*)"00000011000", (uint8_t*)"000011001010",(uint8_t*)"000011001011",
(uint8_t*)"000011001100",(uint8_t*)"000011001101",(uint8_t*)"000001101000",(uint8_t*)"000001101001",
(uint8_t*)"000001101010",(uint8_t*)"000001101011",(uint8_t*)"000011010010",(uint8_t*)"000011010011",
(uint8_t*)"000011010100",(uint8_t*)"000011010101",(uint8_t*)"000011010110",(uint8_t*)"000011010111",
(uint8_t*)"000001101100",(uint8_t*)"000001101101",(uint8_t*)"000011011010",(uint8_t*)"000011011011",
(uint8_t*)"000001010100",(uint8_t*)"000001010101",(uint8_t*)"000001010110",(uint8_t*)"000001010111",
(uint8_t*)"000001100100",(uint8_t*)"000001100101",(uint8_t*)"000001010010",(uint8_t*)"000001010011",
(uint8_t*)"000000100100",(uint8_t*)"000000110111",(uint8_t*)"000000111000",(uint8_t*)"000000100111",
(uint8_t*)"000000101000",(uint8_t*)"000001011000",(uint8_t*)"000001011001",(uint8_t*)"000000101011",
(uint8_t*)"000000101100",(uint8_t*)"000001011010",(uint8_t*)"000001100110",(uint8_t*)"000001100111",
(uint8_t*)"0000001111", (uint8_t*)"000011001000",(uint8_t*)"000011001001",(uint8_t*)"000001011011",
(uint8_t*)"000000110011",(uint8_t*)"000000110100",(uint8_t*)"000000110101",(uint8_t*)"0000001101100",
(uint8_t*)"0000001101101",(uint8_t*)"0000001001010", (uint8_t*)"0000001001011",
(uint8_t*)"0000001001100", (uint8_t*)"0000001001101", (uint8_t*)"0000001110010",
(uint8_t*)"0000001110011"
};
/*
*
*
* Desc: This function rebuilds a header from Type II to Type III
* the source is header2 and the new header is put
* into the enc structure
*
*/
int gprs_rlc_data::egprs_build_header_type3_from_type2
(
uint8_t *enc, /* header to unpack */
GprsCodingScheme *reseg_mcs, /* resegmentation MCS */
uint8_t ps,
uint8_t spb /* SPB field */
)
{
uint8_t byte;
/* Type 3 and type 2 are differed with only last byte to include spb offset */
memcpy(enc, this->hdr_ptr[0], EGPRS_TYPE3_HDR_SIZE);
struct gprs_rlc_dl_header_egprs_3 *header_type3 = (struct gprs_rlc_dl_header_egprs_3 *)enc;
byte = reseg_mcs->get_cps(ps, this->mcs8_retx);
header_type3->cps = byte;
header_type3->spb = spb;
return(1);
} /* end of egprs_build_header_type3_from_type2*/
/*
*
* Fun: egprs_build_header_type3_from_type1
*
* Desc: This function rebuilds a header from Type I to Type III
* the source is header1 and the new header is put
* into the enc structure
* This function is needed for resegmentation from MCS7/8/9 to
* MCS 2/3
*
* Ret: 1 if successful or,
* -1, otherwise
*
* Notes: None
*
* File: gz_egprs1.c
*
*/
int gprs_rlc_data::egprs_build_header_type3_from_type1
(
uint8_t *enc, /* header to unpack */
GprsCodingScheme *reseg_mcs, /* resegmentation MCS */
uint8_t ps,
uint8_t spb/* SPB field */
)
{
uint8_t byte;
struct gprs_rlc_dl_header_egprs_3 *header_type3 = (struct gprs_rlc_dl_header_egprs_3 *) enc;
memcpy(enc, this->hdr_ptr[0], EGPRS_TYPE3_HDR_SIZE);
/* depending on wether if it is the first or the second
block of the original MCS-7/8/9 block we choose the BSN
*/
header_type3->bsn_a = (this->bsn & 0x3);
header_type3->bsn_b = this->bsn >> 2 ;
header_type3->bsn_c = this->bsn & 0x0400 ;
byte = reseg_mcs->get_cps(ps, this->mcs8_retx);
header_type3->cps = byte;
header_type3->spb = spb;
return(1);
} /* end of egprs_build_header_type3_from_type1 */
/*
*
* Desc: This function rebuilds a header from Type I to Type II
* the source is header1 and the new header is put
* into the enc structure
* In this case 2 headers are returned since the BSN for
* each resegmented block is different
*/
int gprs_rlc_data::egprs_build_header_type2_from_type1
(
uint8_t *enc, /* header to unpack */
GprsCodingScheme *reseg_mcs, /* resegmentation MCS */
uint8_t ps
)
{
uint8_t byte;
struct gprs_rlc_dl_header_egprs_2 *header_type2 = (struct gprs_rlc_dl_header_egprs_2 *) enc;
memcpy(enc, this->hdr_ptr[0], EGPRS_TYPE2_HDR_SIZE);
/* depending on wether if it is the first or the second
block of the original MCS-7/8/9 block we choose the BSN
*/
header_type2->bsn_a = (this->bsn & 0x3);
header_type2->bsn_b = this->bsn >> 2 ;
header_type2->bsn_c = this->bsn & 0x0400 ;
byte = reseg_mcs->get_cps(ps, this->mcs8_retx);
header_type2->cps = byte;
return(1);
} /* end of egprs_build_header_type2_from_type1*/
void gprs_rlc_data::update_cps( GprsCodingScheme *cs, const uint8_t next_ps)
{
uint8_t cps = cs->get_cps(next_ps, false);
if((*cs == GprsCodingScheme::MCS1 ||
*cs == GprsCodingScheme::MCS2 ||
*cs == GprsCodingScheme::MCS3 ||
*cs == GprsCodingScheme::MCS4)){
this->last_ps = next_ps;
this->hdr_ptr[0][3] |= cps << 1 ;
}
else if( (*cs == GprsCodingScheme::MCS5) ||
(*cs == GprsCodingScheme::MCS6)){
this->last_ps = next_ps;
this->hdr_ptr[0][3] |= cps << 1 ;
}else if((*cs == GprsCodingScheme::MCS7) ||
(*cs == GprsCodingScheme::MCS8) ||
( *cs == GprsCodingScheme::MCS9)){
this->last_ps = next_ps;
this->hdr_ptr[0][4] = cps<< 3 ;
}
else{
OSMO_ASSERT(*cs >= GprsCodingScheme::MCS9);
}
}
void gprs_rlc_data::fill_hdr_type3( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi,const uint16_t cps)
{
/*Refer Header type from 10.3a.3.3 of 46.060*/
struct gprs_rlc_dl_header_egprs_3 *ptr = (struct gprs_rlc_dl_header_egprs_3 *)hdr_ptr[0];
ptr->usf = GPRS_RLCMAC_DATA_BLOCK;
ptr->tfi_a = tfi & 0x01;
ptr->tfi_b = tfi >> 1;
ptr->bsn_a = bsn & 0x3;
ptr->bsn_b = bsn >> 2 ;
ptr->bsn_c = bsn & 0x0400 ;
/* Need to check with cs */
ptr->cps = cps;
ptr->spb = 0;
LOGP(DRLCMACDL, LOGL_DEBUG, "usf=%d\n tfi_a=%d\n tfi_b=%d\n bsna %d \n bsnb %d\n bsnc %d\n cps %d\n spb %d\n",
ptr->usf, ptr->tfi_a, ptr->tfi_b, ptr->bsn_a,ptr->bsn_b,ptr->bsn_c,ptr->cps,ptr->spb);
this->cs = *cs;
this->hdr_size[0] = EGPRS_TYPE3_HDR_SIZE;
}
void gprs_rlc_data::fill_hdr_type2( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi,const uint16_t cps )
{
/*Refer Header type from 10.3a.3.2 of 46.060*/
struct gprs_rlc_dl_header_egprs_2 *ptr = (struct gprs_rlc_dl_header_egprs_2 *)hdr_ptr[0];
ptr->usf = GPRS_RLCMAC_DATA_BLOCK;
ptr->tfi_a = tfi & 0x01;
ptr->tfi_b = tfi >> 1;
ptr->bsn_a = bsn & 0x3;
ptr->bsn_b = bsn >> 2 ;
ptr->bsn_c = bsn & 0x0400 ;
/* Need to check with cs */
ptr->cps = cps;
LOGP(DRLCMACDL, LOGL_DEBUG, "usf=%d\n tfi_a=%d\n tfi_b=%d\n bsna %d \n bsnb %d\n bsnc %d\n cps %d\n",
ptr->usf, ptr->tfi_a, ptr->tfi_b, ptr->bsn_a,ptr->bsn_b,ptr->bsn_c,ptr->cps);
this->cs = *cs;
this->hdr_size[0] = EGPRS_TYPE2_HDR_SIZE;
}
void gprs_rlc_data::set_resend_fn_ts(const uint32_t fn, const uint8_t ts)
{
this->resend_fn = fn;
this->resend_ts = ts;
}
void gprs_rlc_data::fill_hdr_type1(GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi , const uint16_t cps)
{
/*Refer Header type from 10.3a.3.1 of 46.060*/
struct gprs_rlc_dl_header_egprs_1 *ptr = (struct gprs_rlc_dl_header_egprs_1 *)hdr_ptr[0];
ptr->usf = GPRS_RLCMAC_DATA_BLOCK;
ptr->tfi_a = tfi & 0x01;
ptr->tfi_b = tfi >> 1;
ptr->bsn1_a = bsn & 0x3;
ptr->bsn1_b = bsn >> 2 ;
ptr->bsn1_c = bsn & 0x0400 ;
/*
Theres no scope of retx and Tx block clubbing present in our design
hence bsn2 is always assumed to be 1 i.e bsn2 = nextbsn(bsn1) = 1
*/
ptr->bsn2_a = 1;
ptr->bsn2_b = 0 ;
ptr->cps = cps;
this->cs = *cs;
LOGP(DRLCMACDL, LOGL_DEBUG, "usf :%d \n es :%d\n rrbp: %d \n tfi1:%d\n tfi2:%d\n bsn1a%d \n bsn1b %d \n bsn1c%d\n"
"bsn2a %d\n bsn2b %d\n ",ptr ->usf, ptr -> es_p, ptr -> rrbp, ptr -> tfi_a, ptr ->tfi_b, ptr->bsn1_a,
ptr->bsn1_b, ptr->bsn1_c, ptr->bsn2_a, ptr->bsn2_b);
LOGP(DRLCMACDL, LOGL_DEBUG, "pr: %d cps:%d ", ptr -> pr, ptr ->cps);
this->hdr_size[0] = EGPRS_TYPE1_HDR_SIZE;
}
uint8_t *gprs_rlc_data::prepare(size_t block_data_len)
{
/* todo.. only set it once if it turns out to be a bottleneck */
memset(block, 0x0, sizeof(block));
memset(block, 0x2b, block_data_len);
memset(complete_blk, 0x0, sizeof(complete_blk));
memset(complete_blk, 0x2b, block_data_len);
memset(&hdr_ptr[0],0, RLC_MAX_HDR_SIZE);
memset(&hdr_ptr[1],0, RLC_MAX_HDR_SIZE);
return block;
this->mcs8_retx = false;
this->reseg_status = EGPRS_RESEG_SINGLE_BLOCK;
this->len_block2 = 0;
return complete_blk;
}
void gprs_rlc_data::put_data(const uint8_t *data, size_t data_len)
{
memcpy(block, data, data_len);
len = data_len;
memcpy(complete_blk, data, data_len);
completed_block_len = data_len;
}
void gprs_rlc_v_b::reset()
@ -55,9 +342,25 @@ void gprs_rlc_dl_window::reset()
m_v_b.reset();
}
void gprs_rlc_dl_window::set_sns(uint16_t sns)
{
OSMO_ASSERT(sns >= RLC_GPRS_SNS);
OSMO_ASSERT(sns <= RLC_MAX_SNS);
/* check for 2^n */
OSMO_ASSERT((sns & (-sns)) == sns);
m_sns = sns;
}
void gprs_rlc_dl_window::set_ws(uint16_t ws)
{
OSMO_ASSERT(ws >= RLC_GPRS_SNS/2);
OSMO_ASSERT(ws <= RLC_MAX_SNS/2);
m_ws = ws;
}
int gprs_rlc_dl_window::resend_needed()
{
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = mod_sns(bsn + 1)) {
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = this->mod_sns(bsn + 1)) {
if (m_v_b.is_nacked(bsn) || m_v_b.is_resend(bsn))
return bsn;
}
@ -69,7 +372,7 @@ int gprs_rlc_dl_window::mark_for_resend()
{
int resend = 0;
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = mod_sns(bsn + 1)) {
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = this->mod_sns(bsn + 1)) {
if (m_v_b.is_unacked(bsn)) {
/* mark to be re-send */
m_v_b.mark_resend(bsn);
@ -85,7 +388,7 @@ int gprs_rlc_dl_window::count_unacked()
uint16_t unacked = 0;
uint16_t bsn;
for (bsn = v_a(); bsn != v_s(); bsn = mod_sns(bsn + 1)) {
for (bsn = v_a(); bsn != v_s(); bsn = this->mod_sns(bsn + 1)) {
if (!m_v_b.is_acked(bsn))
unacked += 1;
}
@ -98,45 +401,14 @@ static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn)
return (ssn - 1 - bitnum);
}
void gprs_rlc_dl_window::update(BTS *bts, const struct bitvec *rbb,
uint16_t first_bsn, uint16_t *lost,
uint16_t *received)
{
unsigned num_blocks = rbb->cur_bit;
unsigned bsn;
/* first_bsn is in range V(A)..V(S) */
for (unsigned int bitpos = 0; bitpos < num_blocks; bitpos++) {
bool is_ack;
bsn = mod_sns(first_bsn + bitpos);
if (bsn == mod_sns(v_a() - 1))
break;
is_ack = bitvec_get_bit_pos(rbb, bitpos) == 1;
if (is_ack) {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
if (!m_v_b.is_acked(bsn))
*received += 1;
m_v_b.mark_acked(bsn);
} else {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
}
}
}
void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint16_t ssn,
uint16_t *lost, uint16_t *received)
{
/* SSN - 1 is in range V(A)..V(S)-1 */
for (int bitpos = 0; bitpos < ws(); bitpos++) {
uint16_t bsn = mod_sns(bitnum_to_bsn(bitpos, ssn));
uint16_t bsn = this->mod_sns(bitnum_to_bsn(bitpos, ssn));
if (bsn == mod_sns(v_a() - 1))
if (bsn == this->mod_sns(v_a() - 1))
break;
if (show_rbb[ws() - 1 - bitpos] == 'R') {
@ -153,13 +425,249 @@ void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint16_t ssn,
}
}
void extract_egprs_crbb_urbb(uint16_t uncomp_length, const uint8_t *uncomp_bitmap, char *show_rbb)
{
for (int i = 0; i < uncomp_length; i++) {
uint8_t bit;
bit = !!(uncomp_bitmap[i/8] & (1<<(7-i%8)));
show_rbb[i] = bit ? 'R' : 'I';
}
show_rbb[uncomp_length] = '\0';
}
void extract_egprs_urbb(uint16_t uncomp_length, const uint8_t *uncomp_bitmap, char *show_rbb,uint16_t start_index)
{
for (int i = 0; i < uncomp_length; i++) {
uint8_t bit;
bit = !!(uncomp_bitmap[i/8] & (1<<(7-i%8)));
show_rbb[start_index+uncomp_length-i] = bit ? 'R' : 'I';
}
show_rbb[uncomp_length] = '\0';
}
int search_runlen(
Node *root, /* root of Ones or Zeros tree */
uint8_t* bmbuf, /* Received compressed bitmap buf */
uint8_t bit_pos, /* the start bit pos to read codeword */
uint8_t* len_codewd, /* length of codeword */
uint16_t* rlen /* run length of Ones or Zeros */
)
{
Node* iter;
uint8_t dir;
iter = root;
*len_codewd = 0;
while (iter->run_length == 0) {
if ((iter->left == NULL)&& (iter->right == NULL))
return -1;
/* get the bit value at the bitpos and put it in right most of dir */
dir = (bmbuf[BITS_TO_BYTES(bit_pos)-1]>>(7-(MOD8(bit_pos))))&0x01;
(bit_pos)++;
(*len_codewd)++;
if (((dir&0x01) == 0) && (iter->left != NULL))
iter = iter->left;
else if (((dir&0x01) == 1) && (iter->right != NULL))
iter = iter->right;
else
return -1;
}
(*rlen) = *(iter->run_length);
return 1;
} /* search_runlen */
void gprs_rlc_dl_window::decompress_crbb(
BTS *bts,
int8_t compress_bmap_len, /* compressed bitmap length */
uint8_t clr_code_bit, /* run length of Ones or Zeros */
uint8_t* orig_buf, /* received block bitmap */
int16_t orig_bmaplen, /* bitmap length of Ack/Nack descr */
uint16_t* decompress_bmap_len, /* total bitmap length after decompression */
uint8_t* uncompress_bmbuf, /* bitmap after decompression */
bitvec *dest
)
{
uint8_t bit_pos = 0;
uint8_t nbits = 0; /* number of bits of codeword */
uint16_t run_length = 0;
uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
unsigned wp = 0;
*decompress_bmap_len = 0;
int8_t Lc = compress_bmap_len;
while (compress_bmap_len >= 0) {
if (clr_code_bit == 1) {
search_runlen (bts->ones_list, orig_buf, bit_pos, &nbits, &run_length);
//If run length > 64, need makeup and terminating code
if (run_length < 64) {
clr_code_bit = 0;
}
cbmaplen= cbmaplen + run_length;
/* put run length of Ones in uncompressed bitmap */
while (run_length !=0) {
if (run_length > 8) {
bitvec_write_field(dest, wp, 0xff, 8);
run_length = run_length -8;
}
else {
bitvec_write_field(dest, wp, 0xff, run_length);
run_length = 0;
}
}
}
else {
search_runlen (bts->zeros_list, orig_buf, bit_pos, &nbits, &run_length);
//If run length > 64, need makeup and terminating code
if (run_length < 64) {
clr_code_bit = 1;
}
cbmaplen= cbmaplen + run_length;
/* put run length of Zeros in uncompressed bitmap */
while (run_length !=0) {
if (run_length > 8) {
bitvec_write_field(dest, wp, 0x00, 8);
run_length = run_length -8;
}
else {
bitvec_write_field(dest, wp, 0x00, run_length);
run_length = 0;
}
}
}
bit_pos = bit_pos + nbits;
compress_bmap_len = compress_bmap_len - nbits;
}
/* Decompress_bmap_len is the len of uncompressed bitmap
+ Original bitmap len of ack/nack desc
- Original compressed bitmap len
==> this is requird in extract rbb func*/
(*decompress_bmap_len) = cbmaplen + orig_bmaplen - Lc - 23;
return ;
}/* Decompress_CRBB */
void gprs_rlc_dl_window::egprs_update(BTS *bts, char *show_rbb,
EGPRS_AckNack_Desc_t *Egprs_Desc, uint16_t *lost,
uint16_t *received, int16_t len)
{
int16_t ssn = Egprs_Desc->STARTING_SEQUENCE_NUMBER;
uint8_t bow = Egprs_Desc->BEGINNING_OF_WINDOW;
uint8_t eow = Egprs_Desc->END_OF_WINDOW;
uint16_t uncomp_len = 0; /* total bitmap length of compressed part after
decompcompress plus uncompressed part */
uint8_t uncomp_bitmap[128];
uint16_t crbb_urbb_len = 0; /* bitmap length of compressed part after decompression */
uint16_t urbb_len;
int8_t Lc = Egprs_Desc->CRBB_LENGTH;
bitvec dest;
dest.data = uncomp_bitmap;
dest.cur_bit = 0;
dest.data_len = 128;
if(len > 0) {
urbb_len = len - Lc;
}
else {
urbb_len = Egprs_Desc->URBB_LENGTH;
}
if(Egprs_Desc->Exist_CRBB) {
LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist, "
"CRBB LEN =%d and Starting color code =%d",
Lc, Egprs_Desc->CRBB_STARTING_COLOR_CODE);
decompress_crbb(bts,
Lc,
Egprs_Desc->CRBB_STARTING_COLOR_CODE,
Egprs_Desc->CRBB,
len, //Ack Nack desc length
&uncomp_len,
uncomp_bitmap,
&dest);
/* now attach unCompressed bitmap part to the decompressed bitmap
* in unCompBitmap array if there is any */
/* if (Lc != 0) {
ubmaplen = acknack_len - Lc - 23;
}
else {
ubmaplen = acknack_len - 15;
}*/
crbb_urbb_len = dest.cur_bit;
extract_egprs_crbb_urbb(crbb_urbb_len, uncomp_bitmap, show_rbb);
LOGP(DRLCMACDL, LOGL_DEBUG, "crbb len %d uncomp len %d\n",Lc,crbb_urbb_len);
}
/* uncompressed part */
if ((urbb_len !=0) && (Egprs_Desc->URBB != (uint8_t *)NULL)) {
extract_egprs_urbb(urbb_len, Egprs_Desc->URBB, show_rbb, crbb_urbb_len);
LOGP(DRLCMACDL, LOGL_DEBUG, "urbb len %d\n" ,urbb_len);
}
/* if Beginning of window is set 1, Mark Acked between SSN-2 ( V(Q)-1) to V(A)*/
if (bow) {
for(int i = (v_a() -1); i < (ssn -2); i++ ) {
uint16_t bsn = this->mod_sns(i);
*received += 1;
m_v_b.mark_acked(bsn);
}
/* ssn -1 which is V(Q) should be nacked */
uint16_t bsn = ((2048 + (ssn-1)) & 0x07FF);/* MOD 2048 (MAX BSN NUM) */
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
}
/* SSN - 1 is in range V(A)..V(S)-1 */
for (int bitpos = 0; bitpos < crbb_urbb_len + urbb_len; bitpos++) {
uint16_t bsn = mod_sns(ssn + bitpos);
if (mod_sns(v_s() -bsn) >= distance())
break;
if (show_rbb[bitpos] == 'R') {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
if (!m_v_b.is_acked(bsn))
*received += 1;
m_v_b.mark_acked(bsn);
} else {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
}
}
/* if EOW is set, nack data btw last BSN indicated in the bitmap and
* the end of tx window V(S) */
if(eow) {
/* Currently EOW is not handled
for (int i = ssn + crbb_urbb_len + uncomp_len; bsn < v_s(); i++)
uint16_t bsn = mod_sns(ssn + i);
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
*/
}
}
int gprs_rlc_dl_window::move_window()
{
int i;
uint16_t bsn;
int moved = 0;
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = mod_sns(bsn + 1)) {
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = this->mod_sns(bsn + 1)) {
if (m_v_b.is_acked(bsn)) {
m_v_b.mark_invalid(bsn);
moved += 1;
@ -175,23 +683,23 @@ void gprs_rlc_dl_window::show_state(char *show_v_b)
int i;
uint16_t bsn;
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = mod_sns(bsn + 1)) {
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = this->mod_sns(bsn + 1)) {
uint16_t index = bsn & mod_sns_half();
switch(m_v_b.get_state(index)) {
case GPRS_RLC_DL_BSN_INVALID:
show_v_b[i] = 'I';
break;
case GPRS_RLC_DL_BSN_ACKED:
show_v_b[i] = 'A';
break;
case GPRS_RLC_DL_BSN_RESEND:
show_v_b[i] = 'X';
break;
case GPRS_RLC_DL_BSN_NACKED:
show_v_b[i] = 'N';
break;
default:
show_v_b[i] = '?';
case GPRS_RLC_DL_BSN_INVALID:
show_v_b[i] = 'I';
break;
case GPRS_RLC_DL_BSN_ACKED:
show_v_b[i] = 'A';
break;
case GPRS_RLC_DL_BSN_RESEND:
show_v_b[i] = 'X';
break;
case GPRS_RLC_DL_BSN_NACKED:
show_v_b[i] = 'N';
break;
default:
show_v_b[i] = '?';
}
}
show_v_b[i] = '\0';
@ -203,7 +711,7 @@ void gprs_rlc_v_n::reset()
m_v_n[i] = GPRS_RLC_UL_BSN_INVALID;
}
void gprs_rlc_window::set_sns(uint16_t sns)
void gprs_rlc_ul_window::set_sns(uint16_t sns)
{
OSMO_ASSERT(sns >= RLC_GPRS_SNS);
OSMO_ASSERT(sns <= RLC_MAX_SNS);
@ -212,7 +720,7 @@ void gprs_rlc_window::set_sns(uint16_t sns)
m_sns = sns;
}
void gprs_rlc_window::set_ws(uint16_t ws)
void gprs_rlc_ul_window::set_ws(uint16_t ws)
{
OSMO_ASSERT(ws >= RLC_GPRS_SNS/2);
OSMO_ASSERT(ws <= RLC_MAX_SNS/2);
@ -231,11 +739,29 @@ void gprs_rlc_ul_window::update_rbb(char *rbb)
}
}
/* Update the receive block bitmap */
uint16_t gprs_rlc_ul_window::update_egprs_rbb(char *rbb)
{
int i;
uint16_t bsn;
for (i = 0, bsn = (v_q()+1); ((bsn < (v_r())) && (i < ws())); i++, bsn = this->mod_sns(bsn + 1)) {
//if (m_v_n.is_received(ssn()-1-i))
if (m_v_n.is_received(bsn)) //bsn
//rbb[ws()-1-i] = 'R';
rbb[i] = 'R'; //i
else
rbb[i] = 'I';
}
LOGP(DRLCMACUL, LOGL_DEBUG, "V(N):in update_egprs_rbb \"%s\" R=Received "
"I=Invalid\n", rbb);
return i;
}
/* Raise V(R) to highest received sequence number not received. */
void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn)
{
uint16_t offset_v_r;
offset_v_r = mod_sns(bsn + 1 - v_r());
offset_v_r = this->mod_sns(bsn + 1 - v_r());
/* Positive offset, so raise. */
if (offset_v_r < (sns() >> 1)) {
while (offset_v_r--) {
@ -259,7 +785,7 @@ uint16_t gprs_rlc_ul_window::raise_v_q()
if (!m_v_n.is_received(v_q()))
break;
LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
"V(Q) to %d\n", v_q(), mod_sns(v_q() + 1));
"V(Q) to %d\n", v_q(), this->mod_sns(v_q() + 1));
raise_v_q(1);
count += 1;
}
@ -280,108 +806,3 @@ bool gprs_rlc_ul_window::invalidate_bsn(const uint16_t bsn)
return was_valid;
}
static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc,
GprsCodingScheme cs, bool with_padding, unsigned int header_bits)
{
unsigned int i;
unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0;
memset(rlc, 0, sizeof(*rlc));
rlc->cs = cs;
rlc->with_padding = with_padding;
rlc->num_data_blocks = cs.numDataBlocks();
OSMO_ASSERT(rlc->num_data_blocks <= ARRAY_SIZE(rlc->block_info));
for (i = 0; i < rlc->num_data_blocks; i++) {
gprs_rlc_data_block_info_init(&rlc->block_info[i], cs,
with_padding);
rlc->data_offs_bits[i] =
header_bits + padding_bits +
(i+1) * cs.numDataBlockHeaderBits() +
i * 8 * rlc->block_info[0].data_len;
}
}
void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc,
GprsCodingScheme cs, bool with_padding)
{
return gprs_rlc_data_header_init(rlc, cs, with_padding,
cs.numDataHeaderBitsDL());
}
void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc,
GprsCodingScheme cs, bool with_padding)
{
return gprs_rlc_data_header_init(rlc, cs, with_padding,
cs.numDataHeaderBitsUL());
}
void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi,
GprsCodingScheme cs, bool with_padding)
{
unsigned int data_len = cs.maxDataBlockBytes();
if (with_padding)
data_len -= cs.optionalPaddingBits() / 8;
rdbi->data_len = data_len;
rdbi->bsn = 0;
rdbi->ti = 0;
rdbi->e = 1;
rdbi->cv = 15;
rdbi->pi = 0;
rdbi->spb = 0;
}
unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int punct2,
int with_padding)
{
switch (GprsCodingScheme::Scheme(cs)) {
case GprsCodingScheme::MCS1: return 0b1011 + punct % 2;
case GprsCodingScheme::MCS2: return 0b1001 + punct % 2;
case GprsCodingScheme::MCS3: return (with_padding ? 0b0110 : 0b0011) +
punct % 3;
case GprsCodingScheme::MCS4: return 0b0000 + punct % 3;
case GprsCodingScheme::MCS5: return 0b100 + punct % 2;
case GprsCodingScheme::MCS6: return (with_padding ? 0b010 : 0b000) +
punct % 2;
case GprsCodingScheme::MCS7: return 0b10100 + 3 * (punct % 3) + punct2 % 3;
case GprsCodingScheme::MCS8: return 0b01011 + 3 * (punct % 3) + punct2 % 3;
case GprsCodingScheme::MCS9: return 0b00000 + 4 * (punct % 3) + punct2 % 3;
default: ;
}
return -1;
}
void gprs_rlc_mcs_cps_decode(unsigned int cps,
GprsCodingScheme cs, int *punct, int *punct2, int *with_padding)
{
*punct2 = -1;
*with_padding = 0;
switch (GprsCodingScheme::Scheme(cs)) {
case GprsCodingScheme::MCS1:
cps -= 0b1011; *punct = cps % 2; break;
case GprsCodingScheme::MCS2:
cps -= 0b1001; *punct = cps % 2; break;
case GprsCodingScheme::MCS3:
cps -= 0b0011; *punct = cps % 3; *with_padding = cps >= 3; break;
case GprsCodingScheme::MCS4:
cps -= 0b0000; *punct = cps % 3; break;
case GprsCodingScheme::MCS5:
cps -= 0b100; *punct = cps % 2; break;
case GprsCodingScheme::MCS6:
cps -= 0b000; *punct = cps % 2; *with_padding = cps >= 2; break;
case GprsCodingScheme::MCS7:
cps -= 0b10100; *punct = cps / 3; *punct2 = cps % 3; break;
case GprsCodingScheme::MCS8:
cps -= 0b01011; *punct = cps / 3; *punct2 = cps % 3; break;
case GprsCodingScheme::MCS9:
cps -= 0b00000; *punct = cps / 4; *punct2 = cps % 3; break;
default: ;
}
}

310
src/rlc.h
View File

@ -19,6 +19,7 @@
*/
#pragma once
#include <stdint.h>
#include "gprs_coding_scheme.h"
#include <osmocom/core/endian.h>
@ -31,11 +32,9 @@
#define RLC_EGPRS_MIN_WS 64 /* min window size */
#define RLC_EGPRS_MAX_WS 1024 /* min window size */
#define RLC_EGPRS_SNS 2048 /* EGPRS, must be power of 2 */
#define RLC_EGPRS_MAX_BSN_DELTA 512
#define RLC_MAX_SNS RLC_EGPRS_SNS
#define RLC_MAX_WS RLC_EGPRS_MAX_WS
#define RLC_MAX_LEN 74 /* MCS-9 data unit */
#define RLC_MAX_LEN 74 + 1 /* MCS-9 data unit + E byte */
#define RLC_MAX_HDR_SIZE 5 /* Hdr information stored */
struct BTS;
struct gprs_rlc_v_n;
@ -57,61 +56,89 @@ enum gprs_rlc_dl_bsn_state {
};
/* EDGE resegment status information for UL */
enum egprs_rlc_ul_reseg_bsn_state{
EGPRS_RESEG_DEFAULT = 0,
EGPRS_RESEG_FIRST_BLOCK_RXD = 0x01,
EGPRS_RESEG_SECOND_BLOCK_RXD = 0x02
};
/* EDGE resegment status information for DL */
enum egprs_rlc_dl_reseg_bsn_state{
EGPRS_RESEG_SINGLE_BLOCK = 0,
EGPRS_SECOND_SEGMENT_NOT_SENT,
EGPRS_SECOND_SEGMENT_SENT,
};
static inline uint16_t mod_sns_half()
{
return (RLC_MAX_SNS / 2) - 1;
}
struct gprs_rlc_data_block_info {
struct gprs_rlc_ul_data_block_info {
unsigned int data_len; /* EGPRS: N2, GPRS: N2-2, N-2 */
unsigned int bsn;
unsigned int ti;
unsigned int e;
unsigned int cv; /* FBI == 1 <=> CV == 0 */
unsigned int cv;
unsigned int pi;
unsigned int spb;
};
struct gprs_rlc_data_info {
struct gprs_rlc_ul_header_generic{
GprsCodingScheme cs;
unsigned int r;
unsigned int cv;
unsigned int si;
unsigned int tfi;
unsigned int cps;
unsigned int rsb;
unsigned int usf;
unsigned int es_p;
unsigned int rrbp;
unsigned int pr;
unsigned int pani;
unsigned int num_data_blocks;
unsigned int with_padding;
unsigned int data_offs_bits[2];
struct gprs_rlc_data_block_info block_info[2];
unsigned int data_offs_bytes[2];
struct gprs_rlc_ul_data_block_info block_info[2];
};
struct gprs_rlc_data {
uint8_t *prepare(size_t block_data_length);
void put_data(const uint8_t *data, size_t len);
/* block history */
uint8_t block[RLC_MAX_LEN];
/* block len of history */
uint8_t len;
void fill_hdr_type3( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi, const uint16_t cps);
void fill_hdr_type2( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi, const uint16_t cps);
void fill_hdr_type1( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi, const uint16_t cps);
void set_resend_fn_ts( const uint32_t fn, const uint8_t ts);
struct gprs_rlc_data_block_info block_info;
int egprs_build_header_type3_from_type2(uint8_t *enc,
GprsCodingScheme *reseg_mcs,uint8_t ps,uint8_t spb );
int egprs_build_header_type3_from_type1(uint8_t *enc ,
GprsCodingScheme *reseg_mcs, uint8_t ps,uint8_t spb);
int egprs_build_header_type2_from_type1(uint8_t *enc,
GprsCodingScheme *reseg_mcs,uint8_t ps);
void update_cps( GprsCodingScheme *cs, const uint8_t next_ps);
/* block history . also used for assembled RLC block*/
uint8_t complete_blk[RLC_MAX_LEN];
uint8_t completed_block_len;
/* block history for second segment only if it is received before first segment*/
uint8_t block2[RLC_MAX_LEN];
uint8_t len_block2;
struct gprs_rlc_ul_data_block_info block_info;
egprs_rlc_ul_reseg_bsn_state block_status_ul;
GprsCodingScheme cs;
};
void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc,
GprsCodingScheme cs, bool with_padding);
void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc,
GprsCodingScheme cs, bool with_padding);
void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi,
GprsCodingScheme cs, bool with_padding);
unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int punct2,
int with_padding);
void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs,
int *punct, int *punct2, int *with_padding);
uint8_t last_ps;
uint8_t hdr_ptr[2][RLC_MAX_HDR_SIZE];
uint8_t hdr_size[2];
uint8_t reseg_status;
uint8_t mcs8_retx;
uint8_t status;
uint16_t bsn;
uint32_t resend_fn;
uint8_t resend_ts;
};
/*
* I hold the currently transferred blocks and will provide
@ -154,28 +181,19 @@ private:
/**
* TODO: The UL/DL code could/should share a base class.
* TODO: The UL/DL code could/should share a baseclass but
* we are using llist_for_each_entry for the TBF which
* requires everything which creates a requirement for a POD
* type and in < C++11 something that is using even if the
* most simple form of inheritance is not a POD anymore.
*/
class gprs_rlc_window {
public:
gprs_rlc_window();
struct gprs_rlc_dl_window {
void reset();
const uint16_t mod_sns() const;
const uint16_t mod_sns(uint16_t bsn) const;
const uint16_t sns() const;
const uint16_t ws() const;
void set_sns(uint16_t sns);
void set_ws(uint16_t ws);
protected:
uint16_t m_sns;
uint16_t m_ws;
};
struct gprs_rlc_dl_window: public gprs_rlc_window {
void reset();
bool window_stalled() const;
bool window_empty() const;
@ -192,9 +210,20 @@ struct gprs_rlc_dl_window: public gprs_rlc_window {
int mark_for_resend();
void update(BTS *bts, char *show_rbb, uint16_t ssn,
uint16_t *lost, uint16_t *received);
void update(BTS *bts, const struct bitvec *rbb,
uint16_t first_bsn, uint16_t *lost,
uint16_t *received);
void egprs_update(BTS *bts, char *show_rbb,
EGPRS_AckNack_Desc_t *Egprs_Desc, uint16_t *lost,
uint16_t *received, int16_t len);
void decompress_crbb(
BTS *bts,
int8_t compress_bmap_len,
uint8_t clr_code_bit,
uint8_t* orig_buf,
int16_t orig_bmapLen,
uint16_t* decompress_bmap_len,
uint8_t* uncompress_bmbuf,
bitvec *dest
);
int move_window();
void show_state(char *show_rbb);
int count_unacked();
@ -204,7 +233,13 @@ struct gprs_rlc_dl_window: public gprs_rlc_window {
gprs_rlc_v_b m_v_b;
void set_sns(uint16_t sns);
void set_ws(uint16_t ws);
gprs_rlc_dl_window();
private:
uint16_t m_sns;
uint16_t m_ws;
};
struct gprs_rlc_v_n {
@ -222,7 +257,12 @@ private:
gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
};
struct gprs_rlc_ul_window: public gprs_rlc_window {
struct gprs_rlc_ul_window {
const uint16_t mod_sns() const;
const uint16_t mod_sns(uint16_t bsn) const;
const uint16_t sns() const;
const uint16_t ws() const;
const uint16_t v_r() const;
const uint16_t v_q() const;
@ -232,6 +272,7 @@ struct gprs_rlc_ul_window: public gprs_rlc_window {
bool is_received(uint16_t bsn) const;
void update_rbb(char *rbb);
uint16_t update_egprs_rbb(char *rbb);
void raise_v_r_to(int moves);
void raise_v_r(const uint16_t bsn);
uint16_t raise_v_q();
@ -246,12 +287,17 @@ struct gprs_rlc_ul_window: public gprs_rlc_window {
gprs_rlc_v_n m_v_n;
void set_sns(uint16_t sns);
void set_ws(uint16_t ws);
gprs_rlc_ul_window();
private:
uint16_t m_sns;
uint16_t m_ws;
};
extern "C" {
/* TS 04.60 10.2.2 */
#if OSMO_IS_LITTLE_ENDIAN
struct rlc_ul_header {
uint8_t r:1,
si:1,
@ -277,6 +323,51 @@ struct rlc_dl_header {
bsn:7;
} __attribute__ ((packed));
struct gprs_rlc_dl_header_egprs_3 {
uint8_t usf:3,
es_p:2,
rrbp:2,
tfi_a:1;
uint8_t tfi_b:4,
pr:2,
bsn_a:2;
uint8_t bsn_b;
uint8_t bsn_c:1,
cps:4,
spb:2,
dummy:1;
} __attribute__ ((packed));
struct gprs_rlc_dl_header_egprs_2 {
uint8_t usf:3,
es_p:2,
rrbp:2,
tfi_a:1;
uint8_t tfi_b:4,
pr:2,
bsn_a:2;
uint8_t bsn_b;
uint8_t bsn_c:1,
cps:3,
dummy:4;
} __attribute__ ((packed));
struct gprs_rlc_dl_header_egprs_1 {
uint8_t usf:3,
es_p:2,
rrbp:2,
tfi_a:1;
uint8_t tfi_b:4,
pr:2,
bsn1_a:2;
uint8_t bsn1_b;
uint8_t bsn1_c:1,
bsn2_a:7;
uint8_t bsn2_b:3,
cps:5;
} __attribute__ ((packed));
struct rlc_li_field {
uint8_t e:1,
m:1,
@ -305,52 +396,41 @@ struct gprs_rlc_ul_header_egprs_3 {
dummy:1;
} __attribute__ ((packed));
struct gprs_rlc_dl_header_egprs_1 {
uint8_t usf:3,
es_p:2,
rrbp:2,
tfi_a:1;
uint8_t tfi_b:4,
pr:2,
bsn1_a:2;
uint8_t bsn1_b:8;
uint8_t bsn1_c:1,
bsn2_a:7;
uint8_t bsn2_b:3,
cps:5;
struct gprs_rlc_ul_header_egprs_2 {
uint8_t r:1,
si:1,
cv:4,
tfi_a:2;
uint8_t tfi_b:3,
bsn1_a:5;
uint8_t bsn1_b:6,
cps_a:2;
uint8_t cps_b:1,
rsb:1,
pi:1,
spare:5;
uint8_t spare1:5,
dummy:3;
} __attribute__ ((packed));
struct gprs_rlc_dl_header_egprs_2 {
uint8_t usf:3,
es_p:2,
rrbp:2,
tfi_a:1;
uint8_t tfi_b:4,
pr:2,
bsn1_a:2;
uint8_t bsn1_b:8;
uint8_t bsn1_c:1,
cps:3,
dummy:4;
} __attribute__ ((packed));
struct gprs_rlc_dl_header_egprs_3 {
uint8_t usf:3,
es_p:2,
rrbp:2,
tfi_a:1;
uint8_t tfi_b:4,
pr:2,
bsn1_a:2;
uint8_t bsn1_b:8;
uint8_t bsn1_c:1,
cps:4,
spb:2,
dummy:1;
struct gprs_rlc_ul_header_egprs_1 {
uint8_t r:1,
si:1,
cv:4,
tfi_a:2;
uint8_t tfi_b:3,
bsn1_a:5;
uint8_t bsn1_b:6,
bsn2_a:2;
uint8_t bsn2_b;
uint8_t cps:5,
rsb:1,
pi:1,
spare:1;
uint8_t spare2:6,
dummy:2;
} __attribute__ ((packed));
#else
# error "Only little endian headers are supported yet. TODO: add missing structs"
#endif
}
inline bool gprs_rlc_v_b::is_state(int bsn, const gprs_rlc_dl_bsn_state type) const
@ -418,38 +498,33 @@ inline void gprs_rlc_v_b::mark_invalid(int bsn)
return mark(bsn, GPRS_RLC_DL_BSN_INVALID);
}
inline gprs_rlc_window::gprs_rlc_window()
: m_sns(RLC_GPRS_SNS)
inline gprs_rlc_dl_window::gprs_rlc_dl_window()
: m_v_s(0)
, m_v_a(0)
, m_sns(RLC_GPRS_SNS)
, m_ws(RLC_GPRS_WS)
{
}
inline const uint16_t gprs_rlc_window::sns() const
inline const uint16_t gprs_rlc_dl_window::sns() const
{
return m_sns;
}
inline const uint16_t gprs_rlc_window::ws() const
inline const uint16_t gprs_rlc_dl_window::ws() const
{
return m_ws;
}
inline const uint16_t gprs_rlc_window::mod_sns() const
inline const uint16_t gprs_rlc_dl_window::mod_sns() const
{
return sns() - 1;
}
inline const uint16_t gprs_rlc_window::mod_sns(uint16_t bsn) const
inline const uint16_t gprs_rlc_dl_window::mod_sns(uint16_t bsn) const
{
return bsn & mod_sns();
}
inline gprs_rlc_dl_window::gprs_rlc_dl_window()
: m_v_s(0)
, m_v_a(0)
{
}
inline const uint16_t gprs_rlc_dl_window::v_s() const
{
return m_v_s;
@ -493,6 +568,8 @@ inline const int16_t gprs_rlc_dl_window::distance() const
inline gprs_rlc_ul_window::gprs_rlc_ul_window()
: m_v_r(0)
, m_v_q(0)
, m_sns(RLC_GPRS_SNS)
, m_ws(RLC_GPRS_WS)
{
}
@ -516,6 +593,25 @@ inline bool gprs_rlc_ul_window::is_received(uint16_t bsn) const
return is_in_window(bsn) && m_v_n.is_received(bsn) && offset_v_r < ws();
}
inline const uint16_t gprs_rlc_ul_window::sns() const
{
return m_sns;
}
inline const uint16_t gprs_rlc_ul_window::ws() const
{
return m_ws;
}
inline const uint16_t gprs_rlc_ul_window::mod_sns() const
{
return sns() - 1;
}
inline const uint16_t gprs_rlc_ul_window::mod_sns(uint16_t bsn) const
{
return bsn & mod_sns();
}
inline const uint16_t gprs_rlc_ul_window::v_r() const
{
return m_v_r;

View File

@ -357,7 +357,7 @@ int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
return 0;
}
void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap)
void *l1if_open_pdch(void *priv, uint32_t hlayer1)
{
struct femtol1_hdl *fl1h;
int rc;
@ -378,7 +378,9 @@ void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap)
return NULL;
}
fl1h->gsmtap = gsmtap;
fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1);
if (fl1h->gsmtap)
gsmtap_source_add_sink(fl1h->gsmtap);
return fl1h;
}

View File

@ -28,7 +28,6 @@
#include <gprs_bssgp_pcu.h>
#include <gprs_ms.h>
#include <decoding.h>
#include <pcu_utils.h>
extern "C" {
#include <osmocom/core/msgb.h>
@ -39,9 +38,21 @@ extern "C" {
#include <string.h>
extern void *tall_pcu_ctx;
static void tbf_timer_cb(void *_tbf);
//Maximum Window Size according to number of allocated timeslots
uint16_t windowsizebyTS[9] = {
64, // default value
192, // 1 TS
256, // 2 TS
384, // 3 TS
512, // 4 TS
640, // 5 TS
768, // 6 TS
896, // 7 TS
1024 // 8 TS
};
gprs_rlcmac_tbf::Meas::Meas() :
rssi_sum(0),
rssi_num(0)
@ -61,7 +72,6 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir) :
ul_ack_state(GPRS_RLCMAC_UL_ACK_NONE),
poll_state(GPRS_RLCMAC_POLL_NONE),
poll_fn(0),
poll_ts(0),
n3105(0),
T(0),
num_T_exp(0),
@ -76,12 +86,12 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir) :
m_ms(NULL),
m_ta(0),
m_ms_class(0),
m_list(this),
m_ms_list(this),
m_egprs_enabled(false)
m_egprs_enabled(false)
{
/* The classes of these members do not have proper constructors yet.
* Just set them to 0 like talloc_zero did */
memset(&list, 0, sizeof(list));
memset(&pdch, 0, sizeof(pdch));
memset(&timer, 0, sizeof(timer));
memset(&m_rlc, 0, sizeof(m_rlc));
@ -90,6 +100,9 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir) :
m_llc.init();
m_name_buf[0] = '\0';
/* Back pointer for PODS llist compatibility */
list.back = this;
}
gprs_rlcmac_bts *gprs_rlcmac_tbf::bts_data() const
@ -167,15 +180,15 @@ void gprs_rlcmac_tbf::set_ms_class(uint8_t ms_class_)
m_ms_class = ms_class_;
}
GprsCodingScheme gprs_rlcmac_tbf::current_cs() const
uint8_t gprs_rlcmac_tbf::current_cs() const
{
GprsCodingScheme cs;
uint8_t cs;
if (direction == GPRS_RLCMAC_UL_TBF)
cs = m_ms ? m_ms->current_cs_ul() : GprsCodingScheme();
cs = m_ms ? m_ms->current_cs_ul() : bts->bts_data()->initial_cs_ul;
else
cs = m_ms ? m_ms->current_cs_dl() : GprsCodingScheme();
cs = m_ms ? m_ms->current_cs_dl() : bts->bts_data()->initial_cs_dl;
return cs;
return cs < 1 ? 1 : cs;
}
gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()
@ -311,23 +324,11 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
void tbf_free(struct gprs_rlcmac_tbf *tbf)
{
/* update counters */
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
tbf->bts->tbf_ul_freed();
if (tbf->state_is(GPRS_RLCMAC_FLOW))
tbf->bts->tbf_ul_aborted();
} else {
tbf->bts->tbf_dl_freed();
if (tbf->state_is(GPRS_RLCMAC_FLOW))
tbf->bts->tbf_dl_aborted();
}
/* Give final measurement report */
gprs_rlcmac_rssi_rep(tbf);
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf);
dl_tbf->abort();
gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
gprs_rlcmac_lost_rep(dl_tbf);
dl_tbf->cleanup();
}
@ -347,7 +348,12 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
tbf->stop_timer();
#warning "TODO: Could/Should generate bssgp_tx_llc_discarded"
tbf_unlink_pdch(tbf);
llist_del(&tbf->list());
llist_del(&tbf->list.list);
if (tbf->direction == GPRS_RLCMAC_UL_TBF)
tbf->bts->tbf_ul_freed();
else
tbf->bts->tbf_dl_freed();
if (tbf->ms())
tbf->set_ms(NULL);
@ -394,7 +400,6 @@ int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
const char *gprs_rlcmac_tbf::tbf_state_name[] = {
"NULL",
"ASSIGN",
"WAIT ASSIGN",
"FLOW",
"FINISHED",
"WAIT RELEASE",
@ -436,53 +441,10 @@ void gprs_rlcmac_tbf::stop_timer()
}
}
int gprs_rlcmac_tbf::check_polling(uint32_t fn, uint8_t ts,
uint32_t *poll_fn_, unsigned int *rrbp_)
{
uint32_t fn_offs = 13;
uint32_t new_poll_fn = (fn + fn_offs) % 2715648;
if (!is_control_ts(ts)) {
LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
"scheduled in this TS %d (first control TS %d)\n",
ts, control_ts);
return -EINVAL;
}
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMAC, LOGL_DEBUG,
"Polling is already scheduled for %s\n",
name());
return -EBUSY;
}
if (bts->sba()->find(trx->trx_no, ts, (fn + 13) % 2715648)) {
LOGP(DRLCMAC, LOGL_DEBUG, "%s: Polling is already scheduled "
"for single block allocation at FN %d TS %d ...\n",
name(), new_poll_fn, ts);
return -EBUSY;
}
*poll_fn_ = new_poll_fn;
*rrbp_ = 0;
return 0;
}
void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts)
{
LOGP(DRLCMAC, LOGL_DEBUG,
"%s: Scheduling polling at FN %d TS %d\n",
name(), new_poll_fn, ts);
/* schedule polling */
poll_state = GPRS_RLCMAC_POLL_SCHED;
poll_fn = new_poll_fn;
poll_ts = ts;
}
void gprs_rlcmac_tbf::poll_timeout()
{
LOGP(DRLCMAC, LOGL_NOTICE, "%s poll timeout for FN=%d, TS=%d (curr FN %d)\n",
tbf_name(this), poll_fn, poll_ts, bts->current_frame_number());
LOGP(DRLCMAC, LOGL_NOTICE, "%s poll timeout for FN=%d (curr FN %d)\n",
tbf_name(this), poll_fn, bts->current_frame_number());
poll_state = GPRS_RLCMAC_POLL_NONE;
@ -496,7 +458,7 @@ void gprs_rlcmac_tbf::poll_timeout()
ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE;
bts->rlc_ack_timedout();
if (state_is(GPRS_RLCMAC_FINISHED)) {
gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(this);
gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(this);
ul_tbf->m_n3103++;
if (ul_tbf->m_n3103 == ul_tbf->bts->bts_data()->n3103) {
LOGP(DRLCMAC, LOGL_NOTICE,
@ -550,7 +512,7 @@ void gprs_rlcmac_tbf::poll_timeout()
/* reschedule DL assignment */
dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS;
} else if (direction == GPRS_RLCMAC_DL_TBF) {
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(this);
if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling "
@ -596,11 +558,13 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf,
bts = tbf->bts->bts_data();
if (ms->mode() == GprsCodingScheme::EGPRS)
ms_class = egprs_ms_class;
tbf->m_created_ts = time(NULL);
tbf->set_ms_class(ms_class);
if(!tbf->is_egprs_enabled())
tbf->set_ms_class(ms_class);
else
tbf->set_ms_class(egprs_ms_class);
/* select algorithm */
rc = bts->alloc_algorithm(bts, ms, tbf, bts->alloc_algorithm_curst,
single_slot, use_trx);
@ -643,17 +607,6 @@ static int ul_tbf_dtor(struct gprs_rlcmac_ul_tbf *tbf)
return 0;
}
static void setup_egprs_mode(gprs_rlcmac_bts *bts, GprsMs *ms)
{
if (GprsCodingScheme::getEgprsByNum(bts->max_mcs_ul).isEgprsGmsk() &&
GprsCodingScheme::getEgprsByNum(bts->max_mcs_dl).isEgprsGmsk() &&
ms->mode() != GprsCodingScheme::EGPRS)
{
ms->set_mode(GprsCodingScheme::EGPRS_GMSK);
} else {
ms->set_mode(GprsCodingScheme::EGPRS);
}
}
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
GprsMs *ms, int8_t use_trx,
@ -662,13 +615,6 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_ul_tbf *tbf;
int rc;
if (egprs_ms_class == 0 && bts->egprs_enabled) {
LOGP(DRLCMAC, LOGL_NOTICE,
"Not accepting non-EGPRS phone in EGPRS-only mode\n");
bts->bts->tbf_failed_egprs_only();
return NULL;
}
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: MS_CLASS=%d/%d\n",
"UL", ms_class, egprs_ms_class);
@ -685,13 +631,10 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
if (egprs_ms_class > 0 && bts->egprs_enabled) {
/* TODO: only for 8PSK, otherwise the GPRS MS class has to be used */
tbf->enable_egprs();
tbf->m_window.set_sns(RLC_EGPRS_SNS);
/* TODO: Allow bigger UL windows when CRBB encoding is supported */
tbf->m_window.set_ws(RLC_EGPRS_MIN_WS);
setup_egprs_mode(bts, ms);
LOGP(DRLCMAC, LOGL_INFO, "Enabled EGPRS for %s, mode %s\n",
tbf->name(), GprsCodingScheme::modeName(ms->mode()));
}
rc = setup_tbf(tbf, ms, use_trx, ms_class, egprs_ms_class, single_slot);
@ -701,7 +644,7 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
return NULL;
}
llist_add(&tbf->list(), &bts->bts->ul_tbfs());
llist_add(&tbf->list.list, &bts->ul_tbfs);
tbf->bts->tbf_ul_created();
return tbf;
@ -734,25 +677,15 @@ static int dl_tbf_dtor(struct gprs_rlcmac_dl_tbf *tbf)
}
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
GprsMs *ms, int8_t use_trx,
uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot)
GprsMs *ms, int8_t use_trx,
uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot)
{
struct gprs_rlcmac_dl_tbf *tbf;
int rc;
if (egprs_ms_class == 0 && bts->egprs_enabled) {
if (ms_class > 0) {
LOGP(DRLCMAC, LOGL_NOTICE,
"Not accepting non-EGPRS phone in EGPRS-only mode\n");
bts->bts->tbf_failed_egprs_only();
return NULL;
}
egprs_ms_class = 1;
}
int rc = -1;
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: MS_CLASS=%d/%d\n",
"DL", ms_class, egprs_ms_class);
LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: MS_CLASS=%d\n",
"DL", ms_class);
tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
@ -762,40 +695,25 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
talloc_set_destructor(tbf, dl_tbf_dtor);
new (tbf) gprs_rlcmac_dl_tbf(bts->bts);
if (!ms)
ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
if (egprs_ms_class > 0 && bts->egprs_enabled) {
tbf->enable_egprs();
tbf->m_window.set_sns(RLC_EGPRS_SNS);
setup_egprs_mode(bts, ms);
LOGP(DRLCMAC, LOGL_INFO, "Enabled EGPRS for %s, mode %s\n",
tbf->name(), GprsCodingScheme::modeName(ms->mode()));
}
/* TODO: only for 8PSK, otherwise the GPRS MS class has to be used */
tbf->enable_egprs();
tbf->m_window.set_sns(RLC_EGPRS_SNS);
tbf->m_window.set_ws(RLC_EGPRS_MIN_WS);
}
rc = setup_tbf(tbf, ms, use_trx, ms_class, 0, single_slot);
if (!ms)
{
ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
}
rc = setup_tbf(tbf, ms, use_trx, ms_class, egprs_ms_class, single_slot);
/* if no resource */
if (rc < 0) {
talloc_free(tbf);
return NULL;
}
if (tbf->is_egprs_enabled()) {
unsigned int num_pdch = pcu_bitcount(tbf->dl_slots());
unsigned int ws = bts->ws_base + num_pdch * bts->ws_pdch;
ws = (ws / 32) * 32;
ws = OSMO_MAX(64, ws);
if (num_pdch == 1)
ws = OSMO_MIN(192, ws);
else
ws = OSMO_MIN(128 * num_pdch, ws);
LOGP(DRLCMAC, LOGL_INFO, "%s: Setting EGPRS window size to %d\n",
tbf->name(), ws);
tbf->m_window.set_ws(ws);
}
llist_add(&tbf->list(), &bts->bts->dl_tbfs());
llist_add(&tbf->list.list, &bts->dl_tbfs);
tbf->bts->tbf_dl_created();
tbf->m_last_dl_poll_fn = -1;
@ -824,12 +742,6 @@ void gprs_rlcmac_tbf::handle_timeout()
case 0: /* assignment */
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) {
if (state_is(GPRS_RLCMAC_ASSIGN)) {
LOGP(DRLCMAC, LOGL_NOTICE, "%s releasing due to "
"PACCH assignment timeout (not yet sent).\n",
tbf_name(this));
tbf_free(this);
return;
} else if (state_is(GPRS_RLCMAC_WAIT_ASSIGN)) {
LOGP(DRLCMAC, LOGL_NOTICE, "%s releasing due to "
"PACCH assignment timeout.\n", tbf_name(this));
tbf_free(this);
@ -839,9 +751,9 @@ void gprs_rlcmac_tbf::handle_timeout()
"in assign state\n", tbf_name(this));
}
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) {
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(this);
dl_tbf->m_wait_confirm = 0;
if (dl_tbf->state_is(GPRS_RLCMAC_WAIT_ASSIGN)) {
if (dl_tbf->state_is(GPRS_RLCMAC_ASSIGN)) {
tbf_assign_control_ts(dl_tbf);
if (!dl_tbf->upgrade_to_multislot) {
@ -858,6 +770,7 @@ void gprs_rlcmac_tbf::handle_timeout()
/* keep to flags */
dl_tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
dl_tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
dl_tbf->update();
@ -905,40 +818,37 @@ int gprs_rlcmac_tbf::rlcmac_diag()
return 0;
}
struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn)
{
struct msgb *msg;
struct gprs_rlcmac_dl_tbf *new_dl_tbf = NULL;
int poll_ass_dl = 1;
unsigned int rrbp = 0;
uint32_t new_poll_fn = 0;
int rc;
bool old_tfi_is_valid = is_tfi_assigned();
if (direction == GPRS_RLCMAC_DL_TBF && !is_control_ts(ts)) {
int nbofdlts = 0, i;
uint16_t window_size, new_ws;
if (direction == GPRS_RLCMAC_DL_TBF && control_ts != first_common_ts) {
LOGP(DRLCMAC, LOGL_NOTICE, "Cannot poll for downlink "
"assigment, because MS cannot reply. (TS=%d, "
"first common TS=%d)\n", ts,
"assigment, because MS cannot reply. (control TS=%d, "
"first common TS=%d)\n", control_ts,
first_common_ts);
poll_ass_dl = 0;
}
if (poll_ass_dl) {
if (poll_state == GPRS_RLCMAC_POLL_SCHED &&
ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK)
{
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for %s, so we must wait for the uplink "
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already sheduled "
"for %s, so we must wait for downlink "
"assignment...\n", tbf_name(this));
return NULL;
}
if (bts->sba()->find(trx->trx_no, control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for single block allocation...\n");
return NULL;
}
rc = check_polling(fn, ts, &new_poll_fn, &rrbp);
if (rc < 0)
return NULL;
}
/* on uplink TBF we get the downlink TBF to be assigned. */
if (direction == GPRS_RLCMAC_UL_TBF) {
gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(this);
gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(this);
/* be sure to check first, if contention resolution is done,
* otherwise we cannot send the assignment yet */
@ -960,19 +870,23 @@ struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
return NULL;
}
if(is_egprs_enabled()) {
for (i = 0; i < 8; i++) {
if (new_dl_tbf->pdch[i])
nbofdlts++;
}
if (new_dl_tbf == as_dl_tbf(this))
LOGP(DRLCMAC, LOGL_DEBUG,
"New and old TBF are the same %s\n", name());
new_ws = windowsizebyTS[nbofdlts];
if (old_tfi_is_valid && !new_dl_tbf->is_tlli_valid()) {
LOGP(DRLCMACDL, LOGL_ERROR,
"The old TFI is not assigned and there is no "
"TLLI. Old TBF %s, new TBF %s\n",
name(), new_dl_tbf->name());
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
return NULL;
if (new_ws > (new_dl_tbf->m_window.ws()))
new_dl_tbf->m_window.set_ws(new_ws);
window_size = new_dl_tbf->m_window.ws();
LOGP(DRLCMACDL, LOGL_ERROR, " New Window_size is assigned in"
"create_DL_ASS %d\n",window_size);
}
window_size = new_dl_tbf->m_window.ws();
new_dl_tbf->was_releasing = was_releasing;
msg = msgb_alloc(23, "rlcmac_dl_ass");
@ -983,15 +897,15 @@ struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
msgb_free(msg);
return NULL;
}
bitvec_unhex(ass_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
LOGP(DRLCMAC, LOGL_INFO, "%s start Packet Downlink Assignment (PACCH)\n", tbf_name(new_dl_tbf));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
Encoding::write_packet_downlink_assignment(mac_control_block,
old_tfi_is_valid, m_tfi, (direction == GPRS_RLCMAC_DL_TBF),
new_dl_tbf, poll_ass_dl, rrbp,
bts_data()->alpha, bts_data()->gamma, -1, 0,
is_egprs_enabled());
Encoding::write_packet_downlink_assignment(mac_control_block, m_tfi,
(direction == GPRS_RLCMAC_DL_TBF), new_dl_tbf,
poll_ass_dl, bts_data()->alpha, bts_data()->gamma, -1, 0,
window_size);
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n");
encode_gsm_rlcmac_downlink(ass_vec, mac_control_block);
LOGPC(DCSN1, LOGL_NOTICE, "\n");
@ -1001,13 +915,12 @@ struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
talloc_free(mac_control_block);
if (poll_ass_dl) {
set_polling(new_poll_fn, ts);
if (new_dl_tbf->state_is(GPRS_RLCMAC_ASSIGN))
new_dl_tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN);
poll_state = GPRS_RLCMAC_POLL_SCHED;
poll_fn = (fn + 13) % 2715648;
dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK;
LOGP(DRLCMACDL, LOGL_INFO,
"%s Scheduled DL Assignment polling on FN=%d, TS=%d\n",
name(), poll_fn, poll_ts);
"%s Scheduled DL Assignment polling on FN=%d\n",
name(), poll_fn);
} else {
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
new_dl_tbf->set_state(GPRS_RLCMAC_FLOW);
@ -1020,25 +933,25 @@ struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
return msg;
}
struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts)
struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn)
{
struct msgb *msg;
struct gprs_rlcmac_ul_tbf *new_tbf = NULL;
int rc;
unsigned int rrbp;
uint32_t new_poll_fn;
int nbofults = 0, i;
uint16_t new_ws;
if (poll_state == GPRS_RLCMAC_POLL_SCHED &&
ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) {
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for %s, so we must wait for the uplink "
"sheduled for %s, so we must wait for uplink "
"assignment...\n", tbf_name(this));
return NULL;
}
rc = check_polling(fn, ts, &new_poll_fn, &rrbp);
if (rc < 0)
return NULL;
if (bts->sba()->find(trx->trx_no, control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for "
"single block allocation...\n");
return NULL;
}
if (ms())
new_tbf = ms()->ul_tbf();
@ -1050,6 +963,19 @@ struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts)
return NULL;
}
if(is_egprs_enabled()) {
for (i = 0; i < 8; i++) {
if (new_tbf->pdch[i])
nbofults++;
}
new_ws = windowsizebyTS[nbofults];
if (new_ws > (new_tbf->m_window.ws()))
new_tbf->m_window.set_ws(new_ws);
LOGP(DRLCMACDL, LOGL_ERROR, "New Window_size assigned in"
" create_UL_ASS %d\n",new_tbf->m_window.ws());
}
msg = msgb_alloc(23, "rlcmac_ul_ass");
if (!msg)
return NULL;
@ -1063,7 +989,7 @@ struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts)
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
Encoding::write_packet_uplink_assignment(bts_data(), ass_vec, m_tfi,
(direction == GPRS_RLCMAC_DL_TBF), tlli(),
is_tlli_valid(), new_tbf, 1, rrbp, bts_data()->alpha,
is_tlli_valid(), new_tbf, 1, bts_data()->alpha,
bts_data()->gamma, -1, is_egprs_enabled());
bitvec_pack(ass_vec, msgb_put(msg, 23));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
@ -1074,13 +1000,12 @@ struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts)
bitvec_free(ass_vec);
talloc_free(mac_control_block);
set_polling(new_poll_fn, ts);
poll_state = GPRS_RLCMAC_POLL_SCHED;
poll_fn = (fn + 13) % 2715648;
ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK;
if (new_tbf->state_is(GPRS_RLCMAC_ASSIGN))
new_tbf->set_state(GPRS_RLCMAC_WAIT_ASSIGN);
LOGP(DRLCMACDL, LOGL_INFO,
"%s Scheduled UL Assignment polling on FN=%d, TS=%d\n",
name(), poll_fn, poll_ts);
"%s Scheduled UL Assignment polling on FN=%d\n",
name(), poll_fn);
return msg;
}
@ -1110,11 +1035,9 @@ int gprs_rlcmac_tbf::establish_dl_tbf_on_pacch()
struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
bts->tbf_reused();
new_tbf = tbf_alloc_dl_tbf(bts->bts_data(), ms(),
this->trx->trx_no, ms_class(),
ms() ? ms()->egprs_ms_class() : 0, 0);
if (!new_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
return -1;
@ -1126,7 +1049,6 @@ int gprs_rlcmac_tbf::establish_dl_tbf_on_pacch()
return 0;
}
int gprs_rlcmac_tbf::set_tlli_from_ul(uint32_t new_tlli)
{
struct gprs_rlcmac_tbf *dl_tbf = NULL;
@ -1145,8 +1067,15 @@ int gprs_rlcmac_tbf::set_tlli_from_ul(uint32_t new_tlli)
if (!ms())
set_ms(old_ms);
/* there might be an active and valid downlink TBF */
if (!ms()->dl_tbf() && dl_tbf)
/* Move it to the current MS (see the guard above) */
dl_tbf->set_ms(ms());
}
/* The TLLI has been taken from an UL message */
update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
if (dl_tbf && dl_tbf->ms() != ms()) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still exists. "
@ -1163,17 +1092,36 @@ int gprs_rlcmac_tbf::set_tlli_from_ul(uint32_t new_tlli)
tbf_free(ul_tbf);
ul_tbf = NULL;
}
/* The TLLI has been taken from an UL message */
update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
#if 0 /* REMOVEME ??? */
if (ms()->need_dl_tbf())
establish_dl_tbf_on_pacch();
#endif
return 1;
}
int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
{
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
uint32_t new_tlli;
int rc;
OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
/* no TLLI yet */
if (!rh->ti) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d without "
"TLLI, but no TLLI received yet\n", rh->tfi);
return 0;
}
rc = Decoding::tlli_from_ul_data(data, len, &new_tlli);
if (rc) {
bts->decode_error();
LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
"of UL DATA TFI=%d.\n", rh->tfi);
return 0;
}
LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
"UL DATA TFI=%d.\n", new_tlli, rh->tfi);
return set_tlli_from_ul(new_tlli);
}
const char *tbf_name(gprs_rlcmac_tbf *tbf)
{
return tbf->name();
@ -1197,11 +1145,11 @@ const char *gprs_rlcmac_tbf::name() const
void gprs_rlcmac_tbf::rotate_in_list()
{
llist_del(&list());
llist_del(&list.list);
if (direction == GPRS_RLCMAC_UL_TBF)
llist_add(&list(), &bts->ul_tbfs());
llist_add(&list.list, &bts->bts_data()->ul_tbfs);
else
llist_add(&list(), &bts->dl_tbfs());
llist_add(&list.list, &bts->bts_data()->dl_tbfs);
}
uint8_t gprs_rlcmac_tbf::tsc() const
@ -1209,6 +1157,8 @@ uint8_t gprs_rlcmac_tbf::tsc() const
return trx->pdch[first_ts].tsc;
}
uint8_t gprs_rlcmac_tbf::dl_slots() const
{
uint8_t slots = 0;
@ -1245,7 +1195,24 @@ uint8_t gprs_rlcmac_tbf::ul_slots() const
return slots;
}
bool gprs_rlcmac_tbf::is_control_ts(uint8_t ts) const
void tbf_print_vty_info(struct vty *vty, struct llist_head *ltbf)
{
return ts == control_ts;
gprs_rlcmac_tbf *tbf = llist_pods_entry(ltbf, gprs_rlcmac_tbf);
vty_out(vty, "TBF: TFI=%d TLLI=0x%08x (%s) DIR=%s IMSI=%s%s", tbf->tfi(),
tbf->tlli(), tbf->is_tlli_valid() ? "valid" : "invalid",
tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
tbf->imsi(), VTY_NEWLINE);
vty_out(vty, " created=%lu state=%08x 1st_TS=%d 1st_cTS=%d ctrl_TS=%d "
"MS_CLASS=%d%s",
tbf->created_ts(), tbf->state_flags, tbf->first_ts,
tbf->first_common_ts, tbf->control_ts, tbf->ms_class(),
VTY_NEWLINE);
vty_out(vty, " TS_alloc=");
for (int i = 0; i < 8; i++) {
if (tbf->pdch[i])
vty_out(vty, "%d ", i);
}
vty_out(vty, " CS=%d%s%s", tbf->ms() ? tbf->ms()->current_cs_dl() : 1,
VTY_NEWLINE, VTY_NEWLINE);
}

220
src/tbf.h
View File

@ -41,10 +41,18 @@ class GprsMs;
#define Tassign_agch 0,200000 /* waiting after IMM.ASS confirm */
#define Tassign_pacch 2,0 /* timeout for pacch assigment */
#define EGPRS_TYPE1_HDR_SIZE 0x05
#define EGPRS_TYPE2_HDR_SIZE 0x04
#define EGPRS_TYPE3_HDR_SIZE 0x04
/* defines for header types */
#define EGPRS_HDR_TYPE1 0x0
#define EGPRS_HDR_TYPE2 0x1
#define EGPRS_HDR_TYPE3 0x2
enum gprs_rlcmac_tbf_state {
GPRS_RLCMAC_NULL = 0, /* new created TBF */
GPRS_RLCMAC_ASSIGN, /* wait for DL transmission */
GPRS_RLCMAC_WAIT_ASSIGN,/* wait for confirmation */
GPRS_RLCMAC_ASSIGN, /* wait for downlink assignment */
GPRS_RLCMAC_FLOW, /* RLC/MAC flow, resource needed */
GPRS_RLCMAC_FINISHED, /* flow finished, wait for release */
GPRS_RLCMAC_WAIT_RELEASE,/* wait for release or restart of DL TBF */
@ -89,6 +97,28 @@ enum gprs_rlcmac_tbf_direction {
#define GPRS_RLCMAC_FLAG_TO_DL_ASS 7
#define GPRS_RLCMAC_FLAG_TO_MASK 0xf0 /* timeout bits */
struct llist_pods {
struct llist_head list;
void *back;
};
#define llist_pods_entry(ptr, type) \
((type *)(container_of(ptr, struct llist_pods, list)->back))
/**
* llist_pods_for_each_entry - like llist_for_each_entry, but uses
* struct llist_pods ->back to access the entry.
* This is necessary for non-PODS classes because container_of is
* not guaranteed to work anymore. */
#define llist_pods_for_each_entry(pos, head, member, lpods) \
for (lpods = llist_entry((head)->next, typeof(struct llist_pods), list), \
pos = ((typeof(pos))lpods->back), \
prefetch(pos->member.list.next); \
&lpods->list != (head); \
lpods = llist_entry(lpods->list.next, typeof(struct llist_pods), list), \
pos = ((typeof(pos))lpods->back),\
prefetch(pos->member.list.next))
struct gprs_rlcmac_tbf {
gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir);
@ -102,14 +132,12 @@ struct gprs_rlcmac_tbf {
const char *name() const;
struct msgb *create_dl_ass(uint32_t fn, uint8_t ts);
struct msgb *create_ul_ass(uint32_t fn, uint8_t ts);
struct msgb *create_dl_ass(uint32_t fn);
struct msgb *create_ul_ass(uint32_t fn);
GprsMs *ms() const;
void set_ms(GprsMs *ms);
gprs_rlc_window *window();
uint8_t tsc() const;
int rlcmac_diag();
@ -120,9 +148,6 @@ struct gprs_rlcmac_tbf {
void stop_t3191();
int establish_dl_tbf_on_pacch();
int check_polling(uint32_t fn, uint8_t ts,
uint32_t *poll_fn, unsigned int *rrbp);
void set_polling(uint32_t poll_fn, uint8_t ts);
void poll_timeout();
/** tlli handling */
@ -133,7 +158,6 @@ struct gprs_rlcmac_tbf {
void update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction);
uint8_t tfi() const;
bool is_tfi_assigned() const;
const char *imsi() const;
void assign_imsi(const char *imsi);
@ -141,20 +165,17 @@ struct gprs_rlcmac_tbf {
void set_ta(uint8_t);
uint8_t ms_class() const;
void set_ms_class(uint8_t);
GprsCodingScheme current_cs() const;
uint8_t current_cs() const;
gprs_llc_queue *llc_queue();
const gprs_llc_queue *llc_queue() const;
time_t created_ts() const;
uint8_t dl_slots() const;
uint8_t ul_slots() const;
bool is_control_ts(uint8_t ts) const;
/* EGPRS */
bool is_egprs_enabled() const;
void enable_egprs();
void disable_egprs();
/* EGPRS */
bool is_egprs_enabled() const;
void enable_egprs();
void disable_egprs();
/* attempt to make things a bit more fair */
void rotate_in_list();
@ -162,9 +183,7 @@ struct gprs_rlcmac_tbf {
LListHead<gprs_rlcmac_tbf>& ms_list() {return this->m_ms_list;}
const LListHead<gprs_rlcmac_tbf>& ms_list() const {return this->m_ms_list;}
LListHead<gprs_rlcmac_tbf>& list();
const LListHead<gprs_rlcmac_tbf>& list() const;
struct llist_pods list;
uint32_t state_flags;
enum gprs_rlcmac_tbf_direction direction;
struct gprs_rlcmac_trx *trx;
@ -182,7 +201,6 @@ struct gprs_rlcmac_tbf {
enum gprs_rlcmac_tbf_poll_state poll_state;
uint32_t poll_fn; /* frame number to poll */
uint8_t poll_ts; /* TS to poll */
gprs_rlc m_rlc;
@ -228,10 +246,11 @@ struct gprs_rlcmac_tbf {
protected:
gprs_rlcmac_bts *bts_data() const;
int extract_tlli(const uint8_t *data, const size_t len);
int set_tlli_from_ul(uint32_t new_tlli);
void merge_and_clear_ms(GprsMs *old_ms);
static const char *tbf_state_name[7];
static const char *tbf_state_name[6];
class GprsMs *m_ms;
@ -240,10 +259,8 @@ protected:
uint8_t m_ms_class;
private:
LListHead<gprs_rlcmac_tbf> m_list;
LListHead<gprs_rlcmac_tbf> m_ms_list;
bool m_egprs_enabled;
bool m_egprs_enabled;
mutable char m_name_buf[60];
};
@ -255,7 +272,6 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
GprsMs *ms, int8_t use_trx,
uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot);
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
GprsMs *ms, int8_t use_trx,
uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot);
@ -292,16 +308,6 @@ inline void gprs_rlcmac_tbf::set_state(enum gprs_rlcmac_tbf_state new_state)
state = new_state;
}
inline LListHead<gprs_rlcmac_tbf>& gprs_rlcmac_tbf::list()
{
return this->m_list;
}
inline const LListHead<gprs_rlcmac_tbf>& gprs_rlcmac_tbf::list() const
{
return this->m_list;
}
inline GprsMs *gprs_rlcmac_tbf::ms() const
{
return m_ms;
@ -312,13 +318,6 @@ inline bool gprs_rlcmac_tbf::is_tlli_valid() const
return tlli() != 0;
}
inline bool gprs_rlcmac_tbf::is_tfi_assigned() const
{
/* The TBF is established or has been assigned by a IMM.ASS for
* download */
return state > GPRS_RLCMAC_ASSIGN;
}
inline uint8_t gprs_rlcmac_tbf::tfi() const
{
return m_tfi;
@ -330,39 +329,62 @@ inline time_t gprs_rlcmac_tbf::created_ts() const
}
inline bool gprs_rlcmac_tbf::is_egprs_enabled() const
{
return m_egprs_enabled;
}
{
return m_egprs_enabled;
}
inline void gprs_rlcmac_tbf::enable_egprs()
{
m_egprs_enabled = true;
m_egprs_enabled = true;
}
inline void gprs_rlcmac_tbf::disable_egprs()
{
m_egprs_enabled = false;
m_egprs_enabled = false;
}
struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
gprs_rlcmac_dl_tbf(BTS *bts);
void cleanup();
/* dispatch Unitdata.DL messages */
static int handle(struct gprs_rlcmac_bts *bts,
const uint32_t tlli, const uint32_t old_tlli,
const char *imsi, const uint8_t ms_class,
const uint8_t egprs_ms_class, const uint16_t delay_csec,
const uint8_t *data, const uint16_t len);
static int handle(struct gprs_rlcmac_bts *bts,
const uint32_t tlli, const uint32_t tlli_old, const char *imsi,
const uint8_t ms_class, const uint8_t egprs_ms_class,
const uint16_t delay_csec,
const uint8_t *data, const uint16_t len);
int append_data(const uint8_t ms_class,
const uint16_t pdu_delay_csec,
const uint8_t *data, const uint16_t len);
int rcvd_dl_ack(uint8_t final, uint8_t ssn, uint8_t *rbb);
int rcvd_dl_ack(uint8_t final_ack, unsigned first_bsn, struct bitvec *rbb);
int rcvd_egprs_dl_ack(EGPRS_AckNack_Desc_t *Egprs_Desc, int16_t len);
struct msgb *create_dl_acked_block(uint32_t fn, uint8_t ts);
struct msgb *create_new_bsn_mcs1_mcs4(uint32_t fn, uint8_t ts, GprsCodingScheme *cs);
struct msgb *create_new_bsn_mcs5_mcs6(uint32_t fn, uint8_t ts, GprsCodingScheme *cs);
struct msgb *create_new_bsn_mcs7_mcs9(uint32_t fn, uint8_t ts, GprsCodingScheme *cs);
struct msgb *egprs_resegment_block(GprsCodingScheme *original_mcs,GprsCodingScheme *retx_mcs,
struct gprs_rlc_data *block);
struct msgb *egprs_handle_second_reseg_block(struct gprs_rlc_data *block);
struct msgb *egprs_resegment_mcs8_block(GprsCodingScheme *original_mcs,
GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
struct msgb *egprs_handle_initialmcs_retxmcs_same(struct gprs_rlc_data *rlc_data,
struct egprs_mcs_ps *retx_mcs_ps, const int index);
struct msgb *egprs_resegment_mcs8_to_mcs6(GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
struct msgb *egprs_resegment_mcs8_to_mcs3(GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
struct msgb *egprs_resegment_mcs8_to_mcs6_to_mcs3(GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
struct msgb *egprs_resegment_block_type3_type3( GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
struct msgb * egprs_resegment_block_type2_type3( GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
struct msgb * egprs_resegment_block_type1_type2( GprsCodingScheme *original_mcs,GprsCodingScheme *retx_mcs,
struct gprs_rlc_data *block);
struct msgb * egprs_resegment_block_type1_type3( GprsCodingScheme *retx_mcs,struct gprs_rlc_data *block);
void request_dl_ack();
bool need_control_ts() const;
bool have_data() const;
@ -370,7 +392,10 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
int frames_since_last_drain(unsigned fn) const;
bool keep_open(unsigned fn) const;
int release();
int abort();
bool is_control_ts(uint8_t ts) const {
return ts == control_ts;
}
/* TODO: add the gettimeofday as parameter */
struct msgb *llc_dequeue(bssgp_bvc_ctx *bctx);
@ -406,34 +431,47 @@ protected:
unsigned lost_bytes;
};
int take_next_bsn(uint32_t fn, int previous_bsn,
bool *may_combine);
bool restart_bsn_cycle();
int create_new_bsn(const uint32_t fn, GprsCodingScheme cs);
struct msgb *create_new_bsn(const uint32_t fn, const uint8_t ts);
int create_new_bsn_egprs( uint8_t* dataBlkPtr, uint32_t bytesToCpy, bool * fblksent, uint32_t fn);
void fill_polling(const uint32_t fn, const uint8_t ts,
const int index, uint8_t *rh);
void egprs_get_dl_retx_mcs( gprs_rlc_data *rlc_data, struct egprs_mcs_ps* reTxMcsPs);
void egprs_header_cps_update( gprs_rlc_data *rlc_data,struct egprs_mcs_ps* mcsPs, const int index);
void egprs_inc_ps(uint8_t mcs, uint8_t lastPs, uint8_t *nextPs);
void egprs_get_ps( gprs_rlc_data *rlc_data, struct egprs_ps_sel_tbl *ps);
struct msgb *create_dl_acked_block(const uint32_t fn, const uint8_t ts,
int index, int index2 = -1);
const int index);
struct msgb *create_dl_acked_block_resend_egprs(const uint32_t fn, const uint8_t ts,
const int index);
int update_window(const uint8_t ssn, const uint8_t *rbb);
int update_window(unsigned first_bsn, const struct bitvec *rbb);
int update_egprs_window(EGPRS_AckNack_Desc_t *Egprs_Desc, int16_t len);
int maybe_start_new_window();
bool dl_window_stalled() const;
void reuse_tbf();
void start_llc_timer();
int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res);
void schedule_next_frame();
void fill_hdr_type3(uint8_t *hdr_ptr, GprsCodingScheme *cs);
void fill_hdr_type2(uint8_t *hdr_ptr, GprsCodingScheme *cs);
void fill_hdr_type1(uint8_t *hdr_ptr, GprsCodingScheme *cs);
struct osmo_timer_list m_llc_timer;
};
struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
gprs_rlcmac_ul_tbf(BTS *bts);
struct msgb *create_ul_ack(uint32_t fn, uint8_t ts);
struct msgb *create_ul_ack(uint32_t fn);
/* blocks were acked */
int rcv_data_block_acknowledged(
const struct gprs_rlc_data_info *rlc,
uint8_t *data, struct pcu_l1_meas *meas);
const struct gprs_rlc_ul_header_generic *rlc,
uint8_t *data, uint8_t len, struct pcu_l1_meas *meas);
/* In case of re segmentation process the spb values and decides
weather original block is rebuilt
*/
egprs_rlc_ul_reseg_bsn_state assemble_rlc_block_frm_segmented_blks(
const struct gprs_rlc_ul_header_generic *rlc, struct gprs_rlc_data *block,
uint8_t *data, const uint8_t block_idx );
/* TODO: extract LLC class? */
int assemble_forward_llc(const gprs_rlc_data *data);
@ -452,7 +490,7 @@ struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
uint8_t m_final_ack_sent; /* set if we sent final ack */
protected:
void maybe_schedule_uplink_acknack(const gprs_rlc_data_info *rlc);
void maybe_schedule_uplink_acknack(const gprs_rlc_ul_header_generic *rlc);
};
inline enum gprs_rlcmac_tbf_direction reverse(enum gprs_rlcmac_tbf_direction dir)
@ -460,31 +498,15 @@ inline enum gprs_rlcmac_tbf_direction reverse(enum gprs_rlcmac_tbf_direction dir
return (enum gprs_rlcmac_tbf_direction)
((int)GPRS_RLCMAC_UL_TBF - (int)dir + (int)GPRS_RLCMAC_DL_TBF);
}
inline gprs_rlcmac_ul_tbf *as_ul_tbf(gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
return static_cast<gprs_rlcmac_ul_tbf *>(tbf);
else
return NULL;
}
inline gprs_rlcmac_dl_tbf *as_dl_tbf(gprs_rlcmac_tbf *tbf)
{
if (tbf && tbf->direction == GPRS_RLCMAC_DL_TBF)
return static_cast<gprs_rlcmac_dl_tbf *>(tbf);
else
return NULL;
}
inline gprs_rlc_window *gprs_rlcmac_tbf::window()
{
switch (direction)
{
case GPRS_RLCMAC_UL_TBF: return &as_ul_tbf(this)->m_window;
case GPRS_RLCMAC_DL_TBF: return &as_dl_tbf(this)->m_window;
}
return NULL;
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
void tbf_print_vty_info(struct vty *vty, struct llist_head *tbf);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -42,15 +42,16 @@ extern "C" {
extern void *tall_pcu_ctx;
/*
* Store received block data in LLC message(s) and forward to SGSN
* if complete.
*/
int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
{
const uint8_t *data = _data->block;
uint8_t len = _data->len;
const struct gprs_rlc_data_block_info *rdbi = &_data->block_info;
const uint8_t *data = _data->complete_blk;
uint8_t len = _data->completed_block_len;
const struct gprs_rlc_ul_data_block_info *rdbi = &_data->block_info;
GprsCodingScheme cs = _data->cs;
Decoding::RlcData frames[16], *frame;
@ -87,48 +88,49 @@ int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
}
struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn, uint8_t ts)
struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn)
{
int final = (state_is(GPRS_RLCMAC_FINISHED));
struct msgb *msg;
int rc;
unsigned int rrbp = 0;
uint32_t new_poll_fn = 0;
if (final) {
if (poll_state == GPRS_RLCMAC_POLL_SCHED &&
ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) {
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for %s, so we must wait for "
"the final uplink ack...\n", tbf_name(this));
"sheduled for %s, so we must wait for "
"final uplink ack...\n", tbf_name(this));
return NULL;
}
rc = check_polling(fn, ts, &new_poll_fn, &rrbp);
if (rc < 0)
if (bts->sba()->find(trx->trx_no, control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for single block allocation...\n");
return NULL;
}
}
msg = msgb_alloc(23, "rlcmac_ul_ack");
if (!msg)
return NULL;
bitvec *ack_vec = bitvec_alloc(23);
if (!ack_vec) {
msgb_free(msg);
return NULL;
}
bitvec_unhex(ack_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
Encoding::write_packet_uplink_ack(bts_data(), ack_vec, this, final, rrbp);
Encoding::write_packet_uplink_ack(bts_data(), ack_vec, this, final);
bitvec_pack(ack_vec, msgb_put(msg, 23));
bitvec_free(ack_vec);
/* now we must set this flag, so we are allowed to assign downlink
* TBF on PACCH. it is only allowed when TLLI is acknowledged. */
m_contention_resolution_done = 1;
if (final) {
set_polling(new_poll_fn, ts);
poll_state = GPRS_RLCMAC_POLL_SCHED;
poll_fn = (fn + 13) % 2715648;
/* waiting for final acknowledge */
ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK;
m_final_ack_sent = 1;
@ -138,13 +140,81 @@ struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn, uint8_t ts)
return msg;
}
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::assemble_rlc_block_frm_segmented_blks(
const struct gprs_rlc_ul_header_generic *rlc, struct gprs_rlc_data *block,
uint8_t *data, const uint8_t block_idx )
{
const struct gprs_rlc_ul_data_block_info *rdbi =
&rlc->block_info[block_idx];
uint8_t *rlc_data = 0;
if(rdbi->spb == 2){
rlc_data = &(block->complete_blk[0]);
block->completed_block_len = rlc->block_info[block_idx].data_len ;
memcpy(rlc_data, data + rlc->data_offs_bytes[block_idx],
rlc->block_info[block_idx].data_len);
if(block->block_status_ul & EGPRS_RESEG_SECOND_BLOCK_RXD){
LOGP(DRLCMACUL, LOGL_DEBUG,
" first part is received"
" second part is already present set the status to complete\n");
block->block_status_ul = EGPRS_RESEG_DEFAULT;
block->completed_block_len += Decoding::rlc_copy_to_aligned_buffer(rlc, block_idx, data,
rlc_data);
/* Assembling the resegmented split blocks */
memcpy(rlc_data + block->completed_block_len, &(block->block2[0]), block->len_block2);
block->completed_block_len +=block->len_block2;
}else{
LOGP(DRLCMACUL, LOGL_DEBUG,
" first part is received"
" second part is not received set the status to first block received\n");
block->block_status_ul = EGPRS_RESEG_FIRST_BLOCK_RXD;
return EGPRS_RESEG_FIRST_BLOCK_RXD;
}
}else if(rdbi->spb == 3){
rlc_data = &(block->block2[0]);
block->len_block2 = Decoding::rlc_copy_to_aligned_buffer(rlc, block_idx, data,
rlc_data);
if(block->block_status_ul & EGPRS_RESEG_FIRST_BLOCK_RXD){
LOGP(DRLCMACUL, LOGL_DEBUG,
" second part is received"
" first part is already present set the status to complete\n");
block->block_status_ul = EGPRS_RESEG_DEFAULT;
memcpy( &(block->complete_blk[0]) + block->completed_block_len, rlc_data, block->len_block2);
block->completed_block_len += block->len_block2;
}else{
LOGP(DRLCMACUL, LOGL_DEBUG,
" second part is received"
" first part is not received set the status to second block received\n");
block->block_status_ul = EGPRS_RESEG_SECOND_BLOCK_RXD;
return EGPRS_RESEG_SECOND_BLOCK_RXD;
}
}else{
LOGP(DRLCMACUL, LOGL_ERROR ,
" Not supported SPB for this EGPRS configuration \n");
OSMO_ASSERT(true);
}
return EGPRS_RESEG_DEFAULT;
}
int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
const struct gprs_rlc_data_info *rlc,
uint8_t *data, struct pcu_l1_meas *meas)
const struct gprs_rlc_ul_header_generic *rlc,
uint8_t *data, uint8_t len, struct pcu_l1_meas *meas)
{
int8_t rssi = meas->have_rssi ? meas->rssi : 0;
const uint16_t ws = m_window.ws();
egprs_rlc_ul_reseg_bsn_state re_assemble_status;
this->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
@ -172,7 +242,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
for (block_idx = 0; block_idx < rlc->num_data_blocks; block_idx++) {
int num_chunks;
uint8_t *rlc_data;
const struct gprs_rlc_data_block_info *rdbi =
const struct gprs_rlc_ul_data_block_info *rdbi =
&rlc->block_info[block_idx];
bool need_rlc_data = false;
struct gprs_rlc_data *block;
@ -180,11 +250,11 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
LOGP(DRLCMACUL, LOGL_DEBUG,
"%s: Got %s RLC data block: "
"CV=%d, BSN=%d, SPB=%d, "
"PI=%d, E=%d, TI=%d, bitoffs=%d\n",
"PI=%d, E=%d, TI=%d\n",
name(), rlc->cs.name(),
rdbi->cv, rdbi->bsn, rdbi->spb,
rdbi->pi, rdbi->e, rdbi->ti,
rlc->data_offs_bits[block_idx]);
rdbi->pi, rdbi->e, rdbi->ti
);
/* Check whether the block needs to be decoded */
@ -221,38 +291,39 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
block = m_rlc.block(rdbi->bsn);
block->block_info = *rdbi;
block->cs = rlc->cs;
OSMO_ASSERT(rdbi->data_len < sizeof(block->block));
rlc_data = &(block->block[0]);
/* TODO: Handle SPB != 0 -> Set length to 2*len, add offset if
* 2nd part. Note that resegmentation is currently disabled
* within the UL assignment.
*/
OSMO_ASSERT(rdbi->data_len < sizeof(block->complete_blk));
rlc_data = &(block->complete_blk[0]);
if (rdbi->spb) {
LOGP(DRLCMACUL, LOGL_NOTICE,
"Got SPB != 0 but resegmentation has been "
"disabled, skipping %s data block with BSN %d, "
"TFI=%d.\n", rlc->cs.name(), rdbi->bsn,
"Got SPB(%d) "
"cs(%s) data block with BSN (%d), "
"TFI(%d).\n",rdbi->spb, rlc->cs.name(), rdbi->bsn,
rlc->tfi);
continue;
re_assemble_status = this->assemble_rlc_block_frm_segmented_blks(rlc, block, data , block_idx);
if(EGPRS_RESEG_DEFAULT != re_assemble_status){
continue;
}
}else{
block->completed_block_len = rlc->block_info[block_idx].data_len ;
block->block_status_ul = EGPRS_RESEG_DEFAULT;
memcpy(rlc_data, data + rlc->data_offs_bytes[block_idx] ,
rlc->block_info[block_idx].data_len);
}
block->len =
Decoding::rlc_copy_to_aligned_buffer(rlc, block_idx, data,
rlc_data);
LOGP(DRLCMACUL, LOGL_DEBUG,
"%s: data_length=%d, data=%s\n",
name(), block->len, osmo_hexdump(rlc_data, block->len));
/* TODO: Handle SPB != 0 -> set state to partly received
* (upper/lower) and continue with the loop, unless the other
* part is already present.
*/
name(), block->completed_block_len, osmo_hexdump(rlc_data, block->completed_block_len));
/* Get/Handle TLLI */
if (rdbi->ti) {
num_chunks = Decoding::rlc_data_from_ul_data(
rdbi, rlc->cs, rlc_data, NULL, 0, &new_tlli);
&block->block_info, rlc->cs, rlc_data, NULL, 0, &new_tlli);
if (num_chunks < 0) {
bts->decode_error();
@ -303,7 +374,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
&& this->m_window.v_q() == this->m_window.v_r()) { /* if complete */
struct gprs_rlc_data *block =
m_rlc.block(m_window.mod_sns(m_window.v_r() - 1));
const struct gprs_rlc_data_block_info *rdbi =
const struct gprs_rlc_ul_data_block_info *rdbi =
&block->block_info;
LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, "
@ -323,10 +394,11 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
maybe_schedule_uplink_acknack(rlc);
return 0;
}
void gprs_rlcmac_ul_tbf::maybe_schedule_uplink_acknack(
const gprs_rlc_data_info *rlc)
const gprs_rlc_ul_header_generic *rlc)
{
bool have_ti = rlc->block_info[0].ti ||
(rlc->num_data_blocks > 1 && rlc->block_info[1].ti);

View File

@ -52,23 +52,23 @@ static gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts,
static void check_tfi_usage(BTS *the_bts)
{
int pdch_no;
struct gprs_rlcmac_bts *bts = the_bts->bts_data();
struct gprs_rlcmac_tbf *tfi_usage[8][8][2][32] = {{{{NULL}}}};
LListHead<gprs_rlcmac_tbf> *tbf_lists[2] = {
&the_bts->ul_tbfs(),
&the_bts->dl_tbfs()
struct llist_head *tbf_lists[2] = {
&bts->ul_tbfs,
&bts->dl_tbfs
};
LListHead<gprs_rlcmac_tbf> *pos;
gprs_rlcmac_tbf *tbf;
struct llist_pods *lpods;
unsigned list_idx;
struct gprs_rlcmac_tbf **tbf_var;
for (list_idx = 0; list_idx < ARRAY_SIZE(tbf_lists); list_idx += 1)
{
llist_for_each(pos, tbf_lists[list_idx]) {
tbf = pos->entry();
llist_pods_for_each_entry(tbf, tbf_lists[list_idx], list, lpods) {
for (pdch_no = 0; pdch_no < 8; pdch_no += 1) {
struct gprs_rlcmac_pdch *pdch = tbf->pdch[pdch_no];
if (pdch == NULL)
@ -150,9 +150,9 @@ static void test_alloc_a(gprs_rlcmac_tbf_direction dir,
if (tbfs[i])
tbf_free(tbfs[i]);
tbfs[0] = tbf_alloc(bts, NULL, dir, -1, 0, 0, 0);
OSMO_ASSERT(tbfs[0]);
tbf_free(tbfs[0]);
tbfs[tfi] = tbf_alloc(bts, NULL, dir, -1, 0, 0, 0);
OSMO_ASSERT(tbfs[tfi]);
tbf_free(tbfs[tfi]);
}
static void test_alloc_a()

File diff suppressed because it is too large Load Diff

11321
tests/edge/EdgeTest.err Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,53 @@
=== start test_coding_scheme ===
=== end test_coding_scheme ===
=== start test_rlc_info_init ===
=== end test_rlc_info_init ===
=== start test_rlc_decoder ===
=== end test_rlc_decoder ===
=== start test_spb_handling ===
=== start test__mcs8_retx_mcs6 ===
=== start uplink_header_type1_test ===
=== start test_rlc_unit_decoder ===
=== end test_rlc_unit_decoder ===
=== start test_rlc_unit_encoder ===
=== end test_rlc_unit_encoder ===
=== start test_tbf_two_phase ===
=== end test_tbf_two_phase ===
=== start test_tbf_two_phase_PUAN ===
=== end test_tbf_two_phase_PUAN ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_for_all_mcs ===
=== end test_downlink_for_all_mcs ===
=== start test_downlink_retransmission_mcs6_mcs3 ===
=== end test_downlink_retransmission_mcs6_mcs3 ===
=== start test_downlink_retransmission_mcs5_mcs2 ===
=== end test_downlink_retransmission_mcs5_mcs2 ===
=== start test_downlink_retransmission_mcs4_mcs1 ===
=== end test_downlink_retransmission_mcs4_mcs1 ===
=== start test_downlink_retransmission_mcs7_mcs5 ===
=== end test_downlink_retransmission_mcs7_mcs5 ===
=== start test_downlink_retransmission_mcs8_mcs6 ===
=== end test_downlink_retransmission_mcs8_mcs6 ===
=== start test_downlink_retransmission_mcs9_mcs6 ===
=== end test_downlink_retransmission_mcs9_mcs6 ===
=== start test_downlink_retransmission_mcs9_mcs3 ===
=== end test_downlink_retransmission_mcs9_mcs3 ===
=== start test_downlink_retransmission_mcs8_mcs3 ===
=== end test_downlink_retransmission_mcs8_mcs3 ===
=== start test_downlink_retransmission_mcs7_mcs2 ===
=== end test_downlink_retransmission_mcs7_mcs2 ===
=== start test_downlink_retransmission_mcs8_mcs6_mcs3 ===
=== end test_downlink_retransmission_mcs8_mcs6_mcs3 ===
=== start test_tbf_final_ack_EPDAN ===
=== end test_tbf_final_ack_EPDAN ===

View File

@ -503,11 +503,11 @@ static void test_ms_cs_selection()
dl_tbf->set_ms(ms);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->current_cs_dl().to_num() == 4);
OSMO_ASSERT(ms->current_cs_dl() == 4);
bts->cs_downgrade_threshold = 200;
OSMO_ASSERT(ms->current_cs_dl().to_num() == 3);
OSMO_ASSERT(ms->current_cs_dl() == 3);
talloc_free(dl_tbf);

View File

@ -86,17 +86,15 @@ void testRlcMacDownlink()
{
struct bitvec *resultVector = bitvec_alloc(23);
bitvec_unhex(resultVector, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
std::string testData[] = {
"4e082500e3f1a81d080820800b2b2b2b2b2b2b2b2b2b2b", // Packet Downlink Assignment
"48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Assignment
"48282407a6a07422720100032b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Assignment
"47240c00400000000000000079eb2ac9402b2b2b2b2b2b", // Packet Uplink Ack Nack
"47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b" // Packet Uplink Assignment
"4913e00850884013a8048b2b2b2b2b2b2b2b2b2b2b2b2b"
"412430007fffffffffffffffefd19c7ba12b2b2b2b2b2b"
"41942b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"
};
int testDataSize = sizeof(testData)/sizeof(testData[0]);
cout << " DOWNLINK " << endl;
@ -152,8 +150,8 @@ void testRlcMacUplink()
bitvec_unhex(resultVector, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
std::string testData[] = {
"400e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Dummy Control Block
"400b8020000000000000002480e00b2b2b2b2b2b2b2b2b", // Packet Downlink Ack/Nack
"400e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Dummy Control Block
"400b8020000000000000002480e0032b2b2b2b2b2b2b2b", // Packet Downlink Ack/Nack
"4016713dc094270ca2ae57ef909006aa0fc0001f80222b" // Packet Resource Request
"400a9020000000000000003010012a0800132b2b2b2b2b"
};

View File

@ -7,13 +7,13 @@ vector1 = 4e8250e3f1a81d882080b2b2b2b2b2b2b2b2b2b2b
vector1 = 4e8250e3f1a81d882080b2b2b2b2b2b2b2b2b2b2b
vector2 = 4e8250e3f1a81d882080b2b2b2b2b2b2b2b2b2b2b
vector1 == vector2 : TRUE
vector1 = 4828247a6a074227210b2b2b2b2b2b2b2b2b2b2b2b
vector1 = 4828247a6a07422721032b2b2b2b2b2b2b2b2b2b2b
=========Start DECODE===========
+++++++++Finish DECODE++++++++++
=========Start ENCODE=============
+++++++++Finish ENCODE+++++++++++
vector1 = 4828247a6a074227210b2b2b2b2b2b2b2b2b2b2b2b
vector2 = 4828247a6a074227210b2b2b2b2b2b2b2b2b2b2b2b
vector1 = 4828247a6a07422721032b2b2b2b2b2b2b2b2b2b2b
vector2 = 4828247a6a07422721032b2b2b2b2b2b2b2b2b2b2b
vector1 == vector2 : TRUE
vector1 = 4724c040000000079eb2ac9402b2b2b2b2b2b
=========Start DECODE===========
@ -32,21 +32,21 @@ vector1 = 47283c367513ba33304242b2b2b2b2b2b2b2b2b2b2b2b
vector2 = 47283c367513ba33304242b2b2b2b2b2b2b2b2b2b2b2b
vector1 == vector2 : TRUE
UPLINK
vector1 = 40e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
vector1 = 40e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
=========Start DECODE===========
+++++++++Finish DECODE++++++++++
=========Start ENCODE=============
+++++++++Finish ENCODE+++++++++++
vector1 = 40e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
vector2 = 40e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
vector1 = 40e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
vector2 = 40e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
vector1 == vector2 : TRUE
vector1 = 40b802000000002480e0b2b2b2b2b2b2b2b2b
vector1 = 40b802000000002480e032b2b2b2b2b2b2b2b
=========Start DECODE===========
+++++++++Finish DECODE++++++++++
=========Start ENCODE=============
+++++++++Finish ENCODE+++++++++++
vector1 = 40b802000000002480e0b2b2b2b2b2b2b2b2b
vector2 = 40b802000000002480e0b2b2b2b2b2b2b2b2b
vector1 = 40b802000000002480e032b2b2b2b2b2b2b2b
vector2 = 40b802000000002480e032b2b2b2b2b2b2b2b
vector1 == vector2 : TRUE
vector1 = 4016713dc09427ca2ae57ef90906aafc001f80222b
=========Start DECODE===========

View File

@ -81,8 +81,6 @@ static void test_tbf_tlli_update()
BTS the_bts;
GprsMs *ms, *ms_new;
printf("=== start %s ===\n", __func__);
the_bts.bts_data()->alloc_algorithm = alloc_algorithm_a;
the_bts.bts_data()->trx[0].pdch[2].enable();
the_bts.bts_data()->trx[0].pdch[3].enable();
@ -140,8 +138,6 @@ static void test_tbf_tlli_update()
OSMO_ASSERT(ul_tbf->ta() == 6);
OSMO_ASSERT(dl_tbf->ta() == 6);
printf("=== end %s ===\n", __func__);
}
static uint8_t llc_data[200];
@ -160,13 +156,14 @@ static void setup_bts(BTS *the_bts, uint8_t ts_no, uint8_t cs = 1)
bts->alloc_algorithm = alloc_algorithm_a;
bts->initial_cs_dl = cs;
bts->initial_cs_ul = cs;
bts->egprs_enabled = false;
trx = &bts->trx[0];
trx->pdch[ts_no].enable();
}
static gprs_rlcmac_dl_tbf *create_dl_tbf(BTS *the_bts, uint8_t ms_class,
uint8_t egprs_ms_class, uint8_t *trx_no_)
uint8_t *trx_no_)
{
gprs_rlcmac_bts *bts;
int tfi;
@ -178,7 +175,7 @@ static gprs_rlcmac_dl_tbf *create_dl_tbf(BTS *the_bts, uint8_t ms_class,
tfi = the_bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx_no, -1);
OSMO_ASSERT(tfi >= 0);
dl_tbf = tbf_alloc_dl_tbf(bts, NULL, trx_no, ms_class, egprs_ms_class, 1);
dl_tbf = tbf_alloc_dl_tbf(bts, NULL, trx_no, ms_class, 0, 1);
check_tbf(dl_tbf);
/* "Establish" the DL TBF */
@ -243,13 +240,11 @@ static void test_tbf_final_ack(enum test_tbf_final_ack_mode test_mode)
uint8_t rbb[64/8];
printf("=== start %s ===\n", __func__);
gprs_rlcmac_dl_tbf *dl_tbf;
gprs_rlcmac_tbf *new_tbf;
setup_bts(&the_bts, ts_no);
dl_tbf = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
dl_tbf = create_dl_tbf(&the_bts, ms_class, &trx_no);
dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
ms = dl_tbf->ms();
@ -298,8 +293,6 @@ static void test_tbf_final_ack(enum test_tbf_final_ack_mode test_mode)
tbf_free(new_tbf);
OSMO_ASSERT(ms->dl_tbf() == NULL);
}
printf("=== end %s ===\n", __func__);
}
static void test_tbf_delayed_release()
@ -324,7 +317,7 @@ static void test_tbf_delayed_release()
setup_bts(&the_bts, ts_no);
bts->dl_tbf_idle_msec = 200;
dl_tbf = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
dl_tbf = create_dl_tbf(&the_bts, ms_class, &trx_no);
dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
for (i = 0; i < sizeof(llc_data); i++)
@ -389,8 +382,8 @@ static void test_tbf_imsi()
setup_bts(&the_bts, ts_no);
dl_tbf[0] = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
dl_tbf[1] = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
dl_tbf[0] = create_dl_tbf(&the_bts, ms_class, &trx_no);
dl_tbf[1] = create_dl_tbf(&the_bts, ms_class, &trx_no);
dl_tbf[0]->update_ms(0xf1000001, GPRS_RLCMAC_DL_TBF);
dl_tbf[1]->update_ms(0xf1000002, GPRS_RLCMAC_DL_TBF);
@ -605,7 +598,6 @@ static void send_control_ack(gprs_rlcmac_tbf *tbf)
RlcMacUplink_t ulreq = {0};
OSMO_ASSERT(tbf->poll_fn != 0);
OSMO_ASSERT(tbf->is_control_ts(tbf->poll_ts));
ulreq.u.MESSAGE_TYPE = MT_PACKET_CONTROL_ACK;
Packet_Control_Acknowledgement_t *ctrl_ack =
@ -613,13 +605,13 @@ static void send_control_ack(gprs_rlcmac_tbf *tbf)
ctrl_ack->PayloadType = GPRS_RLCMAC_CONTROL_BLOCK;
ctrl_ack->TLLI = tbf->tlli();
send_ul_mac_block(tbf->bts, tbf->trx->trx_no, tbf->poll_ts,
send_ul_mac_block(tbf->bts, tbf->trx->trx_no, tbf->control_ts,
&ulreq, tbf->poll_fn);
}
static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
uint8_t ms_class, uint8_t egprs_ms_class)
uint8_t ms_class)
{
GprsMs *ms;
uint32_t rach_fn = *fn - 51;
@ -660,14 +652,6 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
MS_RA_capability_value[0].u.Content.Multislot_capability.
GPRS_multislot_class = ms_class;
if (egprs_ms_class) {
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
MS_RA_capability_value[0].u.Content.Multislot_capability.
Exist_EGPRS_multislot_class = 1;
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
MS_RA_capability_value[0].u.Content.Multislot_capability.
EGPRS_multislot_class = ms_class;
}
send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn);
@ -723,8 +707,7 @@ static void send_dl_data(BTS *the_bts, uint32_t tlli, const char *imsi,
}
}
static void transmit_dl_data(BTS *the_bts, uint32_t tlli, uint32_t *fn,
uint8_t slots = 0xff)
static void transmit_dl_data(BTS *the_bts, uint32_t tlli, uint32_t *fn)
{
gprs_rlcmac_dl_tbf *dl_tbf;
GprsMs *ms;
@ -737,13 +720,10 @@ static void transmit_dl_data(BTS *the_bts, uint32_t tlli, uint32_t *fn,
while (dl_tbf->have_data()) {
uint8_t bn = fn2bn(*fn);
for (ts_no = 0 ; ts_no < 8; ts_no += 1) {
if (!(slots & (1 << ts_no)))
continue;
for (ts_no = 0 ; ts_no < 8; ts_no += 1)
gprs_rlcmac_rcv_rts_block(the_bts->bts_data(),
dl_tbf->trx->trx_no, ts_no, 0,
*fn, bn);
}
*fn = fn_add_blocks(*fn, 1);
}
}
@ -790,8 +770,7 @@ static void test_tbf_two_phase()
setup_bts(&the_bts, ts_no, 4);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta, ms_class);
ms = ul_tbf->ms();
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@ -819,8 +798,7 @@ static void test_tbf_ra_update_rach()
setup_bts(&the_bts, ts_no, 4);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
ms1 = ul_tbf->ms();
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@ -841,8 +819,7 @@ static void test_tbf_ra_update_rach()
OSMO_ASSERT(ms1->llc_queue()->size() == 0);
/* Now establish a new TBF for the RA UPDATE COMPLETE (new TLLI) */
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli2, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli2, &fn, qta, ms_class);
ms2 = ul_tbf->ms();
@ -887,8 +864,7 @@ static void test_tbf_dl_flow_and_rach_two_phase()
setup_bts(&the_bts, ts_no, 1);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
ms1 = ul_tbf->ms();
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@ -908,8 +884,7 @@ static void test_tbf_dl_flow_and_rach_two_phase()
OSMO_ASSERT(ms1 == ms);
/* Now establish a new UL TBF, this will consume one LLC packet */
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
ms2 = ul_tbf->ms();
fprintf(stderr, "New MS: TLLI = 0x%08x, TA = %d, IMSI = %s, LLC = %d\n",
@ -948,8 +923,7 @@ static void test_tbf_dl_flow_and_rach_single_phase()
setup_bts(&the_bts, ts_no, 1);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
ms1 = ul_tbf->ms();
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@ -982,8 +956,9 @@ static void test_tbf_dl_flow_and_rach_single_phase()
OSMO_ASSERT(ms2 == ms);
OSMO_ASSERT(ms1 != ms);
/* DL TBF should be removed */
OSMO_ASSERT(!ms->dl_tbf());
/* DL TBF should be the same */
OSMO_ASSERT(ms->dl_tbf());
OSMO_ASSERT(ms->dl_tbf() == dl_tbf);
/* No queued packets should be lost */
OSMO_ASSERT(ms->llc_queue()->size() == 2);
@ -1010,8 +985,7 @@ static void test_tbf_dl_reuse()
setup_bts(&the_bts, ts_no, 1);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
ms_class, 0);
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
ms1 = ul_tbf->ms();
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@ -1063,7 +1037,7 @@ static void test_tbf_dl_reuse()
ack->DOWNLINK_TFI = dl_tbf1->tfi();
ack->Ack_Nack_Description.FINAL_ACK_INDICATION = 1;
send_ul_mac_block(&the_bts, 0, dl_tbf1->poll_ts, &ulreq, dl_tbf1->poll_fn);
send_ul_mac_block(&the_bts, 0, ts_no, &ulreq, dl_tbf1->poll_fn);
OSMO_ASSERT(dl_tbf1->state_is(GPRS_RLCMAC_WAIT_RELEASE));
@ -1072,7 +1046,7 @@ static void test_tbf_dl_reuse()
ms2 = the_bts.ms_by_tlli(tlli1);
OSMO_ASSERT(ms2 == ms1);
OSMO_ASSERT(ms2->dl_tbf());
OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_WAIT_ASSIGN));
OSMO_ASSERT(ms2->dl_tbf()->state_is(GPRS_RLCMAC_ASSIGN));
dl_tbf2 = ms2->dl_tbf();
@ -1090,210 +1064,6 @@ static void test_tbf_dl_reuse()
printf("=== end %s ===\n", __func__);
}
static void test_tbf_gprs_egprs()
{
BTS the_bts;
gprs_rlcmac_bts *bts;
uint8_t ts_no = 4;
uint8_t ms_class = 45;
int rc = 0;
uint32_t tlli = 0xc0006789;
const char *imsi = "001001123456789";
unsigned delay_csec = 1000;
uint8_t buf[256] = {0};
printf("=== start %s ===\n", __func__);
bts = the_bts.bts_data();
setup_bts(&the_bts, ts_no);
/* EGPRS-only */
bts->egprs_enabled = 1;
gprs_bssgp_create_and_connect(bts, 33001, 0, 33001,
1234, 1234, 1234, 1, 1, 0, 0, 0);
/* Does not support EGPRS */
rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class, 0,
delay_csec, buf, sizeof(buf));
OSMO_ASSERT(rc == -EBUSY);
printf("=== end %s ===\n", __func__);
gprs_bssgp_destroy();
}
static void test_tbf_ws()
{
BTS the_bts;
gprs_rlcmac_bts *bts;
uint8_t ts_no = 4;
uint8_t ms_class = 12;
gprs_rlcmac_dl_tbf *dl_tbf;
printf("=== start %s ===\n", __func__);
bts = the_bts.bts_data();
setup_bts(&the_bts, ts_no);
bts->ws_base = 128;
bts->ws_pdch = 64;
bts->alloc_algorithm = alloc_algorithm_b;
bts->trx[0].pdch[2].enable();
bts->trx[0].pdch[3].enable();
bts->trx[0].pdch[4].enable();
bts->trx[0].pdch[5].enable();
gprs_bssgp_create_and_connect(bts, 33001, 0, 33001,
1234, 1234, 1234, 1, 1, 0, 0, 0);
/* Does no support EGPRS */
dl_tbf = tbf_alloc_dl_tbf(bts, NULL, 0, ms_class, 0, 0);
OSMO_ASSERT(dl_tbf != NULL);
fprintf(stderr, "DL TBF slots: 0x%02x, N: %d, WS: %d\n",
dl_tbf->dl_slots(),
pcu_bitcount(dl_tbf->dl_slots()),
dl_tbf->window()->ws());
OSMO_ASSERT(pcu_bitcount(dl_tbf->dl_slots()) == 4);
OSMO_ASSERT(dl_tbf->window()->ws() == 64);
tbf_free(dl_tbf);
/* EGPRS-only */
bts->egprs_enabled = 1;
/* Does support EGPRS */
dl_tbf = tbf_alloc_dl_tbf(bts, NULL, 0, ms_class, ms_class, 0);
OSMO_ASSERT(dl_tbf != NULL);
fprintf(stderr, "DL TBF slots: 0x%02x, N: %d, WS: %d\n",
dl_tbf->dl_slots(),
pcu_bitcount(dl_tbf->dl_slots()),
dl_tbf->window()->ws());
OSMO_ASSERT(pcu_bitcount(dl_tbf->dl_slots()) == 4);
OSMO_ASSERT(dl_tbf->window()->ws() == 128 + 4 * 64);
tbf_free(dl_tbf);
printf("=== end %s ===\n", __func__);
gprs_bssgp_destroy();
}
static void test_tbf_egprs_two_phase()
{
BTS the_bts;
int ts_no = 7;
uint32_t fn = 2654218;
uint16_t qta = 31;
uint32_t tlli = 0xf1223344;
const char *imsi = "0011223344";
uint8_t ms_class = 1;
uint8_t egprs_ms_class = 1;
gprs_rlcmac_ul_tbf *ul_tbf;
GprsMs *ms;
uint8_t test_data[256];
printf("=== start %s ===\n", __func__);
memset(test_data, 1, sizeof(test_data));
setup_bts(&the_bts, ts_no, 4);
the_bts.bts_data()->initial_mcs_dl = 9;
the_bts.bts_data()->egprs_enabled = 1;
ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta,
ms_class, egprs_ms_class);
ms = ul_tbf->ms();
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta());
send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data));
printf("=== end %s ===\n", __func__);
}
static void establish_and_use_egprs_dl_tbf(BTS *the_bts, int mcs)
{
unsigned i;
uint8_t ms_class = 11;
uint8_t egprs_ms_class = 11;
uint32_t fn = 0;
uint8_t trx_no;
uint32_t tlli = 0xffeeddcc;
uint8_t test_data[512];
uint8_t rbb[64/8];
gprs_rlcmac_dl_tbf *dl_tbf;
printf("Testing MCS-%d\n", mcs);
memset(test_data, 1, sizeof(test_data));
the_bts->bts_data()->initial_mcs_dl = mcs;
dl_tbf = create_dl_tbf(the_bts, ms_class, egprs_ms_class, &trx_no);
dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
for (i = 0; i < sizeof(llc_data); i++)
llc_data[i] = i%256;
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
/* Schedule a small LLC frame */
dl_tbf->append_data(ms_class, 1000, test_data, 10);
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
/* Drain the queue */
while (dl_tbf->have_data())
/* Request to send one RLC/MAC block */
request_dl_rlc_block(dl_tbf, &fn);
/* Schedule a large LLC frame */
dl_tbf->append_data(ms_class, 1000, test_data, sizeof(test_data));
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
/* Drain the queue */
while (dl_tbf->have_data())
/* Request to send one RLC/MAC block */
request_dl_rlc_block(dl_tbf, &fn);
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
/* Receive a final ACK */
dl_tbf->rcvd_dl_ack(1, dl_tbf->m_window.v_s(), rbb);
/* Clean up and ensure tbfs are in the correct state */
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE));
dl_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
check_tbf(dl_tbf);
tbf_free(dl_tbf);
}
static void test_tbf_egprs_dl()
{
BTS the_bts;
gprs_rlcmac_bts *bts;
uint8_t ts_no = 4;
int i;
printf("=== start %s ===\n", __func__);
bts = the_bts.bts_data();
setup_bts(&the_bts, ts_no);
bts->dl_tbf_idle_msec = 200;
bts->egprs_enabled = 1;
for (i = 1; i <= 9; i++)
establish_and_use_egprs_dl_tbf(&the_bts, i);
printf("=== end %s ===\n", __func__);
}
static const struct log_info_cat default_categories[] = {
{"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0},
@ -1352,11 +1122,6 @@ int main(int argc, char **argv)
test_tbf_dl_flow_and_rach_two_phase();
test_tbf_dl_flow_and_rach_single_phase();
test_tbf_dl_reuse();
test_tbf_gprs_egprs();
test_tbf_ws();
test_tbf_egprs_two_phase();
test_tbf_egprs_dl();
if (getenv("TALLOC_REPORT_FULL"))
talloc_report_full(tall_pcu_ctx, stderr);
return EXIT_SUCCESS;

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,5 @@
=== start test_tbf_base ===
=== end test_tbf_base ===
=== start test_tbf_tlli_update ===
=== end test_tbf_tlli_update ===
=== start test_tbf_final_ack ===
=== end test_tbf_final_ack ===
=== start test_tbf_final_ack ===
=== end test_tbf_final_ack ===
=== start test_tbf_delayed_release ===
=== end test_tbf_delayed_release ===
=== start test_tbf_imsi ===
@ -26,20 +20,3 @@
=== end test_tbf_dl_flow_and_rach_single_phase ===
=== start test_tbf_dl_reuse ===
=== end test_tbf_dl_reuse ===
=== start test_tbf_gprs_egprs ===
=== end test_tbf_gprs_egprs ===
=== start test_tbf_ws ===
=== end test_tbf_ws ===
=== start test_tbf_egprs_two_phase ===
=== end test_tbf_egprs_two_phase ===
=== start test_tbf_egprs_dl ===
Testing MCS-1
Testing MCS-2
Testing MCS-3
Testing MCS-4
Testing MCS-5
Testing MCS-6
Testing MCS-7
Testing MCS-8
Testing MCS-9
=== end test_tbf_egprs_dl ===

View File

@ -27,7 +27,7 @@ AT_SETUP([edge])
AT_KEYWORDS([edge])
cat $abs_srcdir/edge/EdgeTest.ok > expout
cat $abs_srcdir/edge/EdgeTest.err > experr
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/edge/EdgeTest], [0], [expout], [ignore])
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/edge/EdgeTest], [0], [expout], [experr])
AT_CLEANUP
AT_SETUP([types])

View File

@ -89,9 +89,9 @@ static void test_rlc()
{
{
struct gprs_rlc_data rlc = { 0, };
memset(rlc.block, 0x23, RLC_MAX_LEN);
memset(rlc.complete_blk, 0x23, RLC_MAX_LEN);
uint8_t *p = rlc.prepare(20);
OSMO_ASSERT(p == rlc.block);
OSMO_ASSERT(p == rlc.complete_blk);
for (int i = 0; i < 20; ++i)
OSMO_ASSERT(p[i] == 0x2B);
for (int i = 20; i < RLC_MAX_LEN; ++i)
@ -327,12 +327,8 @@ static void test_rlc_dl_ul_basic()
{
uint16_t lost = 0, recv = 0;
char show_rbb[65];
uint8_t bits_data[8];
BTS dummy_bts;
gprs_rlc_dl_window dl_win;
bitvec bits;
int bsn_begin, bsn_end, num_blocks;
Ack_Nack_Description_t desc;
dl_win.m_v_b.reset();
@ -352,61 +348,13 @@ static void test_rlc_dl_ul_basic()
}
uint8_t rbb_cmp[8] = { 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff };
bits.data = bits_data;
bits.data_len = sizeof(bits_data);
bits.cur_bit = 0;
memcpy(desc.RECEIVED_BLOCK_BITMAP, rbb_cmp,
sizeof(desc.RECEIVED_BLOCK_BITMAP));
desc.FINAL_ACK_INDICATION = 0;
desc.STARTING_SEQUENCE_NUMBER = 35;
num_blocks = Decoding::decode_gprs_acknack_bits(
&desc, &bits,
&bsn_begin, &bsn_end, &dl_win);
Decoding::extract_rbb(&bits, show_rbb);
Decoding::extract_rbb(rbb_cmp, show_rbb);
printf("show_rbb: %s\n", show_rbb);
dl_win.update(&dummy_bts, &bits, 0, &lost, &recv);
dl_win.update(&dummy_bts, show_rbb, 35, &lost, &recv);
OSMO_ASSERT(lost == 0);
OSMO_ASSERT(recv == 35);
OSMO_ASSERT(bsn_begin == 0);
OSMO_ASSERT(bsn_end == 35);
OSMO_ASSERT(num_blocks == 35);
dl_win.raise(dl_win.move_window());
for (int i = 0; i < 8; ++i) {
dl_win.increment_send();
OSMO_ASSERT(!dl_win.window_empty());
OSMO_ASSERT(dl_win.distance() == 2 + i);
}
uint8_t rbb_cmp2[8] = { 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x31 };
bits.data = bits_data;
bits.data_len = sizeof(bits_data);
bits.cur_bit = 0;
memcpy(desc.RECEIVED_BLOCK_BITMAP, rbb_cmp2,
sizeof(desc.RECEIVED_BLOCK_BITMAP));
desc.FINAL_ACK_INDICATION = 0;
desc.STARTING_SEQUENCE_NUMBER = 35 + 8;
num_blocks = Decoding::decode_gprs_acknack_bits(
&desc, &bits,
&bsn_begin, &bsn_end, &dl_win);
Decoding::extract_rbb(&bits, show_rbb);
printf("show_rbb: %s\n", show_rbb);
lost = recv = 0;
dl_win.update(&dummy_bts, &bits, 0, &lost, &recv);
OSMO_ASSERT(lost == 5);
OSMO_ASSERT(recv == 3);
OSMO_ASSERT(bitvec_get_bit_pos(&bits, 0) == 0);
OSMO_ASSERT(bitvec_get_bit_pos(&bits, 7) == 1);
OSMO_ASSERT(bsn_begin == 35);
OSMO_ASSERT(bsn_end == 43);
OSMO_ASSERT(num_blocks == 8);
}
}

View File

@ -4,5 +4,4 @@ rbb: 00 00 00 00 00 00 00 01
rbb: 00 00 00 00 00 00 00 03
rbb: 00 00 00 00 00 00 00 31
rbb: 10 00 00 00 00 00 00 01
show_rbb: RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
show_rbb: IIRRIIIR
show_rbb: IIIIIIIIIIIIIIIIIIIIIIIIIIIIIRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR