aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 df7d37af..4b0255e3 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 46439911..27cf825d 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 dedf98a8..66d29c6d 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 b5deeb0e..f588c47d 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 1eeacfaf..9e5e2f20 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 493f058c..c27bb7dc 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;