aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-07-09 17:10:44 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2012-07-09 17:10:44 +0200
commite13fa2d56936d6bed8febcc41508a30e4a1038f0 (patch)
tree40e4bdd467bc1bb1a3653363818a536ffb03c2bd
parent88a214cc4520a765c14f15b7379d83c538500b96 (diff)
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.
-rw-r--r--src/gprs_bssgp_pcu.cpp34
-rw-r--r--src/gprs_rlcmac.h2
-rw-r--r--src/gprs_rlcmac_data.cpp25
-rw-r--r--src/pcu_l1_if.cpp13
-rw-r--r--src/pcu_l1_if.h1
-rw-r--r--src/sysmo_l1_if.cpp17
6 files changed, 69 insertions, 23 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 74b24bbe..733d4e29 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -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;
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index c47d6d41..abb99808 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -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);
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index ea813c63..a87fef1b 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -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 */
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index f6ba7750..865a9118 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -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);
}
diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h
index b8cc5c95..2aac5531 100644
--- a/src/pcu_l1_if.h
+++ b/src/pcu_l1_if.h
@@ -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);
diff --git a/src/sysmo_l1_if.cpp b/src/sysmo_l1_if.cpp
index 6cce5543..ceb28d28 100644
--- a/src/sysmo_l1_if.cpp
+++ b/src/sysmo_l1_if.cpp
@@ -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);