aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-09-27 09:23:24 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2012-09-27 09:23:24 +0200
commita9be1547b1b4459d64d92207da2a29e41fcb3ba2 (patch)
treeb05502667c99050b587eab0691b2b54b221aa769
parent99a107dbeef03b2e80aff82023cdfc5c10109b5b (diff)
Use PCH confirm from BTS to start downlink packet flow
Since we don't know when the IMM.ASS message is sent on it's paging group on PCH, we will wait for confirm from BTS and start packet flow then.
-rw-r--r--src/gprs_bssgp_pcu.cpp4
-rw-r--r--src/gprs_rlcmac.h7
-rw-r--r--src/gprs_rlcmac_data.cpp67
-rw-r--r--src/gprs_rlcmac_sched.cpp4
-rw-r--r--src/pcu_l1_if.cpp23
-rw-r--r--src/pcuif_proto.h4
6 files changed, 99 insertions, 10 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index df7d37a..4b0255e 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -143,7 +143,9 @@ 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 */
- tbf->state_flags = 0;
+ tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; /* keep
+ to flags */
+ tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
if (!tbf->ms_class && ms_class)
tbf->ms_class = ms_class;
tbf_update(tbf);
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index 4643991..27cf825 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -98,7 +98,7 @@ extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
#define RLC_MAX_WS 64 /* max window size */
#define RLC_MAX_LEN 54 /* CS-4 including spare bits */
-#define Tassign_agch 0,800000 /* FIXME: we need a confirm from BTS */
+#define Tassign_agch 0,200000 /* waiting after IMM.ASS confirm */
#define Tassign_pacch 2,0 /* timeout for pacch assigment */
enum gprs_rlcmac_tbf_state {
@@ -146,6 +146,7 @@ enum gprs_rlcmac_tbf_direction {
#define GPRS_RLCMAC_FLAG_TO_DL_ACK 5
#define GPRS_RLCMAC_FLAG_TO_UL_ASS 6
#define GPRS_RLCMAC_FLAG_TO_DL_ASS 7
+#define GPRS_RLCMAC_FLAG_TO_MASK 0xf0 /* timeout bits */
struct gprs_rlcmac_tbf {
struct llist_head list;
@@ -192,6 +193,8 @@ struct gprs_rlcmac_tbf {
uint16_t v_a; /* ack state */
char v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
int32_t tx_counter; /* count all transmitted blocks */
+ char imsi[16]; /* store IMSI for PCH retransmission */
+ uint8_t wait_confirm; /* wait for CCCH IMM.ASS cnf */
} dl;
struct {
uint16_t bsn; /* block sequence number */
@@ -349,6 +352,8 @@ 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_imm_ass_cnf(uint8_t *data, uint32_t fn);
+
int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv);
struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging(
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index dedf98a..66d29c6 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -73,6 +73,9 @@ struct rlc_li_field {
} __attribute__ ((packed));
}
+static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll,
+ char *imsi);
+
static int gprs_rlcmac_diag(struct gprs_rlcmac_tbf *tbf)
{
if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
@@ -179,6 +182,16 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
tbf_timer_start(tbf, 3195, bts->t3195, 0);
return 0;
}
+ /* resend IMM.ASS on CCCH on timeout */
+ if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
+ && !(tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) {
+ LOGP(DRLCMAC, LOGL_DEBUG, "Re-send dowlink assignment "
+ "for TBF=%d on PCH (IMSI=%s)\n", tbf->tfi,
+ tbf->dir.dl.imsi);
+ /* send immediate assignment */
+ gprs_rlcmac_downlink_assignment(tbf, 0, tbf->dir.dl.imsi);
+ tbf->dir.dl.wait_confirm = 1;
+ }
} else
LOGP(DRLCMAC, LOGL_ERROR, "- Poll Timeout, but no event!\n");
@@ -477,12 +490,13 @@ void tbf_timer_cb(void *_tbf)
}
if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) {
/* change state to FLOW, so scheduler will start transmission */
+ tbf->dir.dl.wait_confirm = 0;
if (tbf->state == GPRS_RLCMAC_ASSIGN) {
tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
tbf_assign_control_ts(tbf);
} else
- LOGP(DRLCMAC, LOGL_ERROR, "Error: TBF is not "
- "in assign state\n");
+ LOGP(DRLCMAC, LOGL_NOTICE, "Continue flow after "
+ "IMM.ASS confirm\n");
}
break;
case 3169:
@@ -1621,7 +1635,8 @@ 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 */
- tbf->state_flags = 0;
+ tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; /* keep TO flags */
+ tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
tbf_update(tbf);
gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL);
@@ -1778,12 +1793,50 @@ void gprs_rlcmac_trigger_downlink_assignment(struct gprs_rlcmac_tbf *tbf,
/* change state */
tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN);
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
+ strncpy(tbf->dir.dl.imsi, imsi, sizeof(tbf->dir.dl.imsi));
/* send immediate assignment */
gprs_rlcmac_downlink_assignment(tbf, 0, imsi);
- /* send immediate assignment */
- gprs_rlcmac_downlink_assignment(tbf, 0, imsi);
- /* start timer */
+ tbf->dir.dl.wait_confirm = 1;
+ }
+}
+
+int gprs_rlcmac_imm_ass_cnf(uint8_t *data, uint32_t fn)
+{
+ struct gprs_rlcmac_tbf *tbf;
+ uint8_t plen;
+ uint32_t tlli;
+
+ /* move to IA Rest Octets */
+ plen = data[0] >> 2;
+ data += 1 + plen;
+
+ if ((*data & 0xf0) != 0xd0) {
+ LOGP(DRLCMAC, LOGL_ERROR, "Got IMM.ASS confirm, but rest "
+ "octets do not start with bit sequence 'HH01' "
+ "(Packet Downlink Assignment)\n");
+ return -EINVAL;
+ }
+
+ /* get TLLI from downlink assignment */
+ tlli = (*data++) << 28;
+ tlli |= (*data++) << 20;
+ tlli |= (*data++) << 12;
+ tlli |= (*data++) << 4;
+ tlli |= (*data++) >> 4;
+
+ tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_ERROR, "Got IMM.ASS confirm, but TLLI=%08x "
+ "does not exit\n", tlli);
+ return -EINVAL;
+ }
+
+ LOGP(DRLCMAC, LOGL_DEBUG, "Got IMM.ASS confirm for TLLI=%08x\n", tlli);
+
+ if (tbf->dir.dl.wait_confirm) {
tbf_timer_start(tbf, 0, Tassign_agch);
}
- }
+
+ return 0;
+}
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index b5deeb0..f588c47 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -188,6 +188,10 @@ struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn,
&& tbf->state != GPRS_RLCMAC_FINISHED)
continue;
+ /* waiting for CCCH IMM.ASS confirm */
+ if (tbf->dir.dl.wait_confirm)
+ continue;
+
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data message at "
"RTS for DL TBF=%d (TRX=%d, TS=%d)\n", tfi, trx, ts);
/* next TBF to handle ressource is the next one */
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index 1eeacfa..9e5e2f2 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -194,6 +194,26 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
return rc;
}
+static int pcu_rx_data_cnf(struct gsm_pcu_if_data *data_cnf)
+{
+ int rc = 0;
+
+ LOGP(DL1IF, LOGL_DEBUG, "Data confirm received: sapi=%d fn=%d\n",
+ data_cnf->sapi, data_cnf->fn);
+
+ switch (data_cnf->sapi) {
+ case PCU_IF_SAPI_PCH:
+ rc = gprs_rlcmac_imm_ass_cnf(data_cnf->data, data_cnf->fn);
+ break;
+ default:
+ LOGP(DL1IF, LOGL_ERROR, "Received PCU data confirm with "
+ "unsupported sapi %d\n", data_cnf->sapi);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
static int pcu_rx_rts_req(struct gsm_pcu_if_rts_req *rts_req)
{
int rc = 0;
@@ -468,6 +488,9 @@ int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
case PCU_IF_MSG_DATA_IND:
rc = pcu_rx_data_ind(&pcu_prim->u.data_ind);
break;
+ case PCU_IF_MSG_DATA_CNF:
+ rc = pcu_rx_data_cnf(&pcu_prim->u.data_cnf);
+ break;
case PCU_IF_MSG_RTS_REQ:
rc = pcu_rx_rts_req(&pcu_prim->u.rts_req);
break;
diff --git a/src/pcuif_proto.h b/src/pcuif_proto.h
index 493f058..c27bb7d 100644
--- a/src/pcuif_proto.h
+++ b/src/pcuif_proto.h
@@ -1,10 +1,11 @@
#ifndef _PCUIF_PROTO_H
#define _PCUIF_PROTO_H
-#define PCU_IF_VERSION 0x03
+#define PCU_IF_VERSION 0x04
/* msg_type */
#define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */
+#define PCU_IF_MSG_DATA_CNF 0x01 /* confirm (e.g. transmission on PCH) */
#define PCU_IF_MSG_DATA_IND 0x02 /* receive data from given channel */
#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send request */
#define PCU_IF_MSG_RACH_IND 0x22 /* receive RACH */
@@ -137,6 +138,7 @@ struct gsm_pcu_if {
union {
struct gsm_pcu_if_data data_req;
+ struct gsm_pcu_if_data data_cnf;
struct gsm_pcu_if_data data_ind;
struct gsm_pcu_if_rts_req rts_req;
struct gsm_pcu_if_rach_ind rach_ind;