From: Holger Hans Peter Freyther holger@moiji-mobile.com
The TBF should use the IMSI to identify a block flow but all handling is spread across the entire code. Start to clean this up by moving relevant code into the tbf file. Afterwards one can clean up and add more internal structure. --- src/Makefile.am | 6 +- src/gprs_bssgp_pcu.cpp | 121 +------------------------------------ src/tbf.cpp | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ src/tbf.h | 27 +++++++++ 4 files changed, 194 insertions(+), 120 deletions(-) create mode 100644 src/tbf.cpp create mode 100644 src/tbf.h
diff --git a/src/Makefile.am b/src/Makefile.am index 38a4b3c..6646f53 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,7 +40,8 @@ libgprs_la_SOURCES = \ gsm_timer.cpp \ bitvector.cpp \ pcu_l1_if.cpp \ - pcu_vty.c + pcu_vty.c \ + tbf.cpp
if ENABLE_SYSMOBTS libgprs_la_SOURCES += \ @@ -72,7 +73,8 @@ noinst_HEADERS = \ bitvector.h \ pcu_vty.h \ sysmo_l1_if.h \ - femtobts.h + femtobts.h \ + tbf.h
osmo_pcu_SOURCES = pcu_main.cpp
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 4833af8..3432bca 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -21,6 +21,7 @@ #include <gprs_rlcmac.h> #include <gprs_bssgp_pcu.h> #include <pcu_l1_if.h> +#include <tbf.h>
static struct gprs_bssgp_pcu the_pcu = { 0, };
@@ -103,12 +104,9 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) { struct bssgp_ud_hdr *budh;
- int8_t tfi; /* must be signed */ - uint32_t tlli; uint8_t *data; uint16_t len; - struct gprs_rlcmac_tbf *tbf; char imsi[16] = "000";
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg); @@ -123,7 +121,7 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
data = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU); len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU); - if (len > sizeof(tbf->llc_frame)) + if (len > sizeof(gprs_rlcmac_tbf::llc_frame)) { 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); @@ -154,120 +152,7 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
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))) { - LOGP(DRLCMAC, LOGL_INFO, "TBF: APPEND TFI: %u TLLI: 0x%08x\n", tbf->tfi, tbf->tlli); - if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) { - LOGP(DRLCMAC, LOGL_DEBUG, "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 */ - 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); - gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); - } else { - /* the TBF exists, so we must write it in the queue - * we prepend lifetime in front of PDU */ - struct timeval *tv; - struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv), - "llc_pdu_queue"); - if (!llc_msg) - return -ENOMEM; - tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); - if (the_pcu.bts->force_llc_lifetime) - delay_csec = the_pcu.bts->force_llc_lifetime; - /* keep timestap at 0 for infinite delay */ - if (delay_csec != 0xffff) { - /* calculate timestamp of timeout */ - gettimeofday(tv, NULL); - tv->tv_usec += (delay_csec % 100) * 10000; - tv->tv_sec += delay_csec / 100; - if (tv->tv_usec > 999999) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } - } - memcpy(msgb_put(llc_msg, len), data, len); - msgb_enqueue(&tbf->llc_queue, llc_msg); - /* set ms class for updating TBF */ - if (!tbf->ms_class && ms_class) - tbf->ms_class = ms_class; - } - } else { - uint8_t trx, ta, ss; - int8_t use_trx; - struct gprs_rlcmac_tbf *old_tbf; - int rc; - - /* check for uplink data, so we copy our informations */ - tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); - if (tbf && tbf->dir.ul.contention_resolution_done - && !tbf->dir.ul.final_ack_sent) { - use_trx = tbf->trx; - ta = tbf->ta; - ss = 0; - old_tbf = tbf; - } else { - use_trx = -1; - /* we already have an uplink TBF, so we use that TA */ - if (tbf) - ta = tbf->ta; - else { - /* recall TA */ - rc = recall_timing_advance(tlli); - if (rc < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown" - ", assuming 0\n"); - ta = 0; - } else - ta = rc; - } - ss = 1; /* PCH assignment only allows one timeslot */ - old_tbf = NULL; - } - - // Create new TBF (any TRX) - tfi = tfi_find_free(the_pcu.bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx); - if (tfi < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n"); - /* FIXME: send reject */ - return -EBUSY; - } - /* set number of downlink slots according to multislot class */ - tbf = tbf_alloc(the_pcu.bts, tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, - ss); - if (!tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - return -EBUSY; - } - tbf->tlli = tlli; - tbf->tlli_valid = 1; - tbf->ta = ta; - - LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %d 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, old_tbf, imsi); - } - - /* store IMSI for debugging purpose */ - strncpy(tbf->meas.imsi, imsi, sizeof(tbf->meas.imsi) - 1); - - return 0; + return tbf_handle(the_pcu.bts, tlli, imsi, ms_class, delay_csec, data, len); }
int gprs_bssgp_pcu_rx_paging_ps(struct msgb *msg, struct tlv_parsed *tp) diff --git a/src/tbf.cpp b/src/tbf.cpp new file mode 100644 index 0000000..816fdb8 --- /dev/null +++ b/src/tbf.cpp @@ -0,0 +1,160 @@ +/* Copied from gprs_bssgp_pcu.cpp + * + * Copyright (C) 2012 Ivan Klyuchnikov + * Copyright (C) 2013 by Holger Hans Peter Freyther + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <tbf.h> +#include <gprs_rlcmac.h> +#include <gprs_debug.h> + +extern "C" { +#include <osmocom/core/msgb.h> +} + +#include <errno.h> +#include <string.h> + +/** + * TODO: split into unit test-able parts... + */ +int tbf_handle(struct gprs_rlcmac_bts *bts, + const uint32_t tlli, const char *imsi, + const uint8_t ms_class, const uint16_t pdu_delay_csec, + const uint8_t *data, const uint16_t len) +{ + struct gprs_rlcmac_tbf *tbf; + int8_t tfi; /* must be signed */ + + /* check for existing TBF */ + if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) { + LOGP(DRLCMAC, LOGL_INFO, "TBF: APPEND TFI: %u TLLI: 0x%08x\n", tbf->tfi, tbf->tlli); + if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) { + LOGP(DRLCMAC, LOGL_DEBUG, "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 */ + 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); + gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); + } else { + /* the TBF exists, so we must write it in the queue + * we prepend lifetime in front of PDU */ + struct timeval *tv; + struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv), + "llc_pdu_queue"); + if (!llc_msg) + return -ENOMEM; + tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); + + uint16_t delay_csec; + if (bts->force_llc_lifetime) + delay_csec = bts->force_llc_lifetime; + else + delay_csec = pdu_delay_csec; + /* keep timestap at 0 for infinite delay */ + if (delay_csec != 0xffff) { + /* calculate timestamp of timeout */ + gettimeofday(tv, NULL); + tv->tv_usec += (delay_csec % 100) * 10000; + tv->tv_sec += delay_csec / 100; + if (tv->tv_usec > 999999) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + } + memcpy(msgb_put(llc_msg, len), data, len); + msgb_enqueue(&tbf->llc_queue, llc_msg); + /* set ms class for updating TBF */ + if (!tbf->ms_class && ms_class) + tbf->ms_class = ms_class; + } + } else { + uint8_t trx, ta, ss; + int8_t use_trx; + struct gprs_rlcmac_tbf *old_tbf; + int rc; + + /* check for uplink data, so we copy our informations */ + tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); + if (tbf && tbf->dir.ul.contention_resolution_done + && !tbf->dir.ul.final_ack_sent) { + use_trx = tbf->trx; + ta = tbf->ta; + ss = 0; + old_tbf = tbf; + } else { + use_trx = -1; + /* we already have an uplink TBF, so we use that TA */ + if (tbf) + ta = tbf->ta; + else { + /* recall TA */ + rc = recall_timing_advance(tlli); + if (rc < 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown" + ", assuming 0\n"); + ta = 0; + } else + ta = rc; + } + ss = 1; /* PCH assignment only allows one timeslot */ + old_tbf = NULL; + } + + // Create new TBF (any TRX) + tfi = tfi_find_free(bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx); + if (tfi < 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n"); + /* FIXME: send reject */ + return -EBUSY; + } + /* set number of downlink slots according to multislot class */ + tbf = tbf_alloc(bts, tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, + ss); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return -EBUSY; + } + tbf->tlli = tlli; + tbf->tlli_valid = 1; + tbf->ta = ta; + + LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %d 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, old_tbf, imsi); + } + + /* store IMSI for debugging purpose */ + strncpy(tbf->meas.imsi, imsi, sizeof(tbf->meas.imsi) - 1); + return 0; +} diff --git a/src/tbf.h b/src/tbf.h new file mode 100644 index 0000000..1535e8c --- /dev/null +++ b/src/tbf.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2013 by Holger Hans Peter Freyther + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include <stdint.h> + +struct gprs_rlcmac_bts; + +int tbf_handle(struct gprs_rlcmac_bts *bts, + const uint32_t tlli, const char *imsi, const uint8_t ms_class, + const uint16_t delay_csec, const uint8_t *data, const uint16_t len);
From: Holger Hans Peter Freyther holger@moiji-mobile.com
* Create a look up routine for the TBF that will allow us to easily find a TBF by IMSI... * Separate the code that works on an existing TBF. --- src/tbf.cpp | 119 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 49 deletions(-)
diff --git a/src/tbf.cpp b/src/tbf.cpp index 816fdb8..d242b52 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -29,66 +29,87 @@ extern "C" { #include <errno.h> #include <string.h>
+static struct gprs_rlcmac_tbf *tbf_lookup_dl(const uint32_t tlli, const char *imsi) +{ + /* TODO: look up by IMSI first, then tlli, then old_tlli */ + return tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF); +} + +static int tbf_append_data(struct gprs_rlcmac_tbf *tbf, + struct gprs_rlcmac_bts *bts, + const uint8_t ms_class, + const uint16_t pdu_delay_csec, + const uint8_t *data, const uint16_t len) +{ + LOGP(DRLCMAC, LOGL_INFO, "TBF: APPEND TFI: %u TLLI: 0x%08x\n", tbf->tfi, tbf->tlli); + if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) { + LOGP(DRLCMAC, LOGL_DEBUG, "TBF in WAIT RELEASE state " + "(T3193), so reuse TBF\n"); + memcpy(tbf->llc_frame, data, len); + tbf->llc_length = len; + /* reset rlc states */ + memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); + /* keep to flags */ + tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; + tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH); + if (!tbf->ms_class && ms_class) + tbf->ms_class = ms_class; + tbf_update(tbf); + gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); + } else { + /* the TBF exists, so we must write it in the queue + * we prepend lifetime in front of PDU */ + struct timeval *tv; + struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv), + "llc_pdu_queue"); + if (!llc_msg) + return -ENOMEM; + tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); + + uint16_t delay_csec; + if (bts->force_llc_lifetime) + delay_csec = bts->force_llc_lifetime; + else + delay_csec = pdu_delay_csec; + /* keep timestap at 0 for infinite delay */ + if (delay_csec != 0xffff) { + /* calculate timestamp of timeout */ + gettimeofday(tv, NULL); + tv->tv_usec += (delay_csec % 100) * 10000; + tv->tv_sec += delay_csec / 100; + if (tv->tv_usec > 999999) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + } + memcpy(msgb_put(llc_msg, len), data, len); + msgb_enqueue(&tbf->llc_queue, llc_msg); + /* set ms class for updating TBF */ + if (!tbf->ms_class && ms_class) + tbf->ms_class = ms_class; + } + + return 0; +} + /** * TODO: split into unit test-able parts... */ int tbf_handle(struct gprs_rlcmac_bts *bts, const uint32_t tlli, const char *imsi, - const uint8_t ms_class, const uint16_t pdu_delay_csec, + const uint8_t ms_class, const uint16_t delay_csec, const uint8_t *data, const uint16_t len) { struct gprs_rlcmac_tbf *tbf; int8_t tfi; /* must be signed */
/* check for existing TBF */ - if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) { - LOGP(DRLCMAC, LOGL_INFO, "TBF: APPEND TFI: %u TLLI: 0x%08x\n", tbf->tfi, tbf->tlli); - if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) { - LOGP(DRLCMAC, LOGL_DEBUG, "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 */ - 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); - gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); - } else { - /* the TBF exists, so we must write it in the queue - * we prepend lifetime in front of PDU */ - struct timeval *tv; - struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv), - "llc_pdu_queue"); - if (!llc_msg) - return -ENOMEM; - tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); - - uint16_t delay_csec; - if (bts->force_llc_lifetime) - delay_csec = bts->force_llc_lifetime; - else - delay_csec = pdu_delay_csec; - /* keep timestap at 0 for infinite delay */ - if (delay_csec != 0xffff) { - /* calculate timestamp of timeout */ - gettimeofday(tv, NULL); - tv->tv_usec += (delay_csec % 100) * 10000; - tv->tv_sec += delay_csec / 100; - if (tv->tv_usec > 999999) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } - } - memcpy(msgb_put(llc_msg, len), data, len); - msgb_enqueue(&tbf->llc_queue, llc_msg); - /* set ms class for updating TBF */ - if (!tbf->ms_class && ms_class) - tbf->ms_class = ms_class; - } + tbf = tbf_lookup_dl(tlli, imsi); + if (tbf) { + int rc = tbf_append_data(tbf, bts, ms_class, + delay_csec, data, len); + if (rc < 0) + return rc; } else { uint8_t trx, ta, ss; int8_t use_trx;
From: Holger Hans Peter Freyther holger@moiji-mobile.com
--- src/tbf.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/tbf.cpp b/src/tbf.cpp index d242b52..5161e92 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -29,6 +29,13 @@ extern "C" { #include <errno.h> #include <string.h>
+static inline void tbf_update_ms_class(struct gprs_rlcmac_tbf *tbf, + const uint8_t ms_class) +{ + if (!tbf->ms_class && ms_class) + tbf->ms_class = ms_class; +} + static struct gprs_rlcmac_tbf *tbf_lookup_dl(const uint32_t tlli, const char *imsi) { /* TODO: look up by IMSI first, then tlli, then old_tlli */ @@ -52,8 +59,7 @@ static int tbf_append_data(struct gprs_rlcmac_tbf *tbf, /* keep to flags */ tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH); - if (!tbf->ms_class && ms_class) - tbf->ms_class = ms_class; + tbf_update_ms_class(tbf, ms_class); tbf_update(tbf); gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); } else { @@ -84,9 +90,7 @@ static int tbf_append_data(struct gprs_rlcmac_tbf *tbf, } memcpy(msgb_put(llc_msg, len), data, len); msgb_enqueue(&tbf->llc_queue, llc_msg); - /* set ms class for updating TBF */ - if (!tbf->ms_class && ms_class) - tbf->ms_class = ms_class; + tbf_update_ms_class(tbf, ms_class); }
return 0;
From: Holger Hans Peter Freyther holger@moiji-mobile.com
This will allow us to set flags (like IMSI) present and will be of help when fixing the tbf lookup. --- src/tbf.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/tbf.cpp b/src/tbf.cpp index 5161e92..fc8d229 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -36,6 +36,12 @@ static inline void tbf_update_ms_class(struct gprs_rlcmac_tbf *tbf, tbf->ms_class = ms_class; }
+static inline void tbf_assign_imsi(struct gprs_rlcmac_tbf *tbf, + const char *imsi) +{ + strncpy(tbf->meas.imsi, imsi, sizeof(tbf->meas.imsi) - 1); +} + static struct gprs_rlcmac_tbf *tbf_lookup_dl(const uint32_t tlli, const char *imsi) { /* TODO: look up by IMSI first, then tlli, then old_tlli */ @@ -179,7 +185,7 @@ int tbf_handle(struct gprs_rlcmac_bts *bts, gprs_rlcmac_trigger_downlink_assignment(tbf, old_tbf, imsi); }
- /* store IMSI for debugging purpose */ - strncpy(tbf->meas.imsi, imsi, sizeof(tbf->meas.imsi) - 1); + /* store IMSI for debugging purpose. TODO: it is more than debugging */ + tbf_assign_imsi(tbf, imsi); return 0; }
From: Holger Hans Peter Freyther holger@moiji-mobile.com
Move the code that is dedicated to handle the assignment of a new TFI/TBF for the downlink into a new method. --- src/tbf.cpp | 150 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 80 insertions(+), 70 deletions(-)
diff --git a/src/tbf.cpp b/src/tbf.cpp index fc8d229..8dad6bc 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -102,6 +102,81 @@ static int tbf_append_data(struct gprs_rlcmac_tbf *tbf, return 0; }
+static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts, + const char *imsi, + const uint32_t tlli, const uint8_t ms_class, + const uint8_t *data, const uint16_t len) +{ + uint8_t trx, ta, ss; + int8_t use_trx; + struct gprs_rlcmac_tbf *old_tbf, *tbf; + int8_t tfi; /* must be signed */ + int rc; + + /* check for uplink data, so we copy our informations */ + tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); + if (tbf && tbf->dir.ul.contention_resolution_done + && !tbf->dir.ul.final_ack_sent) { + use_trx = tbf->trx; + ta = tbf->ta; + ss = 0; + old_tbf = tbf; + } else { + use_trx = -1; + /* we already have an uplink TBF, so we use that TA */ + if (tbf) + ta = tbf->ta; + else { + /* recall TA */ + rc = recall_timing_advance(tlli); + if (rc < 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown" + ", assuming 0\n"); + ta = 0; + } else + ta = rc; + } + ss = 1; /* PCH assignment only allows one timeslot */ + old_tbf = NULL; + } + + // Create new TBF (any TRX) + tfi = tfi_find_free(bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx); + if (tfi < 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n"); + /* FIXME: send reject */ + return -EBUSY; + } + /* set number of downlink slots according to multislot class */ + tbf = tbf_alloc(bts, tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, ss); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return -EBUSY; + } + tbf->tlli = tlli; + tbf->tlli_valid = 1; + tbf->ta = ta; + + LOGP(DRLCMAC, LOGL_DEBUG, + "TBF: [DOWNLINK] START TFI: %d 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, old_tbf, imsi); + + /* store IMSI for debugging purpose. TODO: it is more than debugging */ + tbf_assign_imsi(tbf, imsi); + return 0; +} + /** * TODO: split into unit test-able parts... */ @@ -111,81 +186,16 @@ int tbf_handle(struct gprs_rlcmac_bts *bts, const uint8_t *data, const uint16_t len) { struct gprs_rlcmac_tbf *tbf; - int8_t tfi; /* must be signed */
/* check for existing TBF */ tbf = tbf_lookup_dl(tlli, imsi); if (tbf) { int rc = tbf_append_data(tbf, bts, ms_class, delay_csec, data, len); - if (rc < 0) - return rc; - } else { - uint8_t trx, ta, ss; - int8_t use_trx; - struct gprs_rlcmac_tbf *old_tbf; - int rc; - - /* check for uplink data, so we copy our informations */ - tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); - if (tbf && tbf->dir.ul.contention_resolution_done - && !tbf->dir.ul.final_ack_sent) { - use_trx = tbf->trx; - ta = tbf->ta; - ss = 0; - old_tbf = tbf; - } else { - use_trx = -1; - /* we already have an uplink TBF, so we use that TA */ - if (tbf) - ta = tbf->ta; - else { - /* recall TA */ - rc = recall_timing_advance(tlli); - if (rc < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown" - ", assuming 0\n"); - ta = 0; - } else - ta = rc; - } - ss = 1; /* PCH assignment only allows one timeslot */ - old_tbf = NULL; - } - - // Create new TBF (any TRX) - tfi = tfi_find_free(bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx); - if (tfi < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n"); - /* FIXME: send reject */ - return -EBUSY; - } - /* set number of downlink slots according to multislot class */ - tbf = tbf_alloc(bts, tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, - ss); - if (!tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - return -EBUSY; - } - tbf->tlli = tlli; - tbf->tlli_valid = 1; - tbf->ta = ta; + if (rc >= 0) + tbf_assign_imsi(tbf, imsi); + return rc; + }
- LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %d 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, old_tbf, imsi); - } - - /* store IMSI for debugging purpose. TODO: it is more than debugging */ - tbf_assign_imsi(tbf, imsi); - return 0; + return tbf_new_dl_assignment(bts, imsi, tlli, ms_class, data, len); }
From: Holger Hans Peter Freyther holger@moiji-mobile.com
These need to be re-factored to use a common allocation routine. --- src/gprs_rlcmac_data.cpp | 2 ++ src/tbf.cpp | 1 + 2 files changed, 3 insertions(+)
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 294753d..17e1fb9 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -238,6 +238,7 @@ static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, uint8_t ms_class, struct gprs_rlcmac_tbf *tbf; uint8_t tfi;
+#warning "Copy and paste with tbf_new_dl_assignment" /* create new TBF, use sme TRX as DL TBF */ tfi = tfi_find_free(bts, GPRS_RLCMAC_UL_TBF, &trx, use_trx); if (tfi < 0) { @@ -1174,6 +1175,7 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) "(AGCH)\n"); } else { // Create new TBF + #warning "Copy and pate with other routines.." tfi = tfi_find_free(bts, GPRS_RLCMAC_UL_TBF, &trx, -1); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); diff --git a/src/tbf.cpp b/src/tbf.cpp index 8dad6bc..21b58ac 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -141,6 +141,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts, }
// Create new TBF (any TRX) +#warning "Copy and paste with alloc_ul_tbf" tfi = tfi_find_free(bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
From: Holger Hans Peter Freyther holger@moiji-mobile.com
--- src/tbf.cpp | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/tbf.cpp b/src/tbf.cpp index 21b58ac..cb8fb19 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -114,6 +114,8 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts, int rc;
/* check for uplink data, so we copy our informations */ +#warning "Do the same look up for IMSI, TLLI and OLD_TLLI" +#warning "Refactor the below lines... into a new method" tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); if (tbf && tbf->dir.ul.contention_resolution_done && !tbf->dir.ul.final_ack_sent) {
From: Holger Hans Peter Freyther holger@moiji-mobile.com
Add the bts parameter to the method list. This would be a static method of the class (in case the TBF would be a class) --- src/gprs_rlcmac_data.cpp | 41 +++-------------------------------------- src/tbf.cpp | 35 +++++++++++++++++++++++++++++++++++ src/tbf.h | 5 +++++ 3 files changed, 43 insertions(+), 38 deletions(-)
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 17e1fb9..bc55c57 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -21,6 +21,7 @@ #include <gprs_bssgp_pcu.h> #include <gprs_rlcmac.h> #include <pcu_l1_if.h> +#include <tbf.h>
extern void *tall_pcu_ctx;
@@ -230,42 +231,6 @@ static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap) return 0; }
-static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, uint8_t ms_class, - uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf) -{ - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - uint8_t trx; - struct gprs_rlcmac_tbf *tbf; - uint8_t tfi; - -#warning "Copy and paste with tbf_new_dl_assignment" - /* create new TBF, use sme TRX as DL TBF */ - tfi = tfi_find_free(bts, GPRS_RLCMAC_UL_TBF, &trx, use_trx); - if (tfi < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - return NULL; - } - /* use multislot class of downlink TBF */ - tbf = tbf_alloc(bts, dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ms_class, 0); - if (!tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - return NULL; - } - tbf->tlli = tlli; - tbf->tlli_valid = 1; /* no contention resolution */ - tbf->dir.ul.contention_resolution_done = 1; - tbf->ta = ta; /* use current TA */ - tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); - tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH); - tbf_timer_start(tbf, 3169, bts->t3169, 0); - - return tbf; -} - - - /* Received Uplink RLC control block. */ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, uint32_t fn) @@ -412,7 +377,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) { LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack " "message, so we provide one:\n"); - alloc_ul_tbf(tbf->trx, tbf->ms_class, tbf->tlli, tbf->ta, tbf); + tbf_alloc_ul(bts, tbf->trx, tbf->ms_class, tbf->tlli, tbf->ta, tbf); /* schedule uplink assignment */ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; } @@ -465,7 +430,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, ms_class = get_ms_class_by_capability(&ul_control_block->u.Packet_Resource_Request.MS_Radio_Access_capability); if (!ms_class) LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n"); - tbf = alloc_ul_tbf(trx, ms_class, tlli, ta, NULL); + tbf = tbf_alloc_ul(bts, trx, ms_class, tlli, ta, NULL); if (!tbf) break; /* set control ts to current MS's TS, until assignment complete */ diff --git a/src/tbf.cpp b/src/tbf.cpp index cb8fb19..79f1ea8 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -1,6 +1,7 @@ /* Copied from gprs_bssgp_pcu.cpp * * Copyright (C) 2012 Ivan Klyuchnikov + * Copyright (C) 2012 Andreas Eversberg jolly@eversberg.eu * Copyright (C) 2013 by Holger Hans Peter Freyther * * This program is free software; you can redistribute it and/or @@ -202,3 +203,37 @@ int tbf_handle(struct gprs_rlcmac_bts *bts,
return tbf_new_dl_assignment(bts, imsi, tlli, ms_class, data, len); } + +struct gprs_rlcmac_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts, + int8_t use_trx, uint8_t ms_class, + uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf) +{ + uint8_t trx; + struct gprs_rlcmac_tbf *tbf; + uint8_t tfi; + +#warning "Copy and paste with tbf_new_dl_assignment" + /* create new TBF, use sme TRX as DL TBF */ + tfi = tfi_find_free(bts, GPRS_RLCMAC_UL_TBF, &trx, use_trx); + if (tfi < 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return NULL; + } + /* use multislot class of downlink TBF */ + tbf = tbf_alloc(bts, dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ms_class, 0); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return NULL; + } + tbf->tlli = tlli; + tbf->tlli_valid = 1; /* no contention resolution */ + tbf->dir.ul.contention_resolution_done = 1; + tbf->ta = ta; /* use current TA */ + tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH); + tbf_timer_start(tbf, 3169, bts->t3169, 0); + + return tbf; +} diff --git a/src/tbf.h b/src/tbf.h index 1535e8c..330eac1 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -22,6 +22,11 @@
struct gprs_rlcmac_bts;
+/* dispatch Unitdata.DL messages */ int tbf_handle(struct gprs_rlcmac_bts *bts, const uint32_t tlli, const char *imsi, const uint8_t ms_class, const uint16_t delay_csec, const uint8_t *data, const uint16_t len); + +struct gprs_rlcmac_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts, + int8_t use_trx, uint8_t ms_class, + uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf);
osmocom-net-gprs@lists.osmocom.org