aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-08-07 16:00:56 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2012-08-07 16:00:56 +0200
commit07e97cf8a551b05d7f5f3f9583b68b2eff0f1c23 (patch)
tree2e5663d0d7d23aa4153b079894f20b94515fbd7c /src
parentcbcd124588abf91be129aee3f37505ca60706de9 (diff)
Adding single block allocation
It is mandatory to support it because MS may request a single block. In this case the network must assign a single block. It is possible to force single block allocation for all uplink requests on RACH. (VTY option)
Diffstat (limited to 'src')
-rw-r--r--src/gprs_rlcmac.cpp117
-rw-r--r--src/gprs_rlcmac.h21
-rw-r--r--src/gprs_rlcmac_data.cpp213
-rw-r--r--src/gprs_rlcmac_sched.cpp40
-rw-r--r--src/pcu_l1_if.cpp15
-rw-r--r--src/pcu_vty.c28
6 files changed, 344 insertions, 90 deletions
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 956d52fc..1aeb9b18 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -879,6 +879,67 @@ void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf)
}
}
+/* starting time for assigning single slot
+ * This offset must be a multiple of 13. */
+#define AGCH_START_OFFSET 52
+
+LLIST_HEAD(gprs_rlcmac_sbas);
+
+int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta)
+{
+
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+ struct gprs_rlcmac_pdch *pdch;
+ struct gprs_rlcmac_sba *sba;
+ uint8_t trx, ts;
+ uint32_t fn;
+
+ sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba);
+ if (!sba)
+ return -ENOMEM;
+
+ for (trx = 0; trx < 8; trx++) {
+ for (ts = 0; ts < 8; ts++) {
+ pdch = &bts->trx[trx].pdch[ts];
+ if (!pdch->enable)
+ continue;
+ break;
+ }
+ if (ts < 8)
+ break;
+ }
+ if (trx == 8) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
+ return -EINVAL;
+ }
+
+ fn = (pdch->last_rts_fn + AGCH_START_OFFSET) % 2715648;
+
+ sba->trx = trx;
+ sba->ts = ts;
+ sba->fn = fn;
+ sba->ta = ta;
+
+ llist_add(&sba->list, &gprs_rlcmac_sbas);
+
+ *_trx = trx;
+ *_ts = ts;
+ *_fn = fn;
+ return 0;
+}
+
+struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn)
+{
+ struct gprs_rlcmac_sba *sba;
+
+ llist_for_each_entry(sba, &gprs_rlcmac_sbas, list) {
+ if (sba->trx == trx && sba->ts == ts && sba->fn == fn)
+ return sba;
+ }
+
+ return NULL;
+}
+
#if 0
static void tbf_gsm_timer_cb(void *_tbf)
{
@@ -1129,9 +1190,9 @@ struct msgb *gprs_rlcmac_send_packet_paging_request(
// GSM 04.08 9.1.18 Immediate assignment
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
- uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
+ 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 poll_fn)
+ uint8_t polling, uint32_t fn, uint8_t single_block)
{
unsigned wp = 0;
uint8_t plen;
@@ -1157,9 +1218,9 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
//10.5.2.30 Request Reference
bitvec_write_field(dest, wp,ra,8); // RA
- bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
- bitvec_write_field(dest, wp,fn % 51,6); // T3
- bitvec_write_field(dest, wp,fn % 26,5); // T2
+ bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1'
+ bitvec_write_field(dest, wp,ref_fn % 51,6); // T3
+ bitvec_write_field(dest, wp,ref_fn % 26,5); // T2
// 10.5.2.40 Timing Advance
bitvec_write_field(dest, wp,0x0,2); // spare
@@ -1193,9 +1254,9 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX
if (polling) {
bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present
- bitvec_write_field(dest, wp,(poll_fn / (26 * 51)) % 32,5); // T1'
- bitvec_write_field(dest, wp,poll_fn % 51,6); // T3
- bitvec_write_field(dest, wp,poll_fn % 26,5); // T2
+ bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
+ bitvec_write_field(dest, wp,fn % 51,6); // T3
+ bitvec_write_field(dest, wp,fn % 26,5); // T2
} else {
bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present
}
@@ -1209,20 +1270,32 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
// GMS 04.08 10.5.2.37b 10.5.2.16
bitvec_write_field(dest, wp, 3, 2); // "HH"
bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment
- bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation
- bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
- bitvec_write_field(dest, wp, 0, 1); // POLLING
- bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
- bitvec_write_field(dest, wp, usf, 3); // USF
- bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY
- bitvec_write_field(dest, wp, 0 , 1); // "0" power control: Not Present
- bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
- bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING
- bitvec_write_field(dest, wp, 1 , 1); // "1" Alpha : Present
- bitvec_write_field(dest, wp, 0, 4); // Alpha
- bitvec_write_field(dest, wp, 0, 5); // Gamma
- bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
- bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
+ if (single_block) {
+ bitvec_write_field(dest, wp, 0, 1); // Block Allocation : Single Block Allocation
+ bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present
+ bitvec_write_field(dest, wp, 0, 4); // Alpha
+ bitvec_write_field(dest, wp, 0, 5); // Gamma
+ bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
+ bitvec_write_field(dest, wp, 1, 1); // TBF_STARTING_TIME_FLAG
+ bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
+ bitvec_write_field(dest, wp,fn % 51,6); // T3
+ bitvec_write_field(dest, wp,fn % 26,5); // T2
+ } else {
+ bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation
+ bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
+ bitvec_write_field(dest, wp, 0, 1); // POLLING
+ bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
+ bitvec_write_field(dest, wp, usf, 3); // USF
+ bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY
+ bitvec_write_field(dest, wp, 0, 1); // "0" power control: Not Present
+ bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
+ bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING
+ bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present
+ bitvec_write_field(dest, wp, 0, 4); // Alpha
+ bitvec_write_field(dest, wp, 0, 5); // Gamma
+ bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
+ bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
+ }
}
return plen;
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index e1c8343f..5890bf06 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -79,6 +79,7 @@ struct gprs_rlcmac_bts {
int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf,
struct gprs_rlcmac_tbf *tbf, uint32_t cust);
uint32_t alloc_algorithm_curst; /* options to customize algorithm */
+ uint8_t force_two_phase;
};
extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
@@ -219,6 +220,7 @@ struct gprs_rlcmac_tbf {
extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */
extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */
+extern struct llist_head gprs_rlcmac_sbas; /* list of single block allocs */
/*
* paging entry
@@ -229,6 +231,21 @@ struct gprs_rlcmac_paging {
uint8_t identity_lv[9];
};
+/*
+ * single block allocation entry
+ */
+struct gprs_rlcmac_sba {
+ struct llist_head list;
+ uint8_t trx;
+ uint8_t ts;
+ uint32_t fn;
+ uint8_t ta;
+};
+
+int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);
+
+struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn);
+
int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
int8_t use_trx, int8_t first_ts);
@@ -270,9 +287,9 @@ int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
uint32_t fn);
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
- uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
+ 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 poll_fn);
+ uint32_t fn, uint8_t single_block);
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index a1bed3c6..98ce1b4b 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -185,11 +185,61 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
return 0;
}
+static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
+{
+ int i;
+
+ for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
+ if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
+ continue;
+ if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_GPRS_multislot_class)
+ continue;
+ return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.GPRS_multislot_class;
+ }
+
+ return 0;
+}
+
+static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, int8_t first_ts,
+ uint8_t ms_class, uint32_t tlli, uint8_t ta,
+ struct gprs_rlcmac_tbf *dl_tbf)
+{
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+ uint8_t trx, ts;
+ struct gprs_rlcmac_tbf *tbf;
+ uint8_t tfi;
+
+ /* create new TBF, use sme TRX as DL TBF */
+ tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, use_trx, first_ts);
+ if (tfi < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+ /* FIXME: send reject */
+ return NULL;
+ }
+ /* use multislot class of downlink TBF */
+ tbf = tbf_alloc(dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, ms_class, 0);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+ /* FIXME: send reject */
+ return NULL;
+ }
+ tbf->tlli = tlli;
+ tbf->tlli_valid = 1; /* no contention resolution */
+ tbf->dir.ul.contention_resolution_done = 1;
+ tbf->ta = ta; /* use current TA */
+ tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN);
+ tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
+ tbf_timer_start(tbf, 3169, bts->t3169, 0);
+
+ return tbf;
+}
+
+
+
/* Received Uplink RLC control block. */
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
uint32_t fn)
{
- struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
int8_t tfi = 0; /* must be signed */
uint32_t tlli = 0;
struct gprs_rlcmac_tbf *tbf;
@@ -318,34 +368,10 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
}
/* check for channel request */
if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) {
- uint8_t trx, ts;
- struct gprs_rlcmac_tbf *ul_tbf;
-
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
"message, so we provide one:\n");
-uplink_request:
- /* create new TBF, use sme TRX as DL TBF */
- tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, tbf->trx, tbf->first_ts);
- if (tfi < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
- /* FIXME: send reject */
- break;
- }
- /* use multislot class of downlink TBF */
- ul_tbf = tbf_alloc(tbf, GPRS_RLCMAC_UL_TBF, tfi, trx,
- ts, tbf->ms_class, 0);
- if (!ul_tbf) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
- /* FIXME: send reject */
- break;
- }
- ul_tbf->tlli = tbf->tlli;
- ul_tbf->tlli_valid = 1; /* no contention resolution */
- ul_tbf->dir.ul.contention_resolution_done = 1;
- ul_tbf->ta = tbf->ta; /* use current TA */
- tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN);
- ul_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
- tbf_timer_start(ul_tbf, 3169, bts->t3169, 0);
+
+ alloc_ul_tbf(tbf->trx, tbf->first_ts, tbf->ms_class, tbf->tlli, tbf->ta, tbf);
/* schedule uplink assignment */
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
}
@@ -355,7 +381,23 @@ uplink_request:
tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI;
tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
if (!tbf) {
- LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TLLI=0x%08x\n", tlli);
+ uint8_t ms_class = 0;
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
+ "in packet ressource request of single "
+ "block, so we provide one:\n");
+ if (ul_control_block->u.Packet_Resource_Request.Exist_MS_Radio_Access_capability)
+ ms_class = get_ms_class_by_capability(&ul_control_block->u.Packet_Resource_Request.MS_Radio_Access_capability);
+ if (!ms_class)
+ LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
+ tbf = alloc_ul_tbf(trx, ts, ms_class, tlli, 0, NULL);
+#warning FIXME TA!!!
+ if (!tbf)
+ break;
+ /* set control ts to current MS's TS, until assignment complete */
+ LOGP(DRLCMAC, LOGL_DEBUG, "Change control TS to %d until assinment is complete.\n", ts);
+ tbf->control_ts = ts;
+ /* schedule uplink assignment */
+ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
break;
}
tfi = tbf->tfi;
@@ -658,11 +700,18 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
int final = (tbf->state == GPRS_RLCMAC_FINISHED);
struct msgb *msg;
- if (final && tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
- LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
- "sheduled for TBF=%d, so we must wait for final uplink "
- "ack...\n", tbf->tfi);
+ if (final) {
+ if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
+ "sheduled for TBF=%d, so we must wait for "
+ "final uplink ack...\n", tbf->tfi);
return NULL;
+ }
+ if (sba_find(tbf->trx, tbf->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");
@@ -907,6 +956,11 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
"assignment...\n", tbf->tfi);
return NULL;
}
+ if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for "
+ "single block allocation...\n");
+ return NULL;
+ }
#endif
/* on down TBF we get the uplink TBF to be assigned. */
@@ -935,8 +989,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
bitvec_unhex(ass_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
write_packet_uplink_assignment(ass_vec, tbf->tfi,
- (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf,
- POLLING_ASSIGNMENT_UL);
+ (tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli,
+ tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL);
bitvec_pack(ass_vec, msgb_put(msg, 23));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
@@ -965,37 +1019,73 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
struct gprs_rlcmac_tbf *tbf;
uint8_t trx, ts;
int8_t tfi; /* must be signed */
+ uint8_t sb = 0;
+ uint32_t sb_fn = 0;
+ int rc;
+ uint8_t plen;
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide "
"one:\n");
- // Create new TBF
- tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
- if (tfi < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
- /* FIXME: send reject */
- return -EBUSY;
- }
- /* set class to 0, since we don't know the multislot class yet */
- tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1);
- if (!tbf) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
- /* FIXME: send reject */
- return -EBUSY;
+ if ((ra & 0xf8) == 0x70) {
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block "
+ "allocation\n");
+ sb = 1;
+ } else if (bts->force_two_phase) {
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single phase access, "
+ "but we force two phase access\n");
+ sb = 1;
}
if (qta < 0)
qta = 0;
if (qta > 252)
qta = 252;
- tbf->ta = qta >> 2;
- tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
- tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
- tbf_timer_start(tbf, 3169, bts->t3169, 0);
- LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
- LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
- LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate Assignment Uplink (AGCH)\n", tbf->tfi);
+ if (sb) {
+ rc = sba_alloc(&trx, &ts, &sb_fn, qta >> 2);
+ if (rc < 0)
+ return rc;
+ LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] RACH qbit-ta=%d "
+ "ra=0x%02x, Fn=%d (%d,%d,%d)\n", qta, ra, Fn,
+ (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
+ LOGP(DRLCMAC, LOGL_INFO, "TX: Immediate Assignment Uplink "
+ "(AGCH)\n");
+ } else {
+ // Create new TBF
+ tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
+ if (tfi < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+ /* FIXME: send reject */
+ return -EBUSY;
+ }
+ /* set class to 0, since we don't know the multislot class yet */
+ tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+ /* FIXME: send reject */
+ return -EBUSY;
+ }
+ tbf->ta = qta >> 2;
+ tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
+ tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
+ tbf_timer_start(tbf, 3169, bts->t3169, 0);
+ LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n",
+ tbf->tfi);
+ LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH "
+ "qbit-ta=%d ra=0x%02x, Fn=%d (%d,%d,%d)\n", tbf->tfi,
+ qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
+ LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate "
+ "Assignment Uplink (AGCH)\n", tbf->tfi);
+ }
bitvec *immediate_assignment = bitvec_alloc(22) /* without plen */;
- bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
- int plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0);
+ bitvec_unhex(immediate_assignment,
+ "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
+ if (sb)
+ plen = write_immediate_assignment(immediate_assignment, 0, ra,
+ Fn, qta >> 2, bts->trx[trx].arfcn, ts,
+ bts->trx[trx].pdch[ts].tsc, 0, 0, 0, 0, sb_fn, 1);
+ else
+ plen = write_immediate_assignment(immediate_assignment, 0, ra,
+ Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc,
+ tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0, 0);
pcu_l1if_tx_agch(immediate_assignment, plen);
bitvec_free(immediate_assignment);
@@ -1355,6 +1445,10 @@ tx_block:
LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
"sheduled in this TS %d, waiting for "
"TS %d\n", ts, tbf->control_ts);
+ else if (sba_find(tbf->trx, ts, (fn + 13) % 2715648))
+ LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
+ "sheduled, because single block alllocation "
+ "already exists\n");
else {
LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this "
"TS %d\n", ts);
@@ -1534,6 +1628,11 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
"assignment...\n", tbf->tfi);
return NULL;
}
+ if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
+ "scheduled for single block allocation...\n");
+ return NULL;
+ }
}
/* on uplink TBF we get the downlink TBF to be assigned. */
@@ -1604,7 +1703,7 @@ static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll,
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. */
- int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn);
+ int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn, 0);
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
bitvec_free(immediate_assignment);
}
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 9ffdfb64..b5deeb0e 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -67,6 +67,26 @@ uint32_t sched_poll(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr,
return poll_fn;
}
+uint32_t sched_sba(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)
+{
+ uint32_t sba_fn;
+ struct gprs_rlcmac_sba *sba;
+
+ /* check special TBF for events */
+ sba_fn = fn + 4;
+ if ((block_nr % 3) == 2)
+ sba_fn ++;
+ sba_fn = sba_fn % 2715648;
+ sba = sba_find(trx, ts, sba_fn);
+ if (sba) {
+ llist_del(&sba->list);
+ talloc_free(sba);
+ return sba_fn;
+ }
+
+ return 0xffffffff;
+}
+
uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)
{
@@ -135,14 +155,15 @@ struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn,
return msg;
}
/* schedule PACKET PAGING REQUEST */
- if (llist_empty(&pdch->paging_list))
- return NULL;
- msg = gprs_rlcmac_send_packet_paging_request(pdch);
- if (msg)
+ if (!llist_empty(&pdch->paging_list))
+ msg = gprs_rlcmac_send_packet_paging_request(pdch);
+ if (msg) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request "
"message at RTS for (TRX=%d, TS=%d)\n", trx, ts);
+ return msg;
+ }
- return msg;
+ return NULL;
}
struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn,
@@ -208,7 +229,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
*ul_ass_tbf = NULL, *ul_ack_tbf = NULL;
uint8_t usf = 0x7;
struct msgb *msg = NULL;
- uint32_t poll_fn;
+ uint32_t poll_fn, sba_fn;
if (trx >= 8 || ts >= 8)
return -EINVAL;
@@ -234,6 +255,13 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
(poll_tbf->direction == GPRS_RLCMAC_UL_TBF)
? "UL" : "DL", poll_tbf->tfi);
/* use free USF */
+ /* else. check for sba */
+ else if ((sba_fn = sched_sba(trx, ts, fn, block_nr) != 0xffffffff))
+ LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
+ "TS=%d FN=%d block_nr=%d scheduling free USF for "
+ "single block allocation at FN=%d\n", trx, ts, fn,
+ block_nr, sba_fn);
+ /* use free USF */
/* else, we search for uplink ressource */
else
usf = sched_select_uplink(trx, ts, fn, block_nr, pdch);
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index e5fbad98..2ed023a3 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -247,11 +247,12 @@ static int pcu_rx_rach_ind(struct gsm_pcu_if_rach_ind *rach_ind)
return rc;
}
-int flush_pdch(struct gprs_rlcmac_pdch *pdch)
+int flush_pdch(struct gprs_rlcmac_pdch *pdch, uint8_t trx, uint8_t ts)
{
uint8_t tfi;
struct gprs_rlcmac_tbf *tbf;
struct gprs_rlcmac_paging *pag;
+ struct gprs_rlcmac_sba *sba, *sba2;
/* kick all TBF on slot */
for (tfi = 0; tfi < 32; tfi++) {
@@ -266,6 +267,13 @@ int flush_pdch(struct gprs_rlcmac_pdch *pdch)
while ((pag = gprs_rlcmac_dequeue_paging(pdch)))
talloc_free(pag);
+ llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) {
+ if (sba->trx == trx && sba->ts == ts) {
+ llist_del(&sba->list);
+ talloc_free(sba);
+ }
+ }
+
return 0;
}
@@ -294,7 +302,8 @@ bssgp_failed:
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
for (ts = 0; ts < 8; ts++) {
if (bts->trx[trx].pdch[ts].enable)
- flush_pdch(&bts->trx[trx].pdch[ts]);
+ flush_pdch(&bts->trx[trx].pdch[ts],
+ trx, ts);
}
}
gprs_bssgp_destroy();
@@ -399,7 +408,7 @@ bssgp_failed:
if (pdch->enable) {
pcu_tx_act_req(trx, ts, 0);
pdch->enable = 0;
- flush_pdch(pdch);
+ flush_pdch(pdch, trx, ts);
}
}
}
diff --git a/src/pcu_vty.c b/src/pcu_vty.c
index e5d37658..39a1b722 100644
--- a/src/pcu_vty.c
+++ b/src/pcu_vty.c
@@ -90,6 +90,8 @@ static int config_write_pcu(struct vty *vty)
vty_out(vty, " alloc-algorithm a%s", VTY_NEWLINE);
if (bts->alloc_algorithm == alloc_algorithm_b)
vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE);
+ if (bts->force_two_phase)
+ vty_out(vty, " two-phase-access%s", VTY_NEWLINE);
}
@@ -193,6 +195,30 @@ DEFUN(cfg_pcu_alloc,
return CMD_SUCCESS;
}
+DEFUN(cfg_pcu_two_phase,
+ cfg_pcu_two_phase_cmd,
+ "two-phase-access",
+ "Force two phase access when MS requests single phase access\n")
+{
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+ bts->force_two_phase = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_pcu_no_two_phase,
+ cfg_pcu_no_two_phase_cmd,
+ "no two-phase-access",
+ NO_STR "Only use two phase access when requested my MS\n")
+{
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+ bts->force_two_phase = 0;
+
+ return CMD_SUCCESS;
+}
+
static const char pcu_copyright[] =
"Copyright (C) 2012 by ...\r\n"
"License GNU GPL version 2 or later\r\n"
@@ -222,6 +248,8 @@ int pcu_vty_init(const struct log_info *cat)
install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd);
install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);
install_element(PCU_NODE, &cfg_pcu_alloc_cmd);
+ install_element(PCU_NODE, &cfg_pcu_two_phase_cmd);
+ install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd);
install_element(PCU_NODE, &ournode_end_cmd);
return 0;