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)
This commit is contained in:
parent
cbcd124588
commit
07e97cf8a5
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue