aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs_bssgp_pcu.cpp
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-07-03 13:36:03 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2012-07-03 13:36:03 +0200
commite6228b34a75efcb6b0700ac29672d62539860fbf (patch)
treefb63787c14638347a13c6e42b203ae956e23c5e5 /src/gprs_bssgp_pcu.cpp
parent83ced4978ab2d58a4b8bf68be922adc0671db747 (diff)
TBF acknowledged mode finished for both link directions
Diffstat (limited to 'src/gprs_bssgp_pcu.cpp')
-rw-r--r--src/gprs_bssgp_pcu.cpp78
1 files changed, 56 insertions, 22 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 85fef64d..8d391f23 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -29,40 +29,31 @@ 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;
uint8_t trx, ts;
+ uint8_t *data;
+ uint16_t len;
+ struct gprs_rlcmac_tbf *tbf;
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
- struct gprs_rlcmac_tbf *tbf;
- // Create new TBF
- tfi = tfi_alloc(&trx, &ts);
- if (tfi < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
- /* FIXME: send reject */
- return -EBUSY;
- }
- tbf = tbf_alloc(tfi, trx, ts);
- tbf->direction = GPRS_RLCMAC_DL_TBF;
- tbf->state = GPRS_RLCMAC_FLOW;
- tbf->tlli = ntohl(budh->tlli);
- LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+ tlli = ntohl(budh->tlli);
/* LLC_PDU is mandatory IE */
if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU))
{
- LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tbf->tlli);
+ LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}
- uint8_t *llc_pdu = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
- tbf->llc_index = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
-
- LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = ");
- for (i = 0; i < tbf->llc_index; i++)
+ data = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
+ len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
+ if (len > sizeof(tbf->llc_frame))
{
- tbf->llc_frame[i] = llc_pdu[i];
- LOGPC(DBSSGP, LOGL_NOTICE, "%02x", tbf->llc_frame[i]);
+ LOGP(DBSSGP, LOGL_ERROR, "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_NOTICE, "LLC PDU = (TLLI=0x%08x) %s\n", tlli, osmo_hexdump(data, len));
uint16_t imsi_len = 0;
uint8_t *imsi;
@@ -79,7 +70,50 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
LOGPC(DBSSGP, LOGL_NOTICE, "\n");
}
- gprs_rlcmac_packet_downlink_assignment(tbf);
+ /* check for existing TBF */
+ if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] APPEND TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+ if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF in WAIT RELEASE state "
+ "(T3193), so reuse TBF\n");
+ memcpy(tbf->llc_frame, data, len);
+ tbf->llc_length = len;
+ memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset
+ rlc states */
+ gprs_rlcmac_trigger_downlink_assignment(tbf, 1);
+ } else {
+ /* the TBF exists, so we must write it in the queue */
+ struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
+ if (!llc_msg)
+ return -ENOMEM;
+ memcpy(msgb_put(llc_msg, len), data, len);
+ msgb_enqueue(&tbf->llc_queue, llc_msg);
+ }
+ } else {
+ // Create new TBF
+ tfi = tfi_alloc(&trx, &ts);
+ if (tfi < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+ /* FIXME: send reject */
+ return -EBUSY;
+ }
+ tbf = tbf_alloc(tfi, trx, ts);
+ tbf->direction = GPRS_RLCMAC_DL_TBF;
+ tbf->tlli = tlli;
+ tbf->tlli_valid = 1;
+
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+
+ /* new TBF, so put first frame */
+ memcpy(tbf->llc_frame, data, len);
+ tbf->llc_length = len;
+
+ /* trigger downlink assignment and set state to ASSIGN.
+ * 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);
+ }
return 0;
}