diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/gprs_bssgp_pcu.cpp | 121 | ||||
-rw-r--r-- | src/tbf.cpp | 160 | ||||
-rw-r--r-- | src/tbf.h | 27 |
4 files changed, 194 insertions, 120 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 38a4b3c8..6646f534 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 4833af8a..3432bca8 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 00000000..816fdb86 --- /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 00000000..1535e8c4 --- /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); |