Send downlink IMMEDIATE ASSIGNMENT on PCH and not on AGCH

The IMSI is used to define paging group on which it is sent.

This is tested with MS that requires correct paging group.
This commit is contained in:
Andreas Eversberg 2012-07-09 17:10:44 +02:00
parent 88a214cc45
commit e13fa2d569
6 changed files with 69 additions and 23 deletions

View File

@ -32,7 +32,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
struct bssgp_ud_hdr *budh;
int tfi;
uint32_t tlli;
int i = 0;
int i, j;
uint8_t trx, ts;
uint8_t *data;
uint16_t len;
@ -55,22 +55,30 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP TLLI=0x%08x Rx UL-UD IE_LLC_PDU too large\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_COND_IE_ERR, NULL, msg);
}
LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x %s\n", tlli, osmo_hexdump(data, len));
uint16_t imsi_len = 0;
uint8_t *imsi;
/* read IMSI. if no IMSI exists, use first paging block (any paging),
* because during attachment the IMSI might not be known, so the MS
* will listen to all paging blocks. */
char imsi[16] = "000";
if (TLVP_PRESENT(tp, BSSGP_IE_IMSI))
{
imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
imsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_IMSI);
LOGPC(DBSSGP, LOGL_DEBUG, " IMSI = ");
for (i = 0; i < imsi_len; i++)
uint8_t imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
uint8_t *bcd_imsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_IMSI);
if ((bcd_imsi[0] & 0x08))
imsi_len = imsi_len * 2 - 1;
else
imsi_len = (imsi_len - 1) * 2;
for (i = 0, j = 0; j < imsi_len && j < 16; j++)
{
LOGPC(DBSSGP, LOGL_DEBUG, "%02x", imsi[i]);
if (!(j & 1)) {
imsi[j] = (bcd_imsi[i] >> 4) + '0';
i++;
} else
imsi[j] = (bcd_imsi[i] & 0xf) + '0';
}
LOGPC(DBSSGP, LOGL_DEBUG, "\n");
imsi[j] = '\0';
}
LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len);
/* check for existing TBF */
if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) {
@ -82,7 +90,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
tbf->llc_length = len;
memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset
rlc states */
gprs_rlcmac_trigger_downlink_assignment(tbf, 1);
gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL);
} else {
/* the TBF exists, so we must write it in the queue */
struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
@ -114,7 +122,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
* we don't use old_downlink, so the possible uplink is used
* to trigger downlink assignment. if there is no uplink,
* AGCH is used. */
gprs_rlcmac_trigger_downlink_assignment(tbf, 0);
gprs_rlcmac_trigger_downlink_assignment(tbf, 0, imsi);
}
return 0;

View File

@ -252,7 +252,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
uint8_t old_downlink);
uint8_t old_downlink, char *imsi);
int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
uint8_t ssn, uint8_t *rbb);

View File

@ -263,6 +263,9 @@ puts("FIXME: UL request during UL request"); exit(0);
return 1;
}
#ifdef DEBUG_DL_ASS_IDLE
char debug_imsi[16];
#endif
void tbf_timer_cb(void *_tbf)
{
@ -276,7 +279,7 @@ void tbf_timer_cb(void *_tbf)
switch (tbf->T) {
#ifdef DEBUG_DL_ASS_IDLE
case 1234:
gprs_rlcmac_trigger_downlink_assignment(tbf, 0);
gprs_rlcmac_trigger_downlink_assignment(tbf, 0, debug_imsi);
break;
#endif
case 0: /* assignment */
@ -1268,7 +1271,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
LOGP(DRLCMAC, LOGL_DEBUG, "Trigger dowlink assignment on PACCH, "
"because another LLC PDU has arrived in between\n");
memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset RLC states */
gprs_rlcmac_trigger_downlink_assignment(tbf, 1);
gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL);
return 0;
}
@ -1334,25 +1337,27 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
return msg;
}
static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll)
static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll,
char *imsi)
{
LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u TLLI: 0x%08x Immediate Assignment Downlink (AGCH)\n", tbf->tfi, tbf->tlli);
LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u TLLI: 0x%08x Immediate Assignment Downlink (PCH)\n", tbf->tfi, tbf->tlli);
bitvec *immediate_assignment = bitvec_alloc(22); /* without plen */
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->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn);
pcu_l1if_tx_agch(immediate_assignment, plen);
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
bitvec_free(immediate_assignment);
}
/* depending on the current TBF, we assign on PACCH or AGCH */
void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
uint8_t old_downlink)
uint8_t old_downlink, char *imsi)
{
gprs_rlcmac_tbf *old_tbf;
#ifdef DEBUG_DL_ASS_IDLE
strncpy(debug_imsi, imsi);
LOGP(DRLCMAC, LOGL_ERROR, "**** DEBUGGING DOWNLINK ASSIGNMENT ****\n");
#endif
@ -1384,9 +1389,13 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
tbf_timer_start(tbf, 0, Tassign_pacch);
#endif
} else {
LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment for TBF=%d on AGCH, no TBF exist\n", tbf->tfi);
LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment for TBF=%d on PCH, no TBF exist (IMSI=%s)\n", tbf->tfi, imsi);
if (!imsi || strlen(imsi) < 3) {
LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI!\n");
return;
}
/* send immediate assignment */
gprs_rlcmac_downlink_assignment(tbf, 0);
gprs_rlcmac_downlink_assignment(tbf, 0, imsi);
/* change state */
tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN);
/* start timer */

View File

@ -120,7 +120,18 @@ void pcu_l1if_tx_agch(bitvec * block, int plen)
prim->id = GsmL1_PrimId_PhDataReq;
prim->u.phDataReq.sapi = GsmL1_Sapi_Agch;
bitvec_pack(block, prim->u.phDataReq.msgUnitParam.u8Buffer);
#warning Please review, if OpenBTS requires AGCH frame without pseudo length:
prim->u.phDataReq.msgUnitParam.u8Size = 22;
osmo_wqueue_enqueue(&l1fh->udp_wq, msg);
}
void pcu_l1if_tx_pch(bitvec * block, int plen, char *imsi)
{
struct msgb *msg = l1p_msgb_alloc();
GsmL1_Prim_t *prim = msgb_l1prim(msg);
prim->id = GsmL1_PrimId_PhDataReq;
prim->u.phDataReq.sapi = GsmL1_Sapi_Pch;
bitvec_pack(block, prim->u.phDataReq.msgUnitParam.u8Buffer);
prim->u.phDataReq.msgUnitParam.u8Size = 22;
osmo_wqueue_enqueue(&l1fh->udp_wq, msg);
}

View File

@ -36,6 +36,7 @@ void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
void pcu_l1if_tx_agch(bitvec * block, int len);
void pcu_l1if_tx_pch(bitvec * block, int plen, char *imsi);
int pcu_l1if_open(void);
void pcu_l1if_close(void);

View File

@ -150,6 +150,23 @@ void pcu_l1if_tx_agch(bitvec * block, int plen)
pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, 23);
}
void pcu_l1if_tx_pch(bitvec * block, int plen, char *imsi)
{
uint8_t data[23+3]; /* prefix PLEN */
/* paging group */
if (!imsi || strlen(imsi) < 3)
return;
imsi += strlen(imsi) - 3;
data[0] = imsi[0];
data[1] = imsi[1];
data[2] = imsi[2];
bitvec_pack(block, data + 3+1);
data[3] = (plen << 2) | 0x01;
pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, 23+3);
}
static void pcu_l1if_tx_bcch(uint8_t *data, int len)
{
pcu_tx_data_req(0, 0, PCU_IF_SAPI_BCCH, 0, 0, 0, data, len);