Added paging for RR connection on PACCH of active TBFs
Untested
This commit is contained in:
parent
8389fd0513
commit
2b91464862
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue