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
|
#if 0
|
||||||
static void tbf_gsm_timer_cb(void *_tbf)
|
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
|
// GSM 04.08 9.1.18 Immediate assignment
|
||||||
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
|
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 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;
|
unsigned wp = 0;
|
||||||
uint8_t plen;
|
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
|
//10.5.2.30 Request Reference
|
||||||
bitvec_write_field(dest, wp,ra,8); // RA
|
bitvec_write_field(dest, wp,ra,8); // RA
|
||||||
bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
|
bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1'
|
||||||
bitvec_write_field(dest, wp,fn % 51,6); // T3
|
bitvec_write_field(dest, wp,ref_fn % 51,6); // T3
|
||||||
bitvec_write_field(dest, wp,fn % 26,5); // T2
|
bitvec_write_field(dest, wp,ref_fn % 26,5); // T2
|
||||||
|
|
||||||
// 10.5.2.40 Timing Advance
|
// 10.5.2.40 Timing Advance
|
||||||
bitvec_write_field(dest, wp,0x0,2); // spare
|
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
|
bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX
|
||||||
if (polling) {
|
if (polling) {
|
||||||
bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present
|
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,(fn / (26 * 51)) % 32,5); // T1'
|
||||||
bitvec_write_field(dest, wp,poll_fn % 51,6); // T3
|
bitvec_write_field(dest, wp,fn % 51,6); // T3
|
||||||
bitvec_write_field(dest, wp,poll_fn % 26,5); // T2
|
bitvec_write_field(dest, wp,fn % 26,5); // T2
|
||||||
} else {
|
} else {
|
||||||
bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present
|
bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present
|
||||||
}
|
}
|
||||||
|
@ -1209,21 +1270,33 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
|
||||||
// GMS 04.08 10.5.2.37b 10.5.2.16
|
// GMS 04.08 10.5.2.37b 10.5.2.16
|
||||||
bitvec_write_field(dest, wp, 3, 2); // "HH"
|
bitvec_write_field(dest, wp, 3, 2); // "HH"
|
||||||
bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment
|
bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment
|
||||||
|
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, 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, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
|
||||||
bitvec_write_field(dest, wp, 0, 1); // POLLING
|
bitvec_write_field(dest, wp, 0, 1); // POLLING
|
||||||
bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
|
bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
|
||||||
bitvec_write_field(dest, wp, usf, 3); // USF
|
bitvec_write_field(dest, wp, usf, 3); // USF
|
||||||
bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY
|
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, 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, 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); // TLLI_BLOCK_CHANNEL_CODING
|
||||||
bitvec_write_field(dest, wp, 1 , 1); // "1" Alpha : Present
|
bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present
|
||||||
bitvec_write_field(dest, wp, 0, 4); // Alpha
|
bitvec_write_field(dest, wp, 0, 4); // Alpha
|
||||||
bitvec_write_field(dest, wp, 0, 5); // Gamma
|
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); // TIMING_ADVANCE_INDEX_FLAG
|
||||||
bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
|
bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return plen;
|
return plen;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ struct gprs_rlcmac_bts {
|
||||||
int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf,
|
int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf,
|
||||||
struct gprs_rlcmac_tbf *tbf, uint32_t cust);
|
struct gprs_rlcmac_tbf *tbf, uint32_t cust);
|
||||||
uint32_t alloc_algorithm_curst; /* options to customize algorithm */
|
uint32_t alloc_algorithm_curst; /* options to customize algorithm */
|
||||||
|
uint8_t force_two_phase;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
|
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_ul_tbfs; /* list of uplink TBFs */
|
||||||
extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink 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
|
* paging entry
|
||||||
|
@ -229,6 +231,21 @@ struct gprs_rlcmac_paging {
|
||||||
uint8_t identity_lv[9];
|
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,
|
int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
|
||||||
int8_t use_trx, int8_t first_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);
|
uint32_t fn);
|
||||||
|
|
||||||
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
|
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,
|
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,
|
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
|
||||||
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
|
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;
|
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. */
|
/* Received Uplink RLC control block. */
|
||||||
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
|
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
|
||||||
uint32_t fn)
|
uint32_t fn)
|
||||||
{
|
{
|
||||||
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
|
|
||||||
int8_t tfi = 0; /* must be signed */
|
int8_t tfi = 0; /* must be signed */
|
||||||
uint32_t tlli = 0;
|
uint32_t tlli = 0;
|
||||||
struct gprs_rlcmac_tbf *tbf;
|
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 */
|
/* check for channel request */
|
||||||
if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) {
|
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 "
|
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
|
||||||
"message, so we provide one:\n");
|
"message, so we provide one:\n");
|
||||||
uplink_request:
|
|
||||||
/* create new TBF, use sme TRX as DL TBF */
|
alloc_ul_tbf(tbf->trx, tbf->first_ts, tbf->ms_class, tbf->tlli, tbf->ta, 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);
|
|
||||||
/* schedule uplink assignment */
|
/* schedule uplink assignment */
|
||||||
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
|
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;
|
tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI;
|
||||||
tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
|
tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
|
||||||
if (!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;
|
break;
|
||||||
}
|
}
|
||||||
tfi = tbf->tfi;
|
tfi = tbf->tfi;
|
||||||
|
@ -658,12 +700,19 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
|
||||||
int final = (tbf->state == GPRS_RLCMAC_FINISHED);
|
int final = (tbf->state == GPRS_RLCMAC_FINISHED);
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
|
|
||||||
if (final && tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
|
if (final) {
|
||||||
|
if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
|
||||||
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
|
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
|
||||||
"sheduled for TBF=%d, so we must wait for final uplink "
|
"sheduled for TBF=%d, so we must wait for "
|
||||||
"ack...\n", tbf->tfi);
|
"final uplink ack...\n", tbf->tfi);
|
||||||
return NULL;
|
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");
|
msg = msgb_alloc(23, "rlcmac_ul_ack");
|
||||||
if (!msg)
|
if (!msg)
|
||||||
|
@ -907,6 +956,11 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
|
||||||
"assignment...\n", tbf->tfi);
|
"assignment...\n", tbf->tfi);
|
||||||
return NULL;
|
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
|
#endif
|
||||||
|
|
||||||
/* on down TBF we get the uplink TBF to be assigned. */
|
/* 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,
|
bitvec_unhex(ass_vec,
|
||||||
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
|
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
|
||||||
write_packet_uplink_assignment(ass_vec, tbf->tfi,
|
write_packet_uplink_assignment(ass_vec, tbf->tfi,
|
||||||
(tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf,
|
(tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli,
|
||||||
POLLING_ASSIGNMENT_UL);
|
tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL);
|
||||||
bitvec_pack(ass_vec, msgb_put(msg, 23));
|
bitvec_pack(ass_vec, msgb_put(msg, 23));
|
||||||
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
|
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
|
||||||
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
|
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
|
||||||
|
@ -965,9 +1019,36 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
|
||||||
struct gprs_rlcmac_tbf *tbf;
|
struct gprs_rlcmac_tbf *tbf;
|
||||||
uint8_t trx, ts;
|
uint8_t trx, ts;
|
||||||
int8_t tfi; /* must be signed */
|
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 "
|
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide "
|
||||||
"one:\n");
|
"one:\n");
|
||||||
|
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;
|
||||||
|
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
|
// Create new TBF
|
||||||
tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
|
tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
|
||||||
if (tfi < 0) {
|
if (tfi < 0) {
|
||||||
|
@ -982,20 +1063,29 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
|
||||||
/* FIXME: send reject */
|
/* FIXME: send reject */
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
if (qta < 0)
|
|
||||||
qta = 0;
|
|
||||||
if (qta > 252)
|
|
||||||
qta = 252;
|
|
||||||
tbf->ta = qta >> 2;
|
tbf->ta = qta >> 2;
|
||||||
tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
|
tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
|
||||||
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
|
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
|
||||||
tbf_timer_start(tbf, 3169, bts->t3169, 0);
|
tbf_timer_start(tbf, 3169, bts->t3169, 0);
|
||||||
LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
|
LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n",
|
||||||
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);
|
tbf->tfi);
|
||||||
LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate Assignment Uplink (AGCH)\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 *immediate_assignment = bitvec_alloc(22) /* without plen */;
|
||||||
bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
|
bitvec_unhex(immediate_assignment,
|
||||||
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);
|
"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);
|
pcu_l1if_tx_agch(immediate_assignment, plen);
|
||||||
bitvec_free(immediate_assignment);
|
bitvec_free(immediate_assignment);
|
||||||
|
|
||||||
|
@ -1355,6 +1445,10 @@ tx_block:
|
||||||
LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
|
LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
|
||||||
"sheduled in this TS %d, waiting for "
|
"sheduled in this TS %d, waiting for "
|
||||||
"TS %d\n", ts, tbf->control_ts);
|
"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 {
|
else {
|
||||||
LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this "
|
LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this "
|
||||||
"TS %d\n", ts);
|
"TS %d\n", ts);
|
||||||
|
@ -1534,6 +1628,11 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
|
||||||
"assignment...\n", tbf->tfi);
|
"assignment...\n", tbf->tfi);
|
||||||
return NULL;
|
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. */
|
/* 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");
|
bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
|
||||||
/* use request reference that has maximum distance to current time,
|
/* use request reference that has maximum distance to current time,
|
||||||
* so the assignment will not conflict with possible RACH requests. */
|
* 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);
|
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
|
||||||
bitvec_free(immediate_assignment);
|
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;
|
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 sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
|
||||||
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)
|
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;
|
return msg;
|
||||||
}
|
}
|
||||||
/* schedule PACKET PAGING REQUEST */
|
/* schedule PACKET PAGING REQUEST */
|
||||||
if (llist_empty(&pdch->paging_list))
|
if (!llist_empty(&pdch->paging_list))
|
||||||
return NULL;
|
|
||||||
msg = gprs_rlcmac_send_packet_paging_request(pdch);
|
msg = gprs_rlcmac_send_packet_paging_request(pdch);
|
||||||
if (msg)
|
if (msg) {
|
||||||
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request "
|
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request "
|
||||||
"message at RTS for (TRX=%d, TS=%d)\n", trx, ts);
|
"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,
|
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;
|
*ul_ass_tbf = NULL, *ul_ack_tbf = NULL;
|
||||||
uint8_t usf = 0x7;
|
uint8_t usf = 0x7;
|
||||||
struct msgb *msg = NULL;
|
struct msgb *msg = NULL;
|
||||||
uint32_t poll_fn;
|
uint32_t poll_fn, sba_fn;
|
||||||
|
|
||||||
if (trx >= 8 || ts >= 8)
|
if (trx >= 8 || ts >= 8)
|
||||||
return -EINVAL;
|
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)
|
(poll_tbf->direction == GPRS_RLCMAC_UL_TBF)
|
||||||
? "UL" : "DL", poll_tbf->tfi);
|
? "UL" : "DL", poll_tbf->tfi);
|
||||||
/* use free USF */
|
/* 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, we search for uplink ressource */
|
||||||
else
|
else
|
||||||
usf = sched_select_uplink(trx, ts, fn, block_nr, pdch);
|
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;
|
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;
|
uint8_t tfi;
|
||||||
struct gprs_rlcmac_tbf *tbf;
|
struct gprs_rlcmac_tbf *tbf;
|
||||||
struct gprs_rlcmac_paging *pag;
|
struct gprs_rlcmac_paging *pag;
|
||||||
|
struct gprs_rlcmac_sba *sba, *sba2;
|
||||||
|
|
||||||
/* kick all TBF on slot */
|
/* kick all TBF on slot */
|
||||||
for (tfi = 0; tfi < 32; tfi++) {
|
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)))
|
while ((pag = gprs_rlcmac_dequeue_paging(pdch)))
|
||||||
talloc_free(pag);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +302,8 @@ bssgp_failed:
|
||||||
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
|
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
|
||||||
for (ts = 0; ts < 8; ts++) {
|
for (ts = 0; ts < 8; ts++) {
|
||||||
if (bts->trx[trx].pdch[ts].enable)
|
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();
|
gprs_bssgp_destroy();
|
||||||
|
@ -399,7 +408,7 @@ bssgp_failed:
|
||||||
if (pdch->enable) {
|
if (pdch->enable) {
|
||||||
pcu_tx_act_req(trx, ts, 0);
|
pcu_tx_act_req(trx, ts, 0);
|
||||||
pdch->enable = 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);
|
vty_out(vty, " alloc-algorithm a%s", VTY_NEWLINE);
|
||||||
if (bts->alloc_algorithm == alloc_algorithm_b)
|
if (bts->alloc_algorithm == alloc_algorithm_b)
|
||||||
vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE);
|
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;
|
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[] =
|
static const char pcu_copyright[] =
|
||||||
"Copyright (C) 2012 by ...\r\n"
|
"Copyright (C) 2012 by ...\r\n"
|
||||||
"License GNU GPL version 2 or later\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_queue_lifetime_inf_cmd);
|
||||||
install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_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_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);
|
install_element(PCU_NODE, &ournode_end_cmd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue