Compare commits

...

19 Commits

Author SHA1 Message Date
Jacob Erlbeck
407851b865 tbf: Add BTS::ms_alloc method
Currently the code that creates the MS objects with tbf.cpp is
duplicated.

This commit moves the corresponding code into a new method. Since
there is no TLLI available there, the GprsMsStorage::create_ms method
has been refactored into two variants, one with TLLI/direction and
one without.

Sponsored-by: On-Waves ehf
2015-06-19 13:38:36 +02:00
Jacob Erlbeck
196ddc58a4 tbf: Always create an MS object on TBF allocation
Currently the MS object are created when the TLLI gets known.
Therefore some information (TA, MS class) must be stored in the TBF
itself and is copied to the MS object later on. This would get even
more complex, if the allocation algorithms were extended based on
this scheme.

This commit ensures, that an MS object will always be created on TBF
allocation, even if the TLLI is not yet known. These 'anonymous'
objects are still managed by the MS storage. To avoid dangling
entries without a TLLI there (which cannnot be retrieved anyway), the
timer in the MS objects is not started after all TBF have been
detached, so that they get deleted immediately in that case.

Note that an MS object can still be removed (e.g. by replacement)
from an existing TBF, so tbf->ms() can be NULL.

Ticket: #1794
Sponsored-by: On-Waves ehf
2015-06-19 13:38:32 +02:00
Jacob Erlbeck
77a23a7de4 tbf: Pass the MS object around instead of old_tbf
Currently the old TBF (either uplink or downlink) is passed around at
TBF allocation mainly to get information about the MS. To implement
more complex allocation algorithms, the MS object itself will be
needed anyway.

This commit replaces the old_tbf arguments by MS object arguments.

Sponsored-by: On-Waves ehf
2015-06-19 11:06:46 +02:00
Jacob Erlbeck
e75e76defe tbf: Remove update_tlli method
This method does not do anything anymore, it's functionality has been
taken over by update_ms.

This commit removes gprs_rlcmac_tbf::update_tlli completely.

Sponsored-by: On-Waves ehf
2015-06-18 16:19:20 +02:00
Jacob Erlbeck
67728acc7a llc: Move storage of timestamps into gprs_llc_queue
Currently the receive and expiry timestamps are prepended to the LLC
msgb before it is passed to gprs_llc_queue::enqueue(). Since this meta
information should not be counted as LLC octets, the gprs_llc_queue
needs to known about this (unless the correction was done in the LLC
layer).

This commit moves the meta information storage code into
gprs_llc_queue.  The meta data is now stored in the control block
(cb) area of the msgb.

Note that the info pointer that is returned from the dequeue method
is only valid if that method returns a (non-NULL) msgb. It must not
be used after that msgb has been modified or freed.

Sponsored-by: On-Waves ehf
2015-06-16 10:24:46 +02:00
Jacob Erlbeck
967e4dd2c3 llc: Make timeval arguments const
Some struct timeval pointer arguments do not have the const qualifier,
albeit the methods do not write to the structures. The next commit
will change related pointers to const, so this commit provides the
required constness.

Sponsored-by: On-Waves ehf
2015-06-16 10:18:42 +02:00
Jacob Erlbeck
0a96390122 ms: Reduce DL CS level if only a few LLC bytes are left
If just a few bytes are left to send to the MS, it makes sense to
reduce the coding scheme level to increase the throughput. This
has been shown by Chen and Goodman in their paper "Theoretical
Analysis of GPRS Throughput and Delay". See their throughput over C/I
measurement graphs (figures 4 and 5 in the paper) for details.

This commit implements a simplified CS downgrade feature for the
downlink. The coding scheme will be downgraded if there are only a
few octets are left to be send over the TBF (see the
downgrade-threshold command below) and the NACK rate is not low (the
CS will not get degraded on a high quality RF link). As an exception,
CS-3 will be degraded to CS-1, since CS-2 does not improve the
throughput in general when a few small packets are sent and the
signal fades slowly (see Chen/Goodman).

The following VTY command is added to the config-pcu node:

- cs downgrade-threshold <1-10000>
- cs no downgrade-threshold

to set the threshold of the number of remaining bytes to be RLC/MAC
encoded. The CS will only be reduced, if the number is below the
threshold. The 'no' command disables this feature completely. The
default value is 200 octets.

Sponsored-by: On-Waves ehf
2015-06-15 13:26:01 +02:00
Jacob Erlbeck
155cf8442a llc: Keep track of the number of stored LLC octets
To get the number of LLC octets that are stored in the queue, this
commit adds a m_queue_octets member along with a octets() method.
This value is updated similarly to m_queue_size on each modifying
method call.

Sponsored-by: On-Waves ehf
2015-06-15 11:22:15 +02:00
Jacob Erlbeck
bd8c689ed4 llc: Add missing include directive to llc.h
Currently struct llist_head is used without declaration which
accidently did not produce an error so far.

This commit adds the missing include directive.

Sponsored-by: On-Waves ehf
2015-06-15 11:19:13 +02:00
Jacob Erlbeck
618babae12 llc/test: Add test program for LLC related tests
Sponsored-by: On-Waves ehf
2015-06-15 11:14:45 +02:00
Jacob Erlbeck
2f7228b15f tbf: Fix downlink packet loss
When the MS is pinged with a longer interval, many packets get lost
even if the GprsMs object is kept. If the interval is above the time
where the DL TBF is in state FLOW (mainly influenced be the
dl-tbf-idle-time command), an new TBF must be requested via AGCH for
each ICMP PING message.

Currently the LLC frame containing the PING is immediately stored
in the TBF and gets lost, if TBF establishment fails for some reason.

This commit moves all calls to put_frame() to schedule_next_frame(),
where the data is moved from the LLC queue to the frame storage
within the TBF object. This method is only called from within
create_new_bsn() when the TBF is in the FLOW state and the frame is
going to be encoded immediately.

At all other places, where put_frame() has been called before, the
LLC message is just appended to the LLC queue in the GprsMs object.
This change effectively simplifies the related code parts, since
date/len information and discard notifications is no longer needed
there.

Ticket: #1759
Sponsored-by: On-Waves ehf
2015-06-12 16:59:13 +02:00
Jacob Erlbeck
e61b652e1b tbf/test: Add test for DL LLC packet loss
Currently LLC frames are lost or even reordered when the TBF has be
established via the AGCH and the procedure fails for some reason.

This test tries to reproduce this behaviour by throwing away the
first TBF while calling the handle() method several times. The
results of create_dl_acked_block() are checked against expected
values (this is currently party disabled because the bug still
persists).

Ticket: #1759
Sponsored-by: On-Waves ehf
2015-06-12 16:59:13 +02:00
Jacob Erlbeck
53a32b8e95 ms: Store the NACK rate in the MS object
Currently the NACK/unconfirmed ratio is already passed to the
corresponding MS object, but the value is not being stored there.

This commit adds a member and a getter method and include the values
into the output of the 'show ms' command.

Sponsored-by: On-Waves ehf
2015-06-12 16:59:11 +02:00
Jacob Erlbeck
6634635cf5 tbf: Include CS into create_new_bsn log message
This change lets the test suite fail, so it get its own commit.

Sponsored-by: On-Waves ehf
2015-06-12 15:52:05 +02:00
Jacob Erlbeck
5823b20f2f l1: Add debug log messages for I_LEVEL
The I_LEVEL values that are obtained now look suspicious. They do not
seem to be contained in messages recorded via gsmtab.

To help debugging this issue, this commit adds related debug messages
that are generated while the encoded values are taken from the
RLC/MAC messages.

Sponsored-by: On-Waves ehf
2015-06-12 15:46:43 +02:00
Jacob Erlbeck
6659c516fa l1: Store measurement values sent by the MS
This commit extends the pcu_l1_meas structure by MS side measurement
values which are transmitted by PACKET DOWNLINK ACK/NACK and
PACKET RESOURCE REQUEST messages. The encoded values are remapped to
dB respectively % values. The values are stored in the corresponding
MS object (if there is one).

Note that the values are store as (rounded) integers, so some
different encodings are mapped to the same decoded value.

Sponsored-by: On-Waves ehf
2015-06-12 15:35:10 +02:00
Jacob Erlbeck
54fff3b3e4 ms: Add UL CS selection based on L1 link quality
Currently the UL CS values are set to the corresponding DL CS value,
eventually limited by a maximum value. This approach does not reflect
the general situation of the RF link between ME and BTS, which is
rather asymmetric e.g. due to a lower degree of TX efficiency of the
built-in antenna. This means, that UL and DL CS control should be
decoupled for better results.

This commit adds automatic UL CS selection based on the link quality
measurement parameter. Each coding scheme is mapped to a link quality
range. If the link quality value leaves that range, the current UL CS
value is increased/decreased accordingly. This value will be copied
when the next PACKET_UPLINK_ACK_NACK or PACKET_UPLINK_ASSIGMENT is
sent to the MS.

The following VTY command will be added to the config-pcu node:

-  cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35>
          cs3 <0-35> <0-35> cs4 <0-35>

which sets the ranges for the four coding schemes. For instance the
example below reflects the current default values:

  cs link-quality-ranges cs1 6 cs2 5 8 cs3 7 13 cs4 12

set the following ranges, where the overlapping is used to configure
a hysteresis:

  CS1: -inf ..  6
  CS2:    5 ..  8
  CS3:    7 .. 13
  CS4:   12 .. inf

Sponsored-by: On-Waves ehf
2015-06-12 15:35:10 +02:00
Jacob Erlbeck
3bea905e0d ms: Store the L1 measurement values in the MS objects
This commits adds the GprsMs::update_l1_meas() and GprsMs::l1_meas()
methods to store and access the measurement values. The internal
state is updated depending on which values are actually set.

In addition, these values are shown in the output of the 'show ms
imsi|tlli' command.

Sponsored-by: On-Waves ehf
2015-06-12 15:35:10 +02:00
Jacob Erlbeck
4ff709c3ac l1: Pass all L1 measurements upwards
Currently only the RSSI value is passed to the upper layers. Other
values like TA and BER which are needed for TA update respectively CS
selection are not propagated.

This commit introduces and passes a struct that contains a set of
measurement values.

Sponsored-by: On-Waves ehf
2015-06-12 15:32:17 +02:00
34 changed files with 1265 additions and 352 deletions

View File

@@ -522,6 +522,17 @@ void BTS::snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi)
}
GprsMs *BTS::ms_alloc(uint8_t ms_class)
{
GprsMs *ms;
ms = ms_store().create_ms();
ms->set_timeout(m_bts.ms_idle_sec);
ms->set_ms_class(ms_class);
return ms;
}
/*
* PDCH code below. TODO: move to a separate file
*/
@@ -657,7 +668,8 @@ void gprs_rlcmac_pdch::add_paging(struct gprs_rlcmac_paging *pag)
*
* The blocks are defragmented and forwarded as LLC frames, if complete.
*/
int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len, int8_t rssi)
int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len,
struct pcu_l1_meas *meas)
{
struct gprs_rlcmac_ul_tbf *tbf;
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
@@ -692,7 +704,7 @@ int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len, in
return 0;
}
return tbf->rcv_data_block_acknowledged(data, len, rssi);
return tbf->rcv_data_block_acknowledged(data, len, meas);
}
void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, uint32_t fn)
@@ -711,7 +723,6 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
fn, tlli, trx_no(), ts_no);
return;
}
tbf->update_tlli(tlli);
tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s Packet Control Ack\n", tbf_name(tbf));
@@ -789,11 +800,70 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
"at no request\n");
}
static void get_rx_qual_meas(struct pcu_l1_meas *meas, uint8_t rx_qual_enc)
{
static const int16_t rx_qual_map[] = {
0, /* 0,14 % */
0, /* 0,28 % */
1, /* 0,57 % */
1, /* 1,13 % */
2, /* 2,26 % */
5, /* 4,53 % */
9, /* 9,05 % */
18, /* 18,10 % */
};
meas->set_ms_rx_qual(rx_qual_map[
OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)
]);
}
static void get_meas(struct pcu_l1_meas *meas,
const Packet_Resource_Request_t *qr)
{
unsigned i;
meas->set_ms_c_value(qr->C_VALUE);
if (qr->Exist_SIGN_VAR)
meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)
{
if (qr->Slot[i].Exist) {
LOGP(DRLCMAC, LOGL_INFO,
"Packet resource request: i_level[%d] = %d\n",
i, qr->Slot[i].I_LEVEL);
meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL);
}
}
}
static void get_meas(struct pcu_l1_meas *meas,
const Channel_Quality_Report_t *qr)
{
unsigned i;
get_rx_qual_meas(meas, qr->RXQUAL);
meas->set_ms_c_value(qr->C_VALUE);
meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)
{
if (qr->Slot[i].Exist) {
LOGP(DRLCMAC, LOGL_INFO,
"Channel quality report: i_level[%d] = %d\n",
i, qr->Slot[i].I_LEVEL_TN);
meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL_TN);
}
}
}
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;
tfi = ack_nack->DOWNLINK_TFI;
tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
@@ -835,11 +905,16 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_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->tlli(), tbf->ta(), tbf);
tbf->tlli(), tbf->ta(), tbf->ms());
/* schedule uplink assignment */
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
}
/* get measurements */
if (tbf->ms()) {
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)
@@ -852,6 +927,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
uint32_t tlli = request->ID.u.TLLI;
uint8_t ms_class = 0;
uint8_t ta = 0;
struct pcu_l1_meas meas;
GprsMs *ms = bts()->ms_by_tlli(tlli);
/* Keep the ms, even if it gets idle temporarily */
@@ -897,7 +973,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
ms_class = Decoding::get_ms_class_by_capability(&request->MS_Radio_Access_capability);
if (!ms_class)
LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
ul_tbf = tbf_alloc_ul(bts_data(), trx_no(), ms_class, tlli, ta, NULL);
ul_tbf = tbf_alloc_ul(bts_data(), trx_no(), ms_class, tlli, ta, ms);
if (!ul_tbf)
return;
@@ -906,6 +982,12 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
ul_tbf->control_ts = ts_no;
/* schedule uplink assignment */
ul_tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
/* get measurements */
if (ul_tbf->ms()) {
get_meas(&meas, request);
ul_tbf->ms()->update_l1_meas(&meas);
}
return;
}
@@ -932,7 +1014,6 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
"RX: [PCU <- BTS] %s FIXME: Packet resource request\n",
tbf_name(ul_tbf));
}
}
void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *report, uint32_t fn)
@@ -995,7 +1076,8 @@ int gprs_rlcmac_pdch::rcv_control_block(
/* received RLC/MAC block from L1 */
int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t rssi)
int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
struct pcu_l1_meas *meas)
{
unsigned payload = data[0] >> 6;
bitvec *block;
@@ -1003,7 +1085,7 @@ int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t
switch (payload) {
case GPRS_RLCMAC_DATA_BLOCK:
rc = rcv_data_block_acknowledged(data, len, rssi);
rc = rcv_data_block_acknowledged(data, len, meas);
break;
case GPRS_RLCMAC_CONTROL_BLOCK:
block = bitvec_alloc(len);

View File

@@ -37,6 +37,7 @@ extern "C" {
#include <stdint.h>
struct BTS;
struct GprsMs;
/*
* PDCH instance
@@ -56,7 +57,8 @@ struct gprs_rlcmac_pdch {
void disable();
/* dispatching of messages */
int rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t rssi);
int rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
struct pcu_l1_meas *meas);
gprs_rlcmac_bts *bts_data() const;
BTS *bts() const;
@@ -80,7 +82,8 @@ struct gprs_rlcmac_pdch {
#ifdef __cplusplus
private:
int rcv_data_block_acknowledged(uint8_t *data, uint8_t len, int8_t rssi);
int rcv_data_block_acknowledged(uint8_t *data, uint8_t len,
struct pcu_l1_meas *meas);
int rcv_control_block(bitvec *rlc_block, uint32_t fn);
void rcv_control_ack(Packet_Control_Acknowledgement_t *, uint32_t fn);
@@ -136,7 +139,7 @@ struct gprs_rlcmac_bts {
uint8_t n3105;
struct gprs_rlcmac_trx trx[8];
int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
struct GprsMs *ms,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
uint32_t alloc_algorithm_curst; /* options to customize algorithm */
uint8_t force_two_phase;
@@ -146,6 +149,8 @@ struct gprs_rlcmac_bts {
uint8_t cs_adj_enabled;
uint8_t cs_adj_upper_limit;
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) */
/* TBF handling, make private or move into TBFController */
/* list of uplink TBFs */
@@ -224,6 +229,7 @@ public:
GprsMsStorage &ms_store();
GprsMs *ms_by_tlli(uint32_t tlli, uint32_t old_tlli = 0);
GprsMs *ms_alloc(uint8_t ms_class);
/*
* Statistics

View File

@@ -804,8 +804,8 @@ struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)
return the_pcu.bctx;
}
void gprs_bssgp_update_queue_delay(struct timeval *tv_recv,
struct timeval *tv_now)
void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
const struct timeval *tv_now)
{
struct timeval *delay_sum = &the_pcu.queue_delay_sum;
struct timeval tv_delay;

View File

@@ -83,7 +83,7 @@ void gprs_bssgp_destroy(void);
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
void gprs_bssgp_update_queue_delay(struct timeval *tv_recv,
struct timeval *tv_now);
void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
const struct timeval *tv_now);
#endif // GPRS_BSSGP_PCU_H

View File

@@ -90,7 +90,8 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
m_is_idle(true),
m_ref(0),
m_list(this),
m_delay(0)
m_delay(0),
m_nack_rate_dl(0)
{
LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
@@ -239,7 +240,7 @@ void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
if (tbf->ms() == this)
tbf->set_ms(NULL);
if (!m_dl_tbf && !m_ul_tbf)
if (!m_dl_tbf && !m_ul_tbf && tlli() != 0)
start_timer();
update_status();
@@ -367,7 +368,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
{
struct gprs_rlcmac_bts *bts_data;
int64_t now;
uint8_t max_cs_ul = 4, max_cs_dl = 4;
uint8_t max_cs_dl = 4;
OSMO_ASSERT(m_bts != NULL);
bts_data = m_bts->bts_data();
@@ -377,18 +378,17 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
now = now_msec();
if (bts_data->max_cs_ul)
max_cs_ul = bts_data->max_cs_ul;
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 > 1) {
m_current_cs_dl -= 1;
m_current_cs_ul = m_current_cs_dl;
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): High error rate %d%%, "
"reducing CS level to %d\n",
@@ -399,12 +399,10 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
if (m_current_cs_dl < max_cs_dl) {
if (now - m_last_cs_not_low > 1000) {
m_current_cs_dl += 1;
if (m_current_cs_dl <= max_cs_ul)
m_current_cs_ul = m_current_cs_dl;
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): Low error rate %d%%, "
"increasing CS level to %d\n",
"increasing DL CS level to %d\n",
imsi(), error_rate, m_current_cs_dl);
m_last_cs_not_low = now;
} else {
@@ -421,3 +419,102 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
m_last_cs_not_low = now;
}
}
void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
{
struct gprs_rlcmac_bts *bts_data;
uint8_t max_cs_ul = 4;
unsigned i;
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);
if (meas->have_bto)
m_l1_meas.set_bto(meas->bto);
if (meas->have_ber)
m_l1_meas.set_ber(meas->ber);
if (meas->have_link_qual)
m_l1_meas.set_link_qual(meas->link_qual);
if (meas->have_ms_rx_qual)
m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
if (meas->have_ms_c_value)
m_l1_meas.set_ms_c_value(meas->ms_c_value);
if (meas->have_ms_sign_var)
m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
if (meas->have_ms_i_level) {
for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
if (meas->ts[i].have_ms_i_level)
m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
else
m_l1_meas.ts[i].have_ms_i_level = 0;
}
}
}
uint8_t GprsMs::current_cs_dl() const
{
uint8_t cs = m_current_cs_dl;
size_t unencoded_octets;
if (!m_bts)
return cs;
unencoded_octets = m_llc_queue.octets();
/* 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();
/* There are many unencoded octets, don't reduce */
if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
return cs;
/* RF conditions are good, don't reduce */
if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
return cs;
/* The throughput would probably be better if the CS level was reduced */
cs -= 1;
/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
if (cs == 2)
cs -= 1;
return cs;
}

View File

@@ -26,6 +26,7 @@ struct gprs_rlcmac_ul_tbf;
#include "cxx_linuxlist.h"
#include "llc.h"
#include "pcu_l1_if.h"
extern "C" {
#include <osmocom/core/timer.h>
@@ -96,6 +97,10 @@ public:
LListHead<GprsMs>& list() {return this->m_list;}
const LListHead<GprsMs>& list() const {return this->m_list;}
void update_l1_meas(const pcu_l1_meas *meas);
const pcu_l1_meas* l1_meas() const {return &m_l1_meas;};
unsigned nack_rate_dl() const;
/* internal use */
static void timeout(void *priv_);
@@ -132,6 +137,9 @@ private:
unsigned m_delay;
int64_t m_last_cs_not_low;
pcu_l1_meas m_l1_meas;
unsigned m_nack_rate_dl;
};
inline uint32_t GprsMs::tlli() const
@@ -162,11 +170,6 @@ inline uint8_t GprsMs::ms_class() const
return m_ms_class;
}
inline uint8_t GprsMs::current_cs_dl() const
{
return m_current_cs_dl;
}
inline uint8_t GprsMs::current_cs_ul() const
{
return m_current_cs_ul;
@@ -187,3 +190,8 @@ inline const gprs_llc_queue *GprsMs::llc_queue() const
return &m_llc_queue;
}
inline unsigned GprsMs::nack_rate_dl() const
{
return m_nack_rate_dl;
}

View File

@@ -80,6 +80,18 @@ GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi
return NULL;
}
GprsMs *GprsMsStorage::create_ms()
{
GprsMs *ms;
ms = new GprsMs(m_bts, 0);
ms->set_callback(this);
llist_add(&ms->list(), &m_list);
return ms;
}
GprsMs *GprsMsStorage::create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
{
GprsMs *ms = get_ms(tlli);
@@ -87,15 +99,12 @@ GprsMs *GprsMsStorage::create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction d
if (ms)
return ms;
ms = new GprsMs(m_bts, 0);
ms = create_ms();
if (dir == GPRS_RLCMAC_UL_TBF)
ms->set_tlli(tlli);
else
ms->confirm_tlli(tlli);
ms->set_callback(this);
llist_add(&ms->list(), &m_list);
return ms;
}

View File

@@ -38,6 +38,7 @@ public:
GprsMs *get_ms(uint32_t tlli, uint32_t old_tlli = 0, const char *imsi = 0) const;
GprsMs *create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir);
GprsMs *create_ms();
const LListHead<GprsMs>& ms_list() const {return m_list;}
private:

View File

@@ -42,6 +42,7 @@ extern "C" {
struct gprs_rlcmac_tbf;
struct gprs_rlcmac_bts;
struct BTS;
struct GprsMs;
#ifdef __cplusplus
/*
@@ -95,11 +96,11 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
extern "C" {
#endif
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
struct GprsMs *ms,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
struct GprsMs *ms,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
#ifdef __cplusplus
}

View File

@@ -23,6 +23,7 @@
#include <gprs_debug.h>
#include <bts.h>
#include <tbf.h>
#include <gprs_ms.h>
#include <errno.h>
@@ -139,7 +140,7 @@ static void assign_dlink_tbf(
* Assign single slot for uplink and downlink
*/
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
GprsMs *ms,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
{
struct gprs_rlcmac_pdch *pdch;
@@ -261,16 +262,21 @@ inc_window:
return rx_window;
}
static int reduce_rx_window(const int ms_type, const struct gprs_rlcmac_tbf *old_tbf,
static int reduce_rx_window(const int ms_type, const GprsMs *ms,
const int Tt, const int Tr,
int *rx_window,
uint8_t *rx_win_min, uint8_t *rx_win_max)
{
gprs_rlcmac_ul_tbf *ul_tbf;
if (ms_type != 1)
return 0;
if (!old_tbf)
if (!ms)
return 0;
if (old_tbf->direction != GPRS_RLCMAC_UL_TBF)
ul_tbf = ms->ul_tbf();
if (!ul_tbf)
return 0;
uint8_t collide = 0, ul_usage = 0;
@@ -278,7 +284,7 @@ static int reduce_rx_window(const int ms_type, const struct gprs_rlcmac_tbf *old
/* calculate mask of colliding slots */
for (uint8_t ts_no = 0; ts_no < 8; ts_no++) {
int j;
if (!old_tbf->pdch[ts_no])
if (!ul_tbf->pdch[ts_no])
continue;
ul_usage |= (1 << ts_no);
@@ -525,7 +531,7 @@ static int select_first_ts(gprs_rlcmac_trx *trx, uint8_t tx_win_min,
*
*/
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
GprsMs *ms,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
{
const struct gprs_ms_multislot_class *ms_class;
@@ -592,7 +598,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
/* reduce window, if existing uplink slots collide RX window */
int rc = reduce_rx_window(ms_class->type, old_tbf, Tt, Tr,
int rc = reduce_rx_window(ms_class->type, ms, Tt, Tr,
&rx_window, &rx_win_min, &rx_win_max);
if (rc < 0)
return rc;

View File

@@ -100,12 +100,23 @@ void gprs_llc_queue::init()
{
INIT_LLIST_HEAD(&m_queue);
m_queue_size = 0;
m_queue_octets = 0;
m_avg_queue_delay = 0;
}
void gprs_llc_queue::enqueue(struct msgb *llc_msg)
void gprs_llc_queue::enqueue(struct msgb *llc_msg, const MetaInfo *info)
{
static const MetaInfo def_meta = {{0}};
MetaInfo *meta_storage;
osmo_static_assert(sizeof(*info) <= sizeof(llc_msg->cb), info_does_not_fit);
m_queue_size += 1;
m_queue_octets += msgb_length(llc_msg);
meta_storage = (MetaInfo *)&llc_msg->cb[0];
*meta_storage = info ? *info : def_meta;
msgb_enqueue(&m_queue, llc_msg);
}
@@ -120,27 +131,34 @@ void gprs_llc_queue::clear(BTS *bts)
}
m_queue_size = 0;
m_queue_octets = 0;
}
#define ALPHA 0.5f
struct msgb *gprs_llc_queue::dequeue()
struct msgb *gprs_llc_queue::dequeue(const MetaInfo **info)
{
struct msgb *msg;
struct timeval *tv, tv_now, tv_result;
uint32_t lifetime;
const MetaInfo *meta_storage;
msg = msgb_dequeue(&m_queue);
if (!msg)
return NULL;
meta_storage = (MetaInfo *)&msg->cb[0];
if (info)
*info = meta_storage;
m_queue_size -= 1;
m_queue_octets -= msgb_length(msg);
/* take the second time */
gettimeofday(&tv_now, NULL);
tv = (struct timeval *)&msg->data[sizeof(*tv)];
timersub(&tv_now, tv, &tv_result);
timersub(&tv_now, &meta_storage->recv_time, &tv_result);
lifetime = tv_result.tv_sec*1000 + tv_result.tv_usec/1000;
m_avg_queue_delay = m_avg_queue_delay * ALPHA + lifetime * (1-ALPHA);
@@ -171,7 +189,8 @@ void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
timeradd(&now, &csec, tv);
}
bool gprs_llc_queue::is_frame_expired(struct timeval *tv_now, struct timeval *tv)
bool gprs_llc_queue::is_frame_expired(const struct timeval *tv_now,
const struct timeval *tv)
{
/* Timeout is infinite */
if (tv->tv_sec == 0 && tv->tv_usec == 0)

View File

@@ -18,8 +18,13 @@
#pragma once
extern "C" {
#include <osmocom/core/linuxlist.h>
}
#include <stdint.h>
#include <string.h>
#include <time.h>
#define LLC_MAX_LEN 1543
@@ -59,20 +64,29 @@ struct gprs_llc {
* I store the LLC frames that come from the SGSN.
*/
struct gprs_llc_queue {
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv);
static bool is_frame_expired(struct timeval *now, struct timeval *tv);
struct MetaInfo {
struct timeval recv_time;
struct timeval expire_time;
};
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
struct timeval *tv);
static bool is_frame_expired(const struct timeval *now,
const struct timeval *tv);
static bool is_user_data_frame(uint8_t *data, size_t len);
void init();
void enqueue(struct msgb *llc_msg);
struct msgb *dequeue();
void enqueue(struct msgb *llc_msg, const MetaInfo *info = 0);
struct msgb *dequeue(const MetaInfo **info = 0);
void clear(BTS *bts);
size_t size() const;
size_t octets() const;
private:
uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */
size_t m_queue_size;
size_t m_queue_octets;
struct llist_head m_queue; /* queued LLC DL data */
};
@@ -114,3 +128,8 @@ inline size_t gprs_llc_queue::size() const
{
return this ? m_queue_size : 0;
}
inline size_t gprs_llc_queue::octets() const
{
return this ? m_queue_octets : 0;
}

View File

@@ -181,17 +181,19 @@ void pcu_l1if_tx_pch(bitvec * block, int plen, const char *imsi)
}
extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *data,
uint8_t len, uint32_t fn, int8_t rssi)
uint8_t len, uint32_t fn, struct pcu_l1_meas *meas)
{
struct gprs_rlcmac_pdch *pdch;
pdch = &bts_main_data()->trx[trx_no].pdch[ts_no];
return pdch->rcv_block(data, len, fn, rssi);
return pdch->rcv_block(data, len, fn, meas);
}
static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
{
int rc = 0;
pcu_l1_meas meas;
meas.set_rssi(data_ind->rssi);
LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d "
"block=%d data=%s\n", data_ind->sapi,
@@ -202,7 +204,7 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
case PCU_IF_SAPI_PDTCH:
rc = pcu_rx_data_ind_pdtch(data_ind->trx_nr, data_ind->ts_nr,
data_ind->data, data_ind->len, data_ind->fn,
data_ind->rssi);
&meas);
break;
default:
LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with "

View File

@@ -31,7 +31,81 @@ extern "C" {
#include <osmocom/gsm/gsm_utils.h>
#ifdef __cplusplus
}
#endif
/*
* L1 Measurement values
*/
struct pcu_l1_meas_ts {
unsigned have_ms_i_level:1;
int16_t ms_i_level; /* I_LEVEL in dB */
#ifdef __cplusplus
pcu_l1_meas_ts& set_ms_i_level(int16_t v) {
ms_i_level = v; have_ms_i_level = 1; return *this;
}
pcu_l1_meas_ts() :
have_ms_i_level(0)
{}
#endif
};
struct pcu_l1_meas {
unsigned have_rssi:1;
unsigned have_ber:1;
unsigned have_bto:1;
unsigned have_link_qual:1;
unsigned have_ms_rx_qual:1;
unsigned have_ms_c_value:1;
unsigned have_ms_sign_var:1;
unsigned have_ms_i_level:1;
int8_t rssi; /* RSSI in dBm */
uint8_t ber; /* Bit error rate in % */
int16_t bto; /* Burst timing offset in quarter bits */
int16_t link_qual; /* Link quality in dB */
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 */
struct pcu_l1_meas_ts ts[8];
#ifdef __cplusplus
pcu_l1_meas& set_rssi(int8_t v) { rssi = v; have_rssi = 1; return *this;}
pcu_l1_meas& set_ber(uint8_t v) { ber = v; have_ber = 1; return *this;}
pcu_l1_meas& set_bto(int16_t v) { bto = v; have_bto = 1; return *this;}
pcu_l1_meas& set_link_qual(int16_t v) {
link_qual = v; have_link_qual = 1; return *this;
}
pcu_l1_meas& set_ms_rx_qual(int16_t v) {
ms_rx_qual = v; have_ms_rx_qual = 1; return *this;
}
pcu_l1_meas& set_ms_c_value(int16_t v) {
ms_c_value = v; have_ms_c_value = 1; return *this;
}
pcu_l1_meas& set_ms_sign_var(int16_t v) {
ms_sign_var = v; have_ms_sign_var = 1; return *this;
}
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() :
have_rssi(0),
have_ber(0),
have_bto(0),
have_link_qual(0),
have_ms_rx_qual(0),
have_ms_c_value(0),
have_ms_sign_var(0),
have_ms_i_level(0)
{}
#endif
};
#ifdef __cplusplus
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
@@ -57,6 +131,6 @@ int pcu_rx_rts_req_pdtch(uint8_t trx, uint8_t ts, uint16_t arfcn,
extern "C"
#endif
int pcu_rx_data_ind_pdtch(uint8_t trx, uint8_t ts, uint8_t *data,
uint8_t len, uint32_t fn, int8_t rssi);
uint8_t len, uint32_t fn, struct pcu_l1_meas *meas);
#endif // PCU_L1_IF_H

View File

@@ -178,6 +178,16 @@ 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;
/* CS-1 to CS-4 */
bts->cs_lqual_ranges[0].low = -256;
bts->cs_lqual_ranges[0].high = 6;
bts->cs_lqual_ranges[1].low = 5;
bts->cs_lqual_ranges[1].high = 8;
bts->cs_lqual_ranges[2].low = 7;
bts->cs_lqual_ranges[2].high = 13;
bts->cs_lqual_ranges[3].low = 12;
bts->cs_lqual_ranges[3].high = 256;
bts->cs_downgrade_threshold = 200;
msgb_set_talloc_ctx(tall_pcu_ctx);

View File

@@ -90,6 +90,21 @@ static int config_write_pcu(struct vty *vty)
else
vty_out(vty, " no cs threshold%s", VTY_NEWLINE);
if (bts->cs_downgrade_threshold)
vty_out(vty, " cs downgrade-threshold %d%s",
bts->cs_downgrade_threshold, VTY_NEWLINE);
else
vty_out(vty, " no cs downgrade-threshold%s", VTY_NEWLINE);
vty_out(vty, " cs link-quality-ranges cs1 %d cs2 %d %d cs3 %d %d cs4 %d%s",
bts->cs_lqual_ranges[0].high,
bts->cs_lqual_ranges[1].low,
bts->cs_lqual_ranges[1].high,
bts->cs_lqual_ranges[2].low,
bts->cs_lqual_ranges[2].high,
bts->cs_lqual_ranges[3].low,
VTY_NEWLINE);
if (bts->force_llc_lifetime == 0xffff)
vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE);
else if (bts->force_llc_lifetime)
@@ -600,6 +615,67 @@ DEFUN(cfg_pcu_no_cs_err_limits,
return CMD_SUCCESS;
}
#define CS_DOWNGRADE_STR "set threshold for data size based CS downgrade\n"
DEFUN(cfg_pcu_cs_downgrade_thrsh,
cfg_pcu_cs_downgrade_thrsh_cmd,
"cs downgrade-threshold <1-10000>",
CS_STR CS_DOWNGRADE_STR "downgrade if less octets left\n")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
bts->cs_downgrade_threshold = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_pcu_no_cs_downgrade_thrsh,
cfg_pcu_no_cs_downgrade_thrsh_cmd,
"no cs downgrade-threshold",
CS_STR CS_DOWNGRADE_STR)
{
struct gprs_rlcmac_bts *bts = bts_main_data();
bts->cs_downgrade_threshold = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_pcu_cs_lqual_ranges,
cfg_pcu_cs_lqual_ranges_cmd,
"cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35> cs3 <0-35> <0-35> cs4 <0-35>",
CS_STR "Set link quality ranges\n"
"Set quality range for CS-1 (high value only)\n"
"CS-1 high (dB)\n"
"Set quality range for CS-2\n"
"CS-2 low (dB)\n"
"CS-2 high (dB)\n"
"Set quality range for CS-3\n"
"CS-3 low (dB)\n"
"CS-3 high (dB)\n"
"Set quality range for CS-4 (low value only)\n"
"CS-4 low (dB)\n")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
uint8_t cs1_high = atoi(argv[0]);
uint8_t cs2_low = atoi(argv[1]);
uint8_t cs2_high = atoi(argv[2]);
uint8_t cs3_low = atoi(argv[3]);
uint8_t cs3_high = atoi(argv[4]);
uint8_t cs4_low = atoi(argv[5]);
bts->cs_lqual_ranges[0].high = cs1_high;
bts->cs_lqual_ranges[1].low = cs2_low;
bts->cs_lqual_ranges[1].high = cs2_high;
bts->cs_lqual_ranges[2].low = cs3_low;
bts->cs_lqual_ranges[2].high = cs3_high;
bts->cs_lqual_ranges[3].low = cs4_low;
return CMD_SUCCESS;
}
DEFUN(show_tbf,
show_tbf_cmd,
"show tbf all",
@@ -685,6 +761,9 @@ int pcu_vty_init(const struct log_info *cat)
install_element(PCU_NODE, &cfg_pcu_no_cs_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_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

@@ -58,6 +58,8 @@ int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
static int show_ms(struct vty *vty, GprsMs *ms)
{
unsigned i;
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: CS-%d%s", ms->current_cs_ul(),
@@ -67,6 +69,35 @@ static int show_ms(struct vty *vty, GprsMs *ms)
vty_out(vty, " MS class: %d%s", ms->ms_class(), VTY_NEWLINE);
vty_out(vty, " LLC queue length: %d%s", ms->llc_queue()->size(),
VTY_NEWLINE);
if (ms->l1_meas()->have_rssi)
vty_out(vty, " RSSI: %d dBm%s",
ms->l1_meas()->rssi, VTY_NEWLINE);
if (ms->l1_meas()->have_ber)
vty_out(vty, " Bit error rate: %d %%%s",
ms->l1_meas()->ber, VTY_NEWLINE);
if (ms->l1_meas()->have_link_qual)
vty_out(vty, " Link quality: %d dB%s",
ms->l1_meas()->link_qual, VTY_NEWLINE);
if (ms->l1_meas()->have_bto)
vty_out(vty, " Burst timing offset: %d/4 bit%s",
ms->l1_meas()->bto, VTY_NEWLINE);
if (ms->l1_meas()->have_ms_rx_qual)
vty_out(vty, " Downlink NACK rate: %d %%%s",
ms->nack_rate_dl(), VTY_NEWLINE);
if (ms->l1_meas()->have_ms_rx_qual)
vty_out(vty, " MS RX quality: %d %%%s",
ms->l1_meas()->ms_rx_qual, VTY_NEWLINE);
if (ms->l1_meas()->have_ms_c_value)
vty_out(vty, " MS C value: %d dB%s",
ms->l1_meas()->ms_c_value, VTY_NEWLINE);
if (ms->l1_meas()->have_ms_sign_var)
vty_out(vty, " MS SIGN variance: %d dB%s",
ms->l1_meas()->ms_sign_var, VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(ms->l1_meas()->ts); ++i) {
if (ms->l1_meas()->ts[i].have_ms_i_level)
vty_out(vty, " MS I level (slot %d): %d dB%s",
i, ms->l1_meas()->ts[i].ms_i_level, VTY_NEWLINE);
}
if (ms->ul_tbf())
vty_out(vty, " Uplink TBF: TFI=%d, state=%s%s",
ms->ul_tbf()->tfi(),

View File

@@ -166,10 +166,23 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h,
return rc;
}
static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t *l1_meas)
{
meas->rssi = (int8_t) (l1_meas->fRssi);
meas->have_rssi = 1;
meas->ber = (uint8_t) (l1_meas->fBer * 100);
meas->have_ber = 1;
meas->bto = (int16_t) (l1_meas->i16BurstTiming);
meas->have_bto = 1;
meas->link_qual = (int16_t) (l1_meas->fLinkQuality);
meas->have_link_qual = 1;
}
static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg)
{
int rc = 0;
struct pcu_l1_meas meas = {0};
DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
get_value_string(femtobts_l1sapi_names, data_ind->sapi),
@@ -190,8 +203,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
data_ind->u32Fn, 0, 0, data_ind->msgUnitParam.u8Buffer+1,
data_ind->msgUnitParam.u8Size-1);
get_meas(&meas, &data_ind->measParam);
switch (data_ind->sapi) {
case GsmL1_Sapi_Pdtch:
@@ -205,7 +217,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
data_ind->msgUnitParam.u8Buffer + 1,
data_ind->msgUnitParam.u8Size - 1,
data_ind->u32Fn,
(int8_t) (data_ind->measParam.fRssi));
&meas);
break;
case GsmL1_Sapi_Ptcch:
// FIXME

View File

@@ -158,23 +158,11 @@ void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
{
if (!ms()) {
GprsMs *new_ms = bts->ms_store().get_ms(tlli);
if (!new_ms) {
new_ms = bts->ms_store().create_ms(tlli, dir);
new_ms->set_timeout(bts->bts_data()->ms_idle_sec);
}
if (dir == GPRS_RLCMAC_UL_TBF) {
new_ms->set_ta(m_ta);
}
if (m_ms_class)
new_ms->set_ms_class(m_ms_class);
set_ms(new_ms);
if (!ms())
return;
if (!tlli)
return;
}
if (dir == GPRS_RLCMAC_UL_TBF)
ms()->set_tlli(tlli);
@@ -184,7 +172,7 @@ void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction di
gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
int8_t use_trx, uint8_t ms_class,
uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf)
uint32_t tlli, uint8_t ta, GprsMs *ms)
{
uint8_t trx;
struct gprs_rlcmac_ul_tbf *tbf;
@@ -199,7 +187,7 @@ gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
return NULL;
}
/* use multislot class of downlink TBF */
tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx, ms_class, 0);
tbf = tbf_alloc_ul_tbf(bts, ms, tfi, trx, ms_class, 0);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
/* FIXME: send reject */
@@ -274,7 +262,6 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
int gprs_rlcmac_tbf::update()
{
struct gprs_rlcmac_tbf *ul_tbf = NULL;
struct gprs_rlcmac_bts *bts_data = bts->bts_data();
int rc;
@@ -283,11 +270,8 @@ int gprs_rlcmac_tbf::update()
if (direction != GPRS_RLCMAC_DL_TBF)
return -EINVAL;
if (ms())
ul_tbf = ms()->ul_tbf();
tbf_unlink_pdch(this);
rc = bts_data->alloc_algorithm(bts_data, ul_tbf, this, bts_data->alloc_algorithm_curst, 0);
rc = bts_data->alloc_algorithm(bts_data, ms(), this, bts_data->alloc_algorithm_curst, 0);
/* if no resource */
if (rc < 0) {
LOGP(DRLCMAC, LOGL_ERROR, "No resource after update???\n");
@@ -450,7 +434,7 @@ void gprs_rlcmac_tbf::poll_timeout()
}
static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
GprsMs *ms, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
int rc;
@@ -470,7 +454,7 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
tbf->trx = &bts->trx[trx];
tbf->set_ms_class(ms_class);
/* select algorithm */
rc = bts->alloc_algorithm(bts, old_tbf, tbf, bts->alloc_algorithm_curst,
rc = bts->alloc_algorithm(bts, ms, tbf, bts->alloc_algorithm_curst,
single_slot);
/* if no resource */
if (rc < 0) {
@@ -488,12 +472,14 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
gettimeofday(&tbf->meas.rssi_tv, NULL);
tbf->m_llc.init();
tbf->set_ms(ms);
return 0;
}
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
GprsMs *ms, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
struct gprs_rlcmac_ul_tbf *tbf;
@@ -512,7 +498,11 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
return NULL;
tbf->direction = GPRS_RLCMAC_UL_TBF;
rc = setup_tbf(tbf, bts, old_tbf, tfi, trx, ms_class, single_slot);
if (!ms)
ms = bts->bts->ms_alloc(ms_class);
rc = setup_tbf(tbf, bts, ms, tfi, trx, ms_class, single_slot);
/* if no resource */
if (rc < 0) {
talloc_free(tbf);
@@ -522,17 +512,11 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
llist_add(&tbf->list.list, &bts->ul_tbfs);
tbf->bts->tbf_ul_created();
if (old_tbf && old_tbf->ms())
tbf->set_ms(old_tbf->ms());
if (tbf->ms())
tbf->ms()->attach_ul_tbf(tbf);
return tbf;
}
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
GprsMs *ms, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
struct gprs_rlcmac_dl_tbf *tbf;
@@ -551,7 +535,11 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
return NULL;
tbf->direction = GPRS_RLCMAC_DL_TBF;
rc = setup_tbf(tbf, bts, old_tbf, tfi, trx, ms_class, single_slot);
if (!ms)
ms = bts->bts->ms_alloc(ms_class);
rc = setup_tbf(tbf, bts, ms, tfi, trx, ms_class, single_slot);
/* if no resource */
if (rc < 0) {
talloc_free(tbf);
@@ -567,12 +555,6 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
gettimeofday(&tbf->m_bw.dl_bw_tv, NULL);
gettimeofday(&tbf->m_bw.dl_loss_tv, NULL);
if (old_tbf && old_tbf->ms())
tbf->set_ms(old_tbf->ms());
if (tbf->ms())
tbf->ms()->attach_dl_tbf(tbf);
return tbf;
}
@@ -847,10 +829,6 @@ void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_pdch *pdch)
}
}
void gprs_rlcmac_tbf::update_tlli(uint32_t tlli)
{
}
int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
{
struct gprs_rlcmac_tbf *dl_tbf = NULL;
@@ -860,6 +838,8 @@ int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
int rc;
GprsMs *old_ms;
OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
/* no TLLI yet */
if (!rh->ti) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d without "
@@ -880,15 +860,20 @@ int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
dl_tbf = old_ms->dl_tbf();
ul_tbf = old_ms->ul_tbf();
set_ms(old_ms);
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 */
dl_tbf->set_ms(ms());
}
update_tlli(new_tlli);
/* The TLLI has been taken from an UL message */
update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
"UL DATA TFI=%d.\n", tlli(), rh->tfi);
if (dl_tbf) {
if (dl_tbf && dl_tbf->ms() != ms()) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still exists. "
"Killing pending DL TBF\n", tlli(),
@@ -896,7 +881,7 @@ int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
tbf_free(dl_tbf);
dl_tbf = NULL;
}
if (ul_tbf) {
if (ul_tbf && ul_tbf->ms() != ms()) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still exists. "
"Killing pending UL TBF\n", tlli(),

View File

@@ -30,6 +30,7 @@
struct bssgp_bvc_ctx;
struct rlc_ul_header;
struct msgb;
struct pcu_l1_meas;
class GprsMs;
/*
@@ -138,7 +139,6 @@ struct gprs_rlcmac_tbf {
void poll_timeout();
/** tlli handling */
void update_tlli(uint32_t tlli);
uint32_t tlli() const;
bool is_tlli_valid() const;
@@ -240,16 +240,15 @@ private:
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
int8_t use_trx, uint8_t ms_class,
uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf);
uint32_t tlli, uint8_t ta, GprsMs *ms);
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
GprsMs *ms,
uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot);
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
uint8_t tfi, uint8_t trx,
GprsMs *ms, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot);
void tbf_free(struct gprs_rlcmac_tbf *tbf);
@@ -361,9 +360,10 @@ protected:
int update_window(const uint8_t ssn, const uint8_t *rbb);
int maybe_start_new_window();
bool dl_window_stalled() const;
void reuse_tbf(const uint8_t *data, const uint16_t len);
void reuse_tbf();
void start_llc_timer();
int analyse_errors(char *show_rbb, uint8_t ssn);
void schedule_next_frame();
struct osmo_timer_list m_llc_timer;
};
@@ -372,7 +372,8 @@ struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
struct msgb *create_ul_ack(uint32_t fn);
/* blocks were acked */
int rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi);
int rcv_data_block_acknowledged(const uint8_t *data, size_t len,
struct pcu_l1_meas *meas);
/* TODO: extract LLC class? */
int assemble_forward_llc(const gprs_rlc_data *data);

View File

@@ -99,36 +99,24 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
const uint8_t *data, const uint16_t len)
{
LOGP(DRLCMAC, LOGL_INFO, "%s append\n", tbf_name(this));
gprs_llc_queue::MetaInfo info;
struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
if (!llc_msg)
return -ENOMEM;
gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, &info.expire_time);
gettimeofday(&info.recv_time, NULL);
memcpy(msgb_put(llc_msg, len), data, len);
llc_queue()->enqueue(llc_msg, &info);
tbf_update_ms_class(this, ms_class);
start_llc_timer();
if (state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
LOGP(DRLCMAC, LOGL_DEBUG,
"%s in WAIT RELEASE state "
"(T3193), so reuse TBF\n", tbf_name(this));
tbf_update_ms_class(this, ms_class);
reuse_tbf(data, len);
} else if (!have_data()) {
m_llc.put_frame(data, len);
bts->llc_frame_sched();
/* it is no longer drained */
m_last_dl_drained_fn = -1;
tbf_update_ms_class(this, ms_class);
start_llc_timer();
} else {
/* TODO: put this path into an llc_enqueue method */
/* the TBF exists, so we must write it in the queue
* we prepend lifetime in front of PDU */
struct timeval *tv;
struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
"llc_pdu_queue");
if (!llc_msg)
return -ENOMEM;
tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
gettimeofday(tv, NULL);
memcpy(msgb_put(llc_msg, len), data, len);
llc_queue()->enqueue(llc_msg);
tbf_update_ms_class(this, ms_class);
start_llc_timer();
reuse_tbf();
}
return 0;
@@ -149,7 +137,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
const char *imsi,
const uint32_t tlli, const uint32_t tlli_old,
const uint8_t ms_class,
const uint8_t *data, const uint16_t len)
struct gprs_rlcmac_dl_tbf **tbf)
{
uint8_t trx, ss;
int8_t use_trx;
@@ -167,6 +155,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
ul_tbf = ms->ul_tbf();
ta = ms->ta();
}
/* TODO: if (!ms) create MS before tbf_alloc is called? */
if (ul_tbf && ul_tbf->m_contention_resolution_done
&& !ul_tbf->m_final_ack_sent) {
@@ -184,13 +173,10 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
tfi = bts->bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx, use_trx);
if (tfi >= 0)
/* set number of downlink slots according to multislot class */
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx, ms_class, ss);
dl_tbf = tbf_alloc_dl_tbf(bts, ms, tfi, trx, ms_class, ss);
if (!dl_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli,
1, len);
bts->bts->llc_dropped_frame();
return -EBUSY;
}
dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
@@ -198,10 +184,6 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
LOGP(DRLCMAC, LOGL_DEBUG, "%s [DOWNLINK] START\n", tbf_name(dl_tbf));
/* new TBF, so put first frame */
dl_tbf->m_llc.put_frame(data, len);
dl_tbf->bts->llc_frame_sched();
/* Store IMSI for later look-up and PCH retransmission */
dl_tbf->assign_imsi(imsi);
@@ -210,6 +192,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
* to trigger downlink assignment. if there is no uplink,
* AGCH is used. */
dl_tbf->bts->trigger_dl_ass(dl_tbf, old_ul_tbf);
*tbf = dl_tbf;
return 0;
}
@@ -222,30 +205,40 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
const uint8_t *data, const uint16_t len)
{
struct gprs_rlcmac_dl_tbf *dl_tbf;
int rc;
GprsMs *ms;
/* check for existing TBF */
dl_tbf = tbf_lookup_dl(bts->bts, tlli, tlli_old, imsi);
if (dl_tbf) {
int rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
if (rc >= 0)
dl_tbf->assign_imsi(imsi);
if (!dl_tbf) {
rc = tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class,
&dl_tbf);
if (rc < 0)
return rc;
}
if (dl_tbf->ms())
dl_tbf->ms()->confirm_tlli(tlli);
return rc;
}
OSMO_ASSERT(dl_tbf->ms() != NULL);
ms = dl_tbf->ms();
GprsMs::Guard guard(ms);
return tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class, data, len);
rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
dl_tbf = ms->dl_tbf();
dl_tbf->assign_imsi(imsi);
ms->confirm_tlli(tlli);
return rc;
}
struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
{
struct msgb *msg;
struct timeval *tv_recv, *tv_disc;
struct timeval tv_now, tv_now2;
uint32_t octets = 0, frames = 0;
struct timeval hyst_delta = {0, 0};
const unsigned keep_small_thresh = 60;
const gprs_llc_queue::MetaInfo *info;
if (bts_data()->llc_discard_csec)
csecs_to_timeval(bts_data()->llc_discard_csec, &hyst_delta);
@@ -253,11 +246,9 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
gettimeofday(&tv_now, NULL);
timeradd(&tv_now, &hyst_delta, &tv_now2);
while ((msg = llc_queue()->dequeue())) {
tv_disc = (struct timeval *)msg->data;
msgb_pull(msg, sizeof(*tv_disc));
tv_recv = (struct timeval *)msg->data;
msgb_pull(msg, sizeof(*tv_recv));
while ((msg = llc_queue()->dequeue(&info))) {
const struct timeval *tv_disc = &info->expire_time;
const struct timeval *tv_recv = &info->recv_time;
gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
@@ -385,22 +376,46 @@ do_resend:
goto do_resend;
}
void gprs_rlcmac_dl_tbf::schedule_next_frame()
{
struct msgb *msg;
if (m_llc.frame_length() != 0)
return;
/* dequeue next LLC frame, if any */
msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
if (!msg)
return;
LOGP(DRLCMACDL, LOGL_INFO,
"- Dequeue next LLC for %s (len=%d)\n",
tbf_name(this), msg->len);
m_llc.put_frame(msg->data, msg->len);
bts->llc_frame_sched();
msgb_free(msg);
m_last_dl_drained_fn = -1;
}
struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts)
{
struct rlc_dl_header *rh;
struct rlc_li_field *li;
struct msgb *msg;
uint8_t *delimiter, *data, *e_pointer;
uint16_t space, chunk;
gprs_rlc_data *rlc_data;
const uint16_t bsn = m_window.v_s();
uint8_t cs = 1;
LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d\n",
m_window.v_s());
if (m_llc.frame_length() == 0)
schedule_next_frame();
cs = current_cs();
LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d, CS=%d\n",
m_window.v_s(), cs);
OSMO_ASSERT(cs >= 1);
OSMO_ASSERT(cs <= 4);
@@ -535,15 +550,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
gprs_rlcmac_dl_bw(this, m_llc.frame_length());
m_llc.reset();
/* dequeue next LLC frame, if any */
msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
if (msg) {
LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC for "
"%s (len=%d)\n", tbf_name(this), msg->len);
m_llc.put_frame(msg->data, msg->len);
bts->llc_frame_sched();
msgb_free(msg);
m_last_dl_drained_fn = -1;
}
schedule_next_frame();
/* if we have more data and we have space left */
if (space > 0 && (m_llc.frame_length() || keep_open(fn))) {
li->m = 1; /* we indicate more frames to follow */
@@ -796,7 +803,6 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
int gprs_rlcmac_dl_tbf::maybe_start_new_window()
{
struct msgb *msg;
uint16_t received;
LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
@@ -809,8 +815,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
set_state(GPRS_RLCMAC_WAIT_RELEASE);
/* check for LLC PDU in the LLC Queue */
msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
if (!msg) {
if (!have_data()) {
/* no message, start T3193, change state to RELEASE */
LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we release.\n");
/* start T3193 */
@@ -822,8 +827,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
}
/* we have more data so we will re-use this tbf */
reuse_tbf(msg->data, msg->len);
msgb_free(msg);
reuse_tbf();
return 0;
}
@@ -836,7 +840,7 @@ int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb
return maybe_start_new_window();
}
void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
void gprs_rlcmac_dl_tbf::reuse_tbf()
{
uint8_t trx;
struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
@@ -851,18 +855,11 @@ void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
if (!new_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli(),
1, len);
bts->llc_dropped_frame();
return;
}
new_tbf->set_ms(ms());
/* Start with the passed frame */
new_tbf->m_llc.put_frame(data, len);
bts->llc_frame_sched();
/* reset rlc states */
m_tx_counter = 0;
m_wait_confirm = 0;

View File

@@ -27,6 +27,7 @@
#include <gprs_debug.h>
#include <gprs_bssgp_pcu.h>
#include <decoding.h>
#include <pcu_l1_if.h>
extern "C" {
#include <osmocom/core/msgb.h>
@@ -261,10 +262,12 @@ struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn)
return msg;
}
int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi)
int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(const uint8_t *data,
size_t len, struct pcu_l1_meas *meas)
{
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
int rc;
int8_t rssi = meas->have_rssi ? meas->rssi : 0;
const uint16_t mod_sns = m_window.mod_sns();
const uint16_t ws = m_window.ws();
@@ -278,6 +281,10 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t
/* process RSSI */
gprs_rlcmac_rssi(this, rssi);
/* store measurement values */
if (ms())
ms()->update_l1_meas(meas);
/* get TLLI */
if (!this->is_tlli_valid()) {
if (!extract_tlli(data, len))

View File

@@ -1,6 +1,6 @@
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/
check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest
check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest
noinst_PROGRAMS = emu/pcu_emu
rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp
@@ -54,6 +54,17 @@ ms_MsTest_LDADD = \
ms_MsTest_LDFLAGS = \
-Wl,-u,bssgp_prim_cb
llc_LlcTest_SOURCES = llc/LlcTest.cpp
llc_LlcTest_LDADD = \
$(top_builddir)/src/libgprs.la \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(COMMON_LA)
llc_LlcTest_LDFLAGS = \
-Wl,-u,bssgp_prim_cb
llist_LListTest_SOURCES = llist/LListTest.cpp
llist_LListTest_LDADD = \
$(LIBOSMOCORE_LIBS) \
@@ -84,6 +95,7 @@ EXTRA_DIST = \
tbf/TbfTest.ok tbf/TbfTest.err \
types/TypesTest.ok types/TypesTest.err \
ms/MsTest.ok ms/MsTest.err \
llc/LlcTest.ok llc/LlcTest.err \
llist/LListTest.ok llist/LListTest.err
DISTCLEANFILES = atconfig

View File

@@ -37,14 +37,14 @@ void *tall_pcu_ctx;
int16_t spoof_mnc = 0, spoof_mcc = 0;
static gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, gprs_rlcmac_tbf_direction dir,
GprsMs *ms, gprs_rlcmac_tbf_direction dir,
uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
if (dir == GPRS_RLCMAC_UL_TBF)
return tbf_alloc_ul_tbf(bts, old_tbf, tfi, trx, ms_class, single_slot);
return tbf_alloc_ul_tbf(bts, ms, tfi, trx, ms_class, single_slot);
else
return tbf_alloc_dl_tbf(bts, old_tbf, tfi, trx, ms_class, single_slot);
return tbf_alloc_dl_tbf(bts, ms, tfi, trx, ms_class, single_slot);
}
static void test_alloc_a(gprs_rlcmac_tbf_direction dir, const int count)
@@ -152,7 +152,7 @@ static void test_alloc_b(int ms_class)
/* assume final ack has not been sent */
tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
OSMO_ASSERT(tfi >= 0);
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx_no, ms_class, 0);
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), tfi, trx_no, ms_class, 0);
OSMO_ASSERT(dl_tbf);
dump_assignment(dl_tbf, "DL");
@@ -194,7 +194,7 @@ static void test_alloc_b(int ms_class)
tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
OSMO_ASSERT(tfi >= 0);
ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx_no, ms_class, 0);
ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), tfi, trx_no, ms_class, 0);
ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
ul_tbf->m_contention_resolution_done = 1;
OSMO_ASSERT(ul_tbf);
@@ -241,7 +241,7 @@ static void test_alloc_b(int ms_class)
/* assume final ack has not been sent */
tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
OSMO_ASSERT(tfi >= 0);
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx_no, ms_class, 0);
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), tfi, trx_no, ms_class, 0);
OSMO_ASSERT(dl_tbf);
dump_assignment(dl_tbf, "DL");
@@ -304,7 +304,7 @@ static void test_alloc_b(bool ts0, bool ts1, bool ts2, bool ts3, bool ts4, bool
/* assume final ack has not been sent */
tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
OSMO_ASSERT(tfi >= 0);
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx_no, ms_class, 0);
dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), tfi, trx_no, ms_class, 0);
OSMO_ASSERT(dl_tbf);
/* verify that both are on the same ts */
@@ -348,7 +348,7 @@ static void test_alloc_b(bool ts0, bool ts1, bool ts2, bool ts3, bool ts4, bool
tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
OSMO_ASSERT(tfi >= 0);
ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx_no, ms_class, 0);
ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), tfi, trx_no, ms_class, 0);
OSMO_ASSERT(ul_tbf);
ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
ul_tbf->m_contention_resolution_done = 1;

211
tests/llc/LlcTest.cpp Normal file
View File

@@ -0,0 +1,211 @@
/*
* LlcTest.cpp
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
extern "C" {
#include <osmocom/core/linuxlist.h>
}
#include "llc.h"
#include "gprs_debug.h"
extern "C" {
#include "pcu_vty.h"
#include <osmocom/core/application.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/vty/vty.h>
}
void *tall_pcu_ctx;
int16_t spoof_mnc = 0, spoof_mcc = 0;
static void enqueue_data(gprs_llc_queue *queue, const uint8_t *data, size_t len,
gprs_llc_queue::MetaInfo *info = 0)
{
struct timeval *tv;
uint8_t *msg_data;
struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
"llc_pdu_queue");
msg_data = (uint8_t *)msgb_put(llc_msg, len);
memcpy(msg_data, data, len);
queue->enqueue(llc_msg, info);
}
static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,
size_t len, const gprs_llc_queue::MetaInfo *exp_info = 0)
{
struct msgb *llc_msg;
uint8_t *msg_data;
const gprs_llc_queue::MetaInfo *info_res;
llc_msg = queue->dequeue(&info_res);
OSMO_ASSERT(llc_msg != NULL);
fprintf(stderr, "dequeued msg, length %d (expected %d), data %s\n",
msgb_length(llc_msg), len, msgb_hexdump(llc_msg));
OSMO_ASSERT(msgb_length(llc_msg) == len);
msg_data = msgb_data(llc_msg);
OSMO_ASSERT(memcmp(msg_data, exp_data, len) == 0);
if (exp_info)
OSMO_ASSERT(memcmp(exp_info, info_res, sizeof(*exp_info)) == 0);
msgb_free(llc_msg);
}
static void enqueue_data(gprs_llc_queue *queue, const char *message,
gprs_llc_queue::MetaInfo *info = 0)
{
enqueue_data(queue, (uint8_t *)(message), strlen(message), info);
}
static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message,
const gprs_llc_queue::MetaInfo *exp_info = 0)
{
dequeue_and_check(queue,
(uint8_t *)(exp_message), strlen(exp_message), exp_info);
}
static void test_llc_queue()
{
gprs_llc_queue queue;
printf("=== start %s ===\n", __func__);
queue.init();
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
enqueue_data(&queue, "LLC message");
OSMO_ASSERT(queue.size() == 1);
OSMO_ASSERT(queue.octets() == 11);
enqueue_data(&queue, "other LLC message");
OSMO_ASSERT(queue.size() == 2);
OSMO_ASSERT(queue.octets() == 28);
dequeue_and_check(&queue, "LLC message");
OSMO_ASSERT(queue.size() == 1);
OSMO_ASSERT(queue.octets() == 17);
dequeue_and_check(&queue, "other LLC message");
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
enqueue_data(&queue, "LLC");
OSMO_ASSERT(queue.size() == 1);
OSMO_ASSERT(queue.octets() == 3);
queue.clear(NULL);
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
printf("=== end %s ===\n", __func__);
}
static void test_llc_meta()
{
gprs_llc_queue queue;
gprs_llc_queue::MetaInfo info1 = {
.recv_time = {123456777, 123456},
.expire_time = {123456789, 987654},
};
gprs_llc_queue::MetaInfo info2 = {
.recv_time = {987654321, 547352},
.expire_time = {987654327, 867252},
};
printf("=== start %s ===\n", __func__);
queue.init();
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
enqueue_data(&queue, "LLC message 1", &info1);
enqueue_data(&queue, "LLC message 2", &info2);
dequeue_and_check(&queue, "LLC message 1", &info1);
dequeue_and_check(&queue, "LLC message 2", &info2);
queue.clear(NULL);
OSMO_ASSERT(queue.size() == 0);
OSMO_ASSERT(queue.octets() == 0);
printf("=== end %s ===\n", __func__);
}
static const struct log_info_cat default_categories[] = {
{"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1},
};
static int filter_fn(const struct log_context *ctx,
struct log_target *tar)
{
return 1;
}
const struct log_info debug_log_info = {
filter_fn,
(struct log_info_cat*)default_categories,
ARRAY_SIZE(default_categories),
};
int main(int argc, char **argv)
{
struct vty_app_info pcu_vty_info = {0};
tall_pcu_ctx = talloc_named_const(NULL, 1, "LlcTest context");
if (!tall_pcu_ctx)
abort();
msgb_set_talloc_ctx(tall_pcu_ctx);
osmo_init_logging(&debug_log_info);
log_set_use_color(osmo_stderr_target, 0);
log_set_print_filename(osmo_stderr_target, 0);
log_set_log_level(osmo_stderr_target, LOGL_INFO);
vty_init(&pcu_vty_info);
pcu_vty_init(&debug_log_info);
test_llc_queue();
test_llc_meta();
if (getenv("TALLOC_REPORT_FULL"))
talloc_report_full(tall_pcu_ctx, stderr);
return EXIT_SUCCESS;
}
extern "C" {
void l1if_pdch_req() { abort(); }
void l1if_connect_pdch() { abort(); }
void l1if_close_pdch() { abort(); }
void l1if_open_pdch() { abort(); }
}

4
tests/llc/LlcTest.err Normal file
View File

@@ -0,0 +1,4 @@
dequeued msg, length 11 (expected 11), data 4c 4c 43 20 6d 65 73 73 61 67 65
dequeued msg, length 17 (expected 17), data 6f 74 68 65 72 20 4c 4c 43 20 6d 65 73 73 61 67 65
dequeued msg, length 13 (expected 13), data 4c 4c 43 20 6d 65 73 73 61 67 65 20 31
dequeued msg, length 13 (expected 13), data 4c 4c 43 20 6d 65 73 73 61 67 65 20 32

4
tests/llc/LlcTest.ok Normal file
View File

@@ -0,0 +1,4 @@
=== start test_llc_queue ===
=== end test_llc_queue ===
=== start test_llc_meta ===
=== end test_llc_meta ===

View File

@@ -24,6 +24,7 @@
#include "gprs_debug.h"
#include "gprs_ms.h"
#include "gprs_ms_storage.h"
#include "bts.h"
extern "C" {
#include "pcu_vty.h"
@@ -468,6 +469,42 @@ static void test_ms_timeout()
printf("=== end %s ===\n", __func__);
}
static void test_ms_cs_selection()
{
BTS the_bts;
gprs_rlcmac_bts *bts = the_bts.bts_data();
uint32_t tlli = 0xffeeddbb;
gprs_rlcmac_dl_tbf *dl_tbf;
GprsMs *ms;
printf("=== start %s ===\n", __func__);
bts->initial_cs_dl = 4;
bts->initial_cs_ul = 1;
bts->cs_downgrade_threshold = 0;
ms = new GprsMs(&the_bts, tlli);
OSMO_ASSERT(ms->is_idle());
dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
dl_tbf->direction = GPRS_RLCMAC_DL_TBF;
dl_tbf->set_ms(ms);
OSMO_ASSERT(!ms->is_idle());
OSMO_ASSERT(ms->current_cs_dl() == 4);
bts->cs_downgrade_threshold = 200;
OSMO_ASSERT(ms->current_cs_dl() == 3);
talloc_free(dl_tbf);
printf("=== end %s ===\n", __func__);
}
static const struct log_info_cat default_categories[] = {
{"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1},
};
@@ -507,6 +544,7 @@ int main(int argc, char **argv)
test_ms_change_tlli();
test_ms_storage();
test_ms_timeout();
test_ms_cs_selection();
if (getenv("TALLOC_REPORT_FULL"))
talloc_report_full(tall_pcu_ctx, stderr);

View File

@@ -54,3 +54,5 @@ Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000
Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL)
Timeout for MS object, TLLI = 0xffeeddbb
Destroying MS object, TLLI = 0xffeeddbb
Creating MS object, TLLI = 0xffeeddbb
Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0xffeeddbb DIR=DL STATE=NULL)

View File

@@ -16,3 +16,5 @@
ms_active() was called
ms_idle() was called
=== end test_ms_timeout ===
=== start test_ms_cs_selection ===
=== end test_ms_cs_selection ===

View File

@@ -76,14 +76,12 @@ static void test_tbf_tlli_update()
gprs_rlcmac_tbf *dl_tbf = tbf_alloc_dl_tbf(the_bts.bts_data(),
NULL, 0,
0, 0, 0);
dl_tbf->update_tlli(0x2342);
dl_tbf->update_ms(0x2342, GPRS_RLCMAC_DL_TBF);
dl_tbf->set_ta(4);
gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),
dl_tbf, 0,
dl_tbf->ms(), 0,
0, 0, 0);
ul_tbf->update_tlli(0x2342);
ul_tbf->update_ms(0x2342, GPRS_RLCMAC_UL_TBF);
ms = the_bts.ms_by_tlli(0x2342);
@@ -96,7 +94,6 @@ static void test_tbf_tlli_update()
* Now check.. that DL changes and that the timing advance
* has changed.
*/
dl_tbf->update_tlli(0x4232);
dl_tbf->update_ms(0x4232, GPRS_RLCMAC_DL_TBF);
/* It is still there, since the new TLLI has not been used for UL yet */
@@ -427,6 +424,75 @@ static void test_tbf_exhaustion()
gprs_bssgp_destroy();
}
static void test_tbf_dl_llc_loss()
{
BTS the_bts;
gprs_rlcmac_bts *bts;
uint8_t ts_no = 4;
uint8_t ms_class = 45;
int rc = 0;
uint32_t tlli = 0xc0123456;
const char *imsi = "001001000123456";
unsigned delay_csec = 1000;
GprsMs *ms;
uint8_t buf[19];
printf("=== start %s ===\n", __func__);
bts = the_bts.bts_data();
setup_bts(&the_bts, ts_no);
bts->ms_idle_sec = 10; /* keep the MS object */
gprs_bssgp_create_and_connect(bts, 33001, 0, 33001,
1234, 1234, 1234, 1, 1, 0, 0, 0);
/* Handle LLC frame 1 */
memset(buf, 1, sizeof(buf));
rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class,
delay_csec, buf, sizeof(buf));
OSMO_ASSERT(rc >= 0);
ms = the_bts.ms_store().get_ms(0, 0, imsi);
OSMO_ASSERT(ms != NULL);
OSMO_ASSERT(ms->dl_tbf() != NULL);
/* Handle LLC frame 2 */
memset(buf, 2, sizeof(buf));
rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class,
delay_csec, buf, sizeof(buf));
OSMO_ASSERT(rc >= 0);
/* TBF establishment fails (timeout) */
tbf_free(ms->dl_tbf());
/* Handle LLC frame 3 */
memset(buf, 3, sizeof(buf));
rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class,
delay_csec, buf, sizeof(buf));
OSMO_ASSERT(rc >= 0);
OSMO_ASSERT(ms->dl_tbf() != NULL);
/* Get first BSN */
struct msgb *msg;
int fn = 0;
uint8_t expected_data = 1;
while (ms->dl_tbf()->have_data()) {
msg = ms->dl_tbf()->create_dl_acked_block(fn += 4, 7);
fprintf(stderr, "MSG = %s\n", msgb_hexdump(msg));
OSMO_ASSERT(msgb_length(msg) == 23);
OSMO_ASSERT(msgb_data(msg)[10] == expected_data);
expected_data += 1;
}
OSMO_ASSERT(expected_data-1 == 3);
printf("=== end %s ===\n", __func__);
gprs_bssgp_destroy();
}
static void test_tbf_single_phase()
{
BTS the_bts;
@@ -438,6 +504,7 @@ static void test_tbf_single_phase()
int tfi = 0;
gprs_rlcmac_ul_tbf *ul_tbf;
struct gprs_rlcmac_pdch *pdch;
struct pcu_l1_meas meas;
printf("=== start %s ===\n", __func__);
@@ -462,7 +529,7 @@ static void test_tbf_single_phase()
};
pdch = &the_bts.bts_data()->trx[trx_no].pdch[ts_no];
pdch->rcv_block(&data_msg[0], sizeof(data_msg), fn, 0);
pdch->rcv_block(&data_msg[0], sizeof(data_msg), fn, &meas);
ms = the_bts.ms_by_tlli(0xf1223344);
OSMO_ASSERT(ms != NULL);
@@ -491,6 +558,8 @@ static void test_tbf_two_phase()
bitvec *rlc_block;
uint8_t buf[64];
int num_bytes;
struct pcu_l1_meas meas;
meas.set_rssi(31);
printf("=== start %s ===\n", __func__);
@@ -520,7 +589,7 @@ static void test_tbf_two_phase()
bitvec_free(rlc_block);
pdch = &the_bts.bts_data()->trx[trx_no].pdch[ts_no];
pdch->rcv_block(&buf[0], num_bytes, 2654270, 31);
pdch->rcv_block(&buf[0], num_bytes, 2654270, &meas);
/* check the TBF */
ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no);
@@ -543,7 +612,7 @@ static void test_tbf_two_phase()
uint8_t(1), /* BSN:7, E:1 */
};
pdch->rcv_block(&data_msg[0], sizeof(data_msg), rts_fn, 31);
pdch->rcv_block(&data_msg[0], sizeof(data_msg), rts_fn, &meas);
ms = the_bts.ms_by_tlli(0xf1223344);
OSMO_ASSERT(ms != NULL);
@@ -602,6 +671,7 @@ int main(int argc, char **argv)
test_tbf_delayed_release();
test_tbf_imsi();
test_tbf_exhaustion();
test_tbf_dl_llc_loss();
test_tbf_single_phase();
test_tbf_two_phase();

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,8 @@
=== end test_tbf_imsi ===
=== start test_tbf_exhaustion ===
=== end test_tbf_exhaustion ===
=== start test_tbf_dl_llc_loss ===
=== end test_tbf_dl_llc_loss ===
=== start test_tbf_single_phase ===
=== end test_tbf_single_phase ===
=== start test_tbf_two_phase ===

View File

@@ -37,6 +37,13 @@ cat $abs_srcdir/ms/MsTest.err > experr
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/ms/MsTest], [0], [expout], [experr])
AT_CLEANUP
AT_SETUP([llc])
AT_KEYWORDS([llc])
cat $abs_srcdir/llc/LlcTest.ok > expout
cat $abs_srcdir/llc/LlcTest.err > experr
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/llc/LlcTest], [0], [expout], [experr])
AT_CLEANUP
AT_SETUP([llist])
AT_KEYWORDS([llist])
cat $abs_srcdir/llist/LListTest.ok > expout