Added paging for RR connection on PACCH of active TBFs

Untested
This commit is contained in:
Andreas Eversberg 2012-07-19 13:06:26 +02:00
parent 8389fd0513
commit 2b91464862
4 changed files with 282 additions and 27 deletions

View File

@ -73,6 +73,11 @@ struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = {
LLIST_HEAD(gprs_rlcmac_ul_tbfs);
LLIST_HEAD(gprs_rlcmac_dl_tbfs);
llist_head *gprs_rlcmac_tbfs_lists[] = {
&gprs_rlcmac_ul_tbfs,
&gprs_rlcmac_dl_tbfs,
NULL
};
void *rlcmac_tall_ctx;
/* FIXME: spread ressources over multiple TRX. Also add option to use same
@ -950,6 +955,172 @@ int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
return rc;
}
/* add paging to paging queue(s) */
int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
uint8_t l, trx, ts, any_tbf = 0;
struct gprs_rlcmac_tbf *tbf;
struct gprs_rlcmac_paging *pag;
uint8_t slot_mask[8];
int8_t first_ts; /* must be signed */
LOGP(DRLCMAC, LOGL_INFO, "Add CS paging\n");
/* collect slots to page
* Mark slots for every TBF, but only mark one of it.
* Mark only the first slot found.
* Don't mark, if TBF uses a different slot that is already marked. */
memset(slot_mask, 0, sizeof(slot_mask));
for (l = 0; gprs_rlcmac_tbfs_lists[l]; l++) {
llist_for_each_entry(tbf, gprs_rlcmac_tbfs_lists[l], list) {
first_ts = -1;
for (ts = 0; ts < 8; ts++) {
if (tbf->pdch[ts]) {
/* remember the first slot found */
if (first_ts < 0)
first_ts = ts;
/* break, if we already marked a slot */
if ((slot_mask[tbf->trx] & (1 << ts)))
break;
}
}
/* mark first slot found, if none is marked already */
if (ts == 8 && first_ts >= 0) {
LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
"TRX=%d TS=%d, so we mark\n",
(tbf->direction == GPRS_RLCMAC_UL_TBF)
? "UL" : "DL",
tbf->tfi, tbf->trx, ts);
slot_mask[tbf->trx] |= (1 << first_ts);
} else
LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
"already marked TRX=%d TS=%d\n",
(tbf->direction == GPRS_RLCMAC_UL_TBF)
? "UL" : "DL",
tbf->tfi, tbf->trx, ts);
}
}
/* Now we have a list of marked slots. Every TBF uses at least one
* of these slots. */
/* schedule paging to all marked slots */
for (trx = 0; trx < 8; trx++) {
if (slot_mask[trx] == 0)
continue;
any_tbf = 1;
for (ts = 0; ts < 8; ts++) {
if ((slot_mask[trx] & (1 << ts))) {
/* schedule */
pag = talloc_zero(rlcmac_tall_ctx,
struct gprs_rlcmac_paging);
if (!pag)
return -ENOMEM;
pag->chan_needed = chan_needed;
memcpy(pag->identity_lv, identity_lv,
identity_lv[0] + 1);
llist_add(&pag->list,
&bts->trx[trx].pdch[ts].paging_list);
LOGP(DRLCMAC, LOGL_INFO, "Paging on TRX=%d"
"TS=%d\n", trx, ts);
}
}
}
if (!any_tbf) {
LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n");
}
return 0;
}
struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging(
struct gprs_rlcmac_pdch *pdch)
{
struct gprs_rlcmac_paging *pag;
pag = llist_entry(pdch->paging_list.next,
struct gprs_rlcmac_paging, list);
llist_del(&pag->list);
return pag;
}
struct msgb *gprs_rlcmac_send_packet_paging_request(
struct gprs_rlcmac_pdch *pdch)
{
struct gprs_rlcmac_paging *pag;
struct msgb *msg;
unsigned wp = 0, len;
/* no paging, no message */
pag = gprs_rlcmac_dequeue_paging(pdch);
if (!pag)
return NULL;
LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
/* alloc message */
msg = msgb_alloc(23, "pag ctrl block");
if (!msg)
return NULL;
bitvec *pag_vec = bitvec_alloc(23);
if (!pag_vec) {
msgb_free(msg);
return NULL;
}
wp = write_packet_paging_request(pag_vec);
/* loop until message is full */
while (pag) {
/* try to add paging */
if ((pag->identity_lv[1] & 0x07) == 4) {
/* TMSI */
LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n",
ntohl(*((uint32_t *)(pag->identity_lv + 1))));
len = 1 + 1 + 32 + 2 + 1;
if (pag->identity_lv[0] != 5) {
LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with "
"MI != 5 octets!\n");
break;
}
} else {
/* MI */
LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n",
osmo_hexdump(pag->identity_lv + 1,
pag->identity_lv[0]));
len = 1 + 1 + 4 + (pag->identity_lv[0] << 3) + 2 + 1;
if (pag->identity_lv[0] > 8) {
LOGP(DRLCMAC, LOGL_ERROR, "Paging with "
"MI > 8 octets!\n");
break;
}
}
if (wp + len > 184) {
LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule "
"next time\n");
/* put back paging record, because does not fit */
llist_add_tail(&pag->list, &pdch->paging_list);
break;
}
write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
pag->identity_lv + 1, pag->chan_needed);
pag = gprs_rlcmac_dequeue_paging(pdch);
}
bitvec_pack(pag_vec, msgb_put(msg, 23));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t));
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
LOGPC(DCSN1, LOGL_NOTICE, "\n");
LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
bitvec_free(pag_vec);
return msg;
}
// 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,
@ -1248,6 +1419,44 @@ void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *t
block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.Exist_Power_Control_Parameters = 0x0;
}
unsigned write_packet_paging_request(bitvec * dest)
{
unsigned wp = 0;
bitvec_write_field(dest, wp,0x1,2); // Payload Type
bitvec_write_field(dest, wp,0x0,3); // No polling
bitvec_write_field(dest, wp,0x0,3); // Uplink state flag
bitvec_write_field(dest, wp,0x22,6); // MESSAGE TYPE
bitvec_write_field(dest, wp,0x0,1); // No PERSISTENCE_LEVEL
bitvec_write_field(dest, wp,0x0,1); // No NLN
return wp;
}
unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len,
uint8_t *identity, uint8_t chan_needed)
{
bitvec_write_field(dest, wp,0x1,1); // RR connection paging
if ((identity[0] & 0x07) == 4) {
bitvec_write_field(dest, wp,0x0,1); // TMSI
identity++;
len--;
} else {
bitvec_write_field(dest, wp,0x0,1); // MI
bitvec_write_field(dest, wp,len,4); // MI len
}
while (len) {
bitvec_write_field(dest, wp,*identity++,8); // MI data
len--;
}
bitvec_write_field(dest, wp,chan_needed,2); // CHANNEL_NEEDED
bitvec_write_field(dest, wp,0x0,1); // No eMLPP_PRIORITY
return wp;
}
/* Send Uplink unit-data to SGSN. */
int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf)
{

View File

@ -48,6 +48,7 @@ struct gprs_rlcmac_pdch {
uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */
struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */
struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */
struct llist_head paging_list; /* list of paging messages */
uint32_t last_rts_fn; /* store last frame number of RTS */
};
@ -199,6 +200,15 @@ 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 */
/*
* paging entry
*/
struct gprs_rlcmac_paging {
struct llist_head list;
uint8_t chan_needed;
uint8_t identity_lv[9];
};
int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
uint8_t use_trx, uint8_t first_ts);
@ -285,6 +295,11 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
uint8_t ssn, uint8_t *rbb);
unsigned write_packet_paging_request(bitvec * dest);
unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len,
uint8_t *identity, uint8_t chan_needed);
int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts,
uint8_t *data, uint8_t len);
@ -297,4 +312,12 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv);
struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging(
struct gprs_rlcmac_pdch *pdch);
struct msgb *gprs_rlcmac_send_packet_paging_request(
struct gprs_rlcmac_pdch *pdch);
#endif // GPRS_RLCMAC_H

View File

@ -143,6 +143,10 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
tbf = ul_ack_tbf;
msg = gprs_rlcmac_send_uplink_ack(tbf, fn);
}
/* schedule PACKET PAGING REQUEST */
if (!msg && !llist_empty(&pdch->paging_list)) {
msg = gprs_rlcmac_send_packet_paging_request(pdch);
}
if (msg) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control "
"message at RTS for %s TBF=%d (TRX=%d, TS=%d)\n",

View File

@ -247,12 +247,34 @@ static int pcu_rx_rach_ind(struct gsm_pcu_if_rach_ind *rach_ind)
return rc;
}
int flush_pdch(struct gprs_rlcmac_pdch *pdch)
{
uint8_t tfi;
struct gprs_rlcmac_tbf *tbf;
struct gprs_rlcmac_paging *pag;
/* kick all TBF on slot */
for (tfi = 0; tfi < 32; tfi++) {
tbf = pdch->ul_tbf[tfi];
if (tbf)
tbf_free(tbf);
tbf = pdch->dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
/* flush all pending paging messages */
while ((pag = gprs_rlcmac_dequeue_paging(pdch)))
talloc_free(pag);
return 0;
}
static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_pdch *pdch;
int rc = 0;
int trx, ts, tfi;
struct gprs_rlcmac_tbf *tbf;
int trx, ts;
int i;
if (info_ind->version != PCU_IF_VERSION) {
@ -270,16 +292,8 @@ bssgp_failed:
/* free all TBF */
for (trx = 0; trx < 8; trx++) {
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
for (ts = 0; ts < 8; ts++) {
for (tfi = 0; tfi < 32; tfi++) {
tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
if (tbf)
tbf_free(tbf);
tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
}
for (ts = 0; ts < 8; ts++)
flush_pdch(&bts->trx[trx].pdch[ts]);
}
gprs_bssgp_destroy();
return 0;
@ -366,28 +380,21 @@ bssgp_failed:
for (trx = 0; trx < 8; trx++) {
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
for (ts = 0; ts < 8; ts++) {
pdch = &bts->trx[trx].pdch[ts];
if ((info_ind->trx[trx].pdch_mask & (1 << ts))) {
/* FIXME: activate dynamically at RLCMAC */
if (!bts->trx[trx].pdch[ts].enable)
if (!pdch->enable)
pcu_tx_act_req(trx, ts, 1);
bts->trx[trx].pdch[ts].enable = 1;
bts->trx[trx].pdch[ts].tsc =
info_ind->trx[trx].tsc[ts];
pdch->enable = 1;
pdch->tsc = info_ind->trx[trx].tsc[ts];
INIT_LLIST_HEAD(&pdch->paging_list);
LOGP(DL1IF, LOGL_INFO, "PDCH: trx=%d ts=%d\n",
trx, ts);
} else {
if (bts->trx[trx].pdch[ts].enable)
if (pdch->enable)
pcu_tx_act_req(trx, ts, 0);
bts->trx[trx].pdch[ts].enable = 0;
/* kick all TBF on slot */
for (tfi = 0; tfi < 32; tfi++) {
tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
if (tbf)
tbf_free(tbf);
tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
pdch->enable = 0;
flush_pdch(pdch);
}
}
}
@ -429,6 +436,15 @@ static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
return 0;
}
static int pcu_rx_pag_req(struct gsm_pcu_if_pag_req *pag_req)
{
LOGP(DL1IF, LOGL_DEBUG, "Paging request received: chan_needed=%d "
"length=%d\n", pag_req->chan_needed, pag_req->identity_lv[0]);
return gprs_rlcmac_add_paging(pag_req->chan_needed,
pag_req->identity_lv);
}
int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
{
int rc = 0;
@ -449,6 +465,9 @@ int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
case PCU_IF_MSG_TIME_IND:
rc = pcu_rx_time_ind(&pcu_prim->u.time_ind);
break;
case PCU_IF_MSG_PAG_REQ:
rc = pcu_rx_pag_req(&pcu_prim->u.pag_req);
break;
default:
LOGP(DL1IF, LOGL_ERROR, "Received unknwon PCU msg type %d\n",
msg_type);