From 1294256d65aeda9f37a20d0edae28a78b89bcf0f Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 12 Jul 2012 14:31:57 +0200 Subject: VTY implementation --- src/pcu_vty.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pcu_vty.h | 22 +++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/pcu_vty.c create mode 100644 src/pcu_vty.h (limited to 'src') diff --git a/src/pcu_vty.c b/src/pcu_vty.c new file mode 100644 index 00000000..7e8af43b --- /dev/null +++ b/src/pcu_vty.c @@ -0,0 +1,104 @@ +/* OsmoBTS VTY interface */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +#include "pcu_vty.h" + + +enum node_type pcu_vty_go_parent(struct vty *vty) +{ + switch (vty->node) { +#if 0 + case TRX_NODE: + vty->node = BTS_NODE; + { + struct gsm_bts_trx *trx = vty->index; + vty->index = trx->bts; + } + break; +#endif + default: + vty->node = CONFIG_NODE; + } + return vty->node; +} + +int pcu_vty_is_config_node(struct vty *vty, int node) +{ + switch (node) { +#if 0 + case TRX_NODE: + case BTS_NODE: + return 1; +#endif + default: + return 0; + } +} + +gDEFUN(ournode_exit, ournode_exit_cmd, "exit", + "Exit current node, go down to provious node") +{ + switch (vty->node) { +#if 0 + case TRXV_NODE: + vty->node = BTS_NODE; + { + struct gsm_bts_trx *trx = vty->index; + vty->index = trx->bts; + } + break; +#endif + default: + break; + } + return CMD_SUCCESS; +} + +gDEFUN(ournode_end, ournode_end_cmd, "end", + "End current mode and change to enable mode") +{ + switch (vty->node) { + default: + vty_config_unlock(vty); + vty->node = ENABLE_NODE; + vty->index = NULL; + vty->index_sub = NULL; + break; + } + return CMD_SUCCESS; +} + +static const char pcu_copyright[] = + "Copyright (C) 2012 by ...\r\n" + "License GNU GPL version 2 or later\r\n" + "This is free software: you are free to change and redistribute it.\r\n" + "There is NO WARRANTY, to the extent permitted by law.\r\n"; + +struct vty_app_info pcu_vty_info = { + .name = "Osmo-PCU", + .version = PACKAGE_VERSION, + .copyright = pcu_copyright, + .go_parent_cb = pcu_vty_go_parent, + .is_config_node = pcu_vty_is_config_node, +}; + +int pcu_vty_init(const struct log_info *cat) +{ +// install_element_ve(&show_pcu_cmd); + + logging_vty_add_cmds(cat); + + return 0; +} diff --git a/src/pcu_vty.h b/src/pcu_vty.h new file mode 100644 index 00000000..390d75cd --- /dev/null +++ b/src/pcu_vty.h @@ -0,0 +1,22 @@ +#ifndef _PCU_VTY_H +#define _PCU_VTY_H + +#include +#include + +enum pcu_vty_node { + PCU_NODE = _LAST_OSMOVTY_NODE + 1, +}; + +extern struct cmd_element ournode_exit_cmd; +extern struct cmd_element ournode_end_cmd; + +enum node_type pcu_vty_go_parent(struct vty *vty); +int pcu_vty_is_config_node(struct vty *vty, int node); + +int pcu_vty_init(const struct log_info *cat); + +extern struct vty_app_info pcu_vty_info; + +#endif /* _PCU_VTY_H */ + -- cgit v1.2.3 From ebde64f258b5e522ad47399c034751d2e9421f90 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 12 Jul 2012 09:18:42 +0200 Subject: logging: Add vty to allow definition/storage of debug levels Note: This requires new libosomocore that allows to compile VTY headers with C++. --- src/Makefile.am | 6 ++++-- src/pcu_main.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index ca586fda..041831fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,7 +33,8 @@ libgprs_la_SOURCES = \ gprs_rlcmac_sched.cpp \ gsm_timer.cpp \ bitvector.cpp \ - pcu_l1_if.cpp + pcu_l1_if.cpp \ + pcu_vty.c if ENABLE_SYSMOBTS libgprs_la_SOURCES += \ @@ -56,7 +57,8 @@ noinst_HEADERS = \ pcuif_proto.h \ pcu_l1_if.h \ gsm_timer.h \ - bitvector.h + bitvector.h \ + pcu_vty.h RLCMACTest_SOURCES = RLCMACTest.cpp RLCMACTest_LDADD = \ diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 6c30c1e4..2a01b9b0 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -25,15 +25,26 @@ #include #include #include +extern "C" { +#include "pcu_vty.h" +#include +#include +} struct gprs_rlcmac_bts *gprs_rlcmac_bts; extern struct gprs_nsvc *nsvc; uint16_t spoof_mcc = 0, spoof_mnc = 0; +static int config_given = 0; +static const char *config_file = "osmo-pcu.cfg"; +extern struct vty_app_info pcu_vty_info; +void *tall_pcu_ctx; static void print_help() { printf( "Some useful options:\n" " -h --help this text\n" + " -c --config-file Specify the filename of the config " + "file\n" " -m --mcc MCC use given MCC instead of value " "provided by BTS\n" " -n --mnc MNC use given MNC instead of value " @@ -48,12 +59,13 @@ static void handle_options(int argc, char **argv) int option_idx = 0, c; static const struct option long_options[] = { { "help", 0, 0, 'h' }, + { "config-file", 1, 0, 'c' }, { "mcc", 1, 0, 'm' }, { "mnc", 1, 0, 'n' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "hm:n:", + c = getopt_long(argc, argv, "hc:m:n:", long_options, &option_idx); if (c == -1) break; @@ -63,6 +75,10 @@ static void handle_options(int argc, char **argv) print_help(); exit(0); break; + case 'c': + config_file = strdup(optarg); + config_given = 1; + break; case 'm': spoof_mcc = atoi(optarg); break; @@ -82,7 +98,12 @@ int main(int argc, char *argv[]) struct gprs_rlcmac_bts *bts; int rc; - bts = gprs_rlcmac_bts = talloc_zero(NULL, struct gprs_rlcmac_bts); + tall_pcu_ctx = talloc_named_const(NULL, 1, "Osmo-PCU context"); + if (!tall_pcu_ctx) + return -ENOMEM; + + bts = gprs_rlcmac_bts = talloc_zero(tall_pcu_ctx, + struct gprs_rlcmac_bts); if (!gprs_rlcmac_bts) return -ENOMEM; gprs_rlcmac_bts->initial_cs = 1; @@ -99,12 +120,32 @@ int main(int argc, char *argv[]) osmo_init_logging(&gprs_log_info); + vty_init(&pcu_vty_info); + pcu_vty_init(&gprs_log_info); + handle_options(argc, argv); if ((!!spoof_mcc) + (!!spoof_mnc) == 1) { fprintf(stderr, "--mcc and --mnc must be specified " "together.\n"); exit(0); } + + rc = vty_read_config_file(config_file, NULL); + if (rc < 0 && config_given) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", + config_file); + exit(1); + } + if (rc < 0) + fprintf(stderr, "No config file: '%s' Using default config.\n", + config_file); + + rc = telnet_init(tall_pcu_ctx, NULL, 4240); + if (rc < 0) { + fprintf(stderr, "Error initializing telnet\n"); + exit(1); + } + rc = pcu_l1if_open(); if (rc < 0) @@ -121,6 +162,7 @@ int main(int argc, char *argv[]) pcu_l1if_close(); talloc_free(gprs_rlcmac_bts); + talloc_free(tall_pcu_ctx); return 0; } -- cgit v1.2.3 From b8695f290aa6b14917ea67eeefda245ffa2df26b Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 13 Jul 2012 13:48:45 +0200 Subject: Removed obsolete if-condition --- src/gprs_bssgp_pcu.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index f9a421a5..d1ef046e 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -42,10 +42,6 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg); tlli = ntohl(budh->tlli); - if (!tbf) - { - return -1; - } /* LLC_PDU is mandatory IE */ if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) { -- cgit v1.2.3 From e266bd48aca6f5b7831eb7c44e4773e9884d4c56 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 13 Jul 2012 14:00:21 +0200 Subject: Adding signal handler to allow clean exit of PCU The signal handler will end the main loop, so clean exit is performed. The allocated memory is dumped in order to detect memory leaks. All talloc functions use tall_pcu_ctx context instead of NULL, to track memory leaks. --- src/openbts_sock.cpp | 4 +++- src/pcu_l1_if.cpp | 2 ++ src/pcu_main.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/sysmo_sock.cpp | 3 ++- 4 files changed, 58 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/openbts_sock.cpp b/src/openbts_sock.cpp index cbf7adcc..1f1e9044 100644 --- a/src/openbts_sock.cpp +++ b/src/openbts_sock.cpp @@ -35,6 +35,8 @@ extern "C" { #include } +extern void *tall_pcu_ctx; + struct femtol1_hdl { struct gsm_time gsm_time; uint32_t hLayer1; /* handle to the L1 instance in the DSP */ @@ -142,7 +144,7 @@ int pcu_l1if_open() int rc; /* allocate new femtol1_handle */ - fl1h = talloc_zero(NULL, struct femtol1_hdl); + fl1h = talloc_zero(tall_pcu_ctx, struct femtol1_hdl); INIT_LLIST_HEAD(&fl1h->wlc_list); l1fh->fl1h = fl1h; diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index fd8b3c34..d0f2e325 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -37,6 +37,8 @@ extern "C" { #include #include +extern void *tall_pcu_ctx; + // Variable for storage current FN. int frame_number; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2a01b9b0..2c6d7638 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include extern "C" { #include "pcu_vty.h" #include @@ -38,6 +39,7 @@ static int config_given = 0; static const char *config_file = "osmo-pcu.cfg"; extern struct vty_app_info pcu_vty_info; void *tall_pcu_ctx; +static int quit = 0; static void print_help() { @@ -93,6 +95,39 @@ static void handle_options(int argc, char **argv) } } +void sighandler(int sigset) +{ + if (sigset == SIGHUP || sigset == SIGPIPE) + return; + + fprintf(stderr, "Signal %d received.\n", sigset); + + switch (sigset) { + case SIGINT: + /* If another signal is received afterwards, the program + * is terminated without finishing shutdown process. + */ + signal(SIGINT, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + signal(SIGABRT, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGUSR2, SIG_DFL); + + quit = 1; + break; + case SIGABRT: + /* in case of abort, we want to obtain a talloc report + * and then return to the caller, who will abort the process + */ + case SIGUSR1: + case SIGUSR2: + talloc_report_full(tall_pcu_ctx, stderr); + break; + } +} + int main(int argc, char *argv[]) { struct gprs_rlcmac_bts *bts; @@ -118,6 +153,8 @@ int main(int argc, char *argv[]) bts->n3103 = 4; bts->n3105 = 8; + msgb_set_talloc_ctx(tall_pcu_ctx); + osmo_init_logging(&gprs_log_info); vty_init(&pcu_vty_info); @@ -151,8 +188,15 @@ int main(int argc, char *argv[]) if (rc < 0) return rc; - while (1) - { + signal(SIGINT, sighandler); + signal(SIGHUP, sighandler); + signal(SIGTERM, sighandler); + signal(SIGPIPE, sighandler); + signal(SIGABRT, sighandler); + signal(SIGUSR1, sighandler); + signal(SIGUSR2, sighandler); + + while (!quit) { osmo_gsm_timers_check(); osmo_gsm_timers_prepare(); osmo_gsm_timers_update(); @@ -160,8 +204,13 @@ int main(int argc, char *argv[]) osmo_select_main(0); } + telnet_exit(); + pcu_l1if_close(); + talloc_free(gprs_rlcmac_bts); + + talloc_report_full(tall_pcu_ctx, stderr); talloc_free(tall_pcu_ctx); return 0; diff --git a/src/sysmo_sock.cpp b/src/sysmo_sock.cpp index 8d83ca20..390f3f69 100644 --- a/src/sysmo_sock.cpp +++ b/src/sysmo_sock.cpp @@ -37,6 +37,7 @@ extern "C" { #include #include +extern void *tall_pcu_ctx; /* * SYSMO-PCU socket functions @@ -219,7 +220,7 @@ int pcu_l1if_open(void) state = pcu_sock_state; if (!state) { - state = talloc_zero(NULL, struct pcu_sock_state); + state = talloc_zero(tall_pcu_ctx, struct pcu_sock_state); if (!state) return -ENOMEM; INIT_LLIST_HEAD(&state->upqueue); -- cgit v1.2.3 From b0c7ea72c8157f1b8124bbe105aa05c46a77a005 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 13 Jul 2012 14:46:03 +0200 Subject: Changed data structures for TBF and PDCH instances, to allow multislot The new data structure is required to define slot/TFI assigment for MS with multislot capability. Now there are two lists for TBFs: uplink and downlink. It is possible to have different TBFs with same TFI in the same direction, as long as they are assigned on different timeslots. See tbf.txt for description. Note: This does not implement any multislot support. It defines the new data structure. Currently only the first slot is assigned. --- src/gprs_bssgp_pcu.cpp | 30 +++-- src/gprs_rlcmac.cpp | 303 ++++++++++++++++++++++++++++++++-------------- src/gprs_rlcmac.h | 55 +++++---- src/gprs_rlcmac_data.cpp | 103 ++++++++-------- src/gprs_rlcmac_sched.cpp | 58 +++++---- src/pcu_l1_if.cpp | 43 ++++--- src/sysmo_sock.cpp | 5 +- src/tbf.txt | 30 +++++ 8 files changed, 411 insertions(+), 216 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index d1ef046e..c4d70afd 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -31,10 +31,9 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) { struct bssgp_ud_hdr *budh; - int tfi; + int8_t tfi; /* must be signed */ uint32_t tlli; int i, j; - uint8_t trx, ts; uint8_t *data; uint16_t len; struct gprs_rlcmac_tbf *tbf; @@ -101,19 +100,36 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) msgb_enqueue(&tbf->llc_queue, llc_msg); } } else { - // Create new TBF - tfi = tfi_alloc(&trx, &ts); + uint8_t trx, ts, use_trx, first_ts; + + /* check for uplink data, so we copy our informations */ + if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF))) { + use_trx = tbf->trx; + first_ts = tbf->first_ts; + } else { + use_trx = -1; + first_ts = -1; + } + + // Create new TBF (any TRX) + tfi = tfi_alloc(GPRS_RLCMAC_DL_TBF, &trx, &ts, use_trx, first_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; + /* FIXME: set number of downlink slots according to multislot + * class */ + tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, tfi, trx, ts, 1); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return -EBUSY; + } tbf->tlli = tlli; tbf->tlli_valid = 1; - LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + 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); diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 9d2601c8..ab04aeab 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -22,18 +22,33 @@ #include #include -LLIST_HEAD(gprs_rlcmac_tbfs); +LLIST_HEAD(gprs_rlcmac_ul_tbfs); +LLIST_HEAD(gprs_rlcmac_dl_tbfs); void *rlcmac_tall_ctx; -/* FIXME: spread ressources on multiple TRX */ -int tfi_alloc(uint8_t *_trx, uint8_t *_ts) +/* FIXME: spread ressources over multiple TRX. Also add option to use same + * TRX in case of existing TBF for TLLI in the other direction. */ +/* search for free TFI and return TFI, TRX and first TS */ +int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, + uint8_t use_trx, uint8_t first_ts) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; - uint8_t trx, ts, tfi; + struct gprs_rlcmac_tbf **tbfp; + uint8_t trx_from, trx_to, trx, ts, tfi; + + if (use_trx >= 0 && use_trx < 8) + trx_from = trx_to = use_trx; + else { + trx_from = 0; + trx_to = 7; + } + if (first_ts < 0 || first_ts >= 8) + first_ts = 0; - for (trx = 0; trx < 8; trx++) { - for (ts = 0; ts < 8; ts++) { + /* on TRX find first enabled TS */ + for (trx = trx_from; trx <= trx_to; trx++) { + for (ts = first_ts; ts < 8; ts++) { pdch = &bts->trx[trx].pdch[ts]; if (!pdch->enable) continue; @@ -42,16 +57,20 @@ int tfi_alloc(uint8_t *_trx, uint8_t *_ts) if (ts < 8) break; } - if (trx == 8) { + if (trx > trx_to) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n"); return -EINVAL; } LOGP(DRLCMAC, LOGL_DEBUG, "Searching for first unallocated TFI: " - "TRX=%d TS=%d\n", trx, ts); + "TRX=%d first TS=%d\n", trx, ts); + if (dir == GPRS_RLCMAC_UL_TBF) + tbfp = pdch->ul_tbf; + else + tbfp = pdch->dl_tbf; for (tfi = 0; tfi < 32; tfi++) { - if (!pdch->tbf[tfi]) + if (!tbfp[tfi]) break; } @@ -66,126 +85,221 @@ int tfi_alloc(uint8_t *_trx, uint8_t *_ts) return -1; } -int find_free_usf(uint8_t trx, uint8_t ts) +static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch, uint8_t ts) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - struct gprs_rlcmac_pdch *pdch; struct gprs_rlcmac_tbf *tbf; uint8_t usf_map = 0; uint8_t tfi, usf; - if (trx >= 8 || ts >= 8) - return -EINVAL; - pdch = &bts->trx[trx].pdch[ts]; - /* make map of used USF */ for (tfi = 0; tfi < 32; tfi++) { - tbf = pdch->tbf[tfi]; + tbf = pdch->ul_tbf[tfi]; if (!tbf) continue; - if (tbf->direction != GPRS_RLCMAC_UL_TBF) - continue; - usf_map |= (1 << tbf->dir.ul.usf); + usf_map |= (1 << tbf->dir.ul.usf[ts]); } /* look for USF, don't use USF=7 */ for (usf = 0; usf < 7; usf++) { - if (!(usf_map & (1 << usf))) { - LOGP(DRLCMAC, LOGL_DEBUG, " Found USF=%d.\n", usf); + if (!(usf_map & (1 << usf))) return usf; - } } - LOGP(DRLCMAC, LOGL_NOTICE, "No USF available.\n"); return -1; } /* lookup TBF Entity (by TFI) */ -#warning FIXME: use pdch instance by trx and ts, because tfi is local -struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction) +struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, + enum gprs_rlcmac_tbf_direction dir) { struct gprs_rlcmac_tbf *tbf; + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + if (tfi >= 32 || trx >= 8 || ts >= 8) + return NULL; - llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) { - if (tbf->state != GPRS_RLCMAC_RELEASING - && tbf->tfi == tfi - && tbf->direction == direction) + if (dir == GPRS_RLCMAC_UL_TBF) + tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; + else + tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; + if (!tbf) + return NULL; + + if (tbf->state != GPRS_RLCMAC_RELEASING) return tbf; - } + return NULL; } /* search for active downlink or uplink tbf */ -struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction) +struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, + enum gprs_rlcmac_tbf_direction dir) { struct gprs_rlcmac_tbf *tbf; - llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) { - if (tbf->state != GPRS_RLCMAC_RELEASING - && tbf->tlli == tlli - && tbf->direction == direction) - return tbf; + if (dir == GPRS_RLCMAC_UL_TBF) { + llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) { + if (tbf->state != GPRS_RLCMAC_RELEASING + && tbf->tlli == tlli) + return tbf; + } + } else { + llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { + if (tbf->state != GPRS_RLCMAC_RELEASING + && tbf->tlli == tlli) + return tbf; + } } return NULL; } -#warning FIXME: use pdch instance by trx and ts, because polling is local -struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn) +struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; - llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) { - if (tbf->state != GPRS_RLCMAC_RELEASING + uint8_t tfi; + + /* only one TBF can poll on specific TS/FN, because scheduler can only + * schedule one downlink control block (with polling) at a FN per TS */ + for (tfi = 0; tfi < 32; tfi++) { + tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; + if (tbf && tbf->state != GPRS_RLCMAC_RELEASING + && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED + && tbf->poll_fn == fn && tbf->poll_ts == ts) + return tbf; + tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; + if (tbf && tbf->state != GPRS_RLCMAC_RELEASING && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED - && tbf->poll_fn == fn) + && tbf->poll_fn == fn && tbf->poll_ts == ts) return tbf; } return NULL; } -struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts) +struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, + uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t num_ts) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; struct gprs_rlcmac_tbf *tbf; + uint8_t ts_count, ts; + int8_t usf, tsc = -1; /* both must be signed */ LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n"); - LOGP(DRLCMAC, LOGL_INFO, "Allocating TBF with TFI=%d.\n", tfi); + LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF with TFI=%d on TRX=%d.\n", + (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tfi, trx); - if (trx >= 8 || ts >= 8 || tfi >= 32) + if (trx >= 8 || first_ts >= 8 || tfi >= 32) return NULL; - pdch = &bts->trx[trx].pdch[ts]; tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf); if (!tbf) return NULL; + tbf->direction = dir; tbf->tfi = tfi; tbf->trx = trx; - tbf->ts = ts; tbf->arfcn = bts->trx[trx].arfcn; - tbf->tsc = bts->trx[trx].pdch[ts].tsc; - tbf->pdch = pdch; + /* assign free TS to TBF, where TFI is free + * for uplink: assign free USF to each uplink TS + * Note that the first TS must be free, because it was selected by + * tfi_alloc(). */ + for (ts_count = 0, ts = first_ts; ts < 8; ts++) { + pdch = &bts->trx[trx].pdch[ts]; + if (!pdch->enable) + continue; + if (tsc < 0) + tbf->tsc = tsc = pdch->tsc; + else if (tsc != pdch->tsc) { + LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS=%d of TRX=%d, " + "because it has different TSC than lower TS " + "of TRX. In order to allow multislot, all " + "slots must be configured with the same TSC!\n", + ts, trx); + continue; + } + if (dir == GPRS_RLCMAC_UL_TBF) { + /* if TFI is free on TS */ + if (!pdch->ul_tbf[tfi]) { + /* if USF available */ + usf = find_free_usf(pdch, ts); + if (usf >= 0) { + LOGP(DRLCMAC, LOGL_DEBUG, " Assign " + "uplink TS=%d USF=%d\n", + ts, usf); + pdch->ul_tbf[tfi] = tbf; + tbf->pdch[ts] = pdch; + ts_count++; + } else + LOGP(DRLCMAC, LOGL_DEBUG, " Skipping " + "TS=%d, no USF available\n", + ts); + } + } else { + /* if TFI is free on TS */ + if (!pdch->dl_tbf[tfi]) { + LOGP(DRLCMAC, LOGL_DEBUG, " Assign downlink " + "TS=%d\n", ts); + pdch->dl_tbf[tfi] = tbf; + tbf->pdch[ts] = pdch; + ts_count++; + } + } + if (ts_count == num_ts) + break; + } + if (!ts_count) { /* implies that direction is uplink */ + LOGP(DRLCMAC, LOGL_NOTICE, "No USF available\n"); + talloc_free(tbf); + return NULL; + } + + tbf->first_ts = first_ts; tbf->ws = 64; tbf->sns = 128; INIT_LLIST_HEAD(&tbf->llc_queue); - llist_add(&tbf->list, &gprs_rlcmac_tbfs); - pdch->tbf[tfi] = tbf; + if (dir == GPRS_RLCMAC_UL_TBF) + llist_add(&tbf->list, &gprs_rlcmac_ul_tbfs); + else + llist_add(&tbf->list, &gprs_rlcmac_dl_tbfs); return tbf; } void tbf_free(struct gprs_rlcmac_tbf *tbf) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; struct msgb *msg; + int ts; - LOGP(DRLCMAC, LOGL_INFO, "Free TBF=%d with TLLI=0x%08x.\n", tbf->tfi, + LOGP(DRLCMAC, LOGL_INFO, "Free %s TBF=%d with TLLI=0x%08x.\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli); + if (tbf->ul_ass_state != GPRS_RLCMAC_UL_ASS_NONE) + LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending uplink " + "assignment. This may not happen, because the " + "assignment message never gets transmitted. Please " + "be shure not to free in this state. PLEASE FIX!\n"); + if (tbf->dl_ass_state != GPRS_RLCMAC_DL_ASS_NONE) + LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending downlink " + "assignment. This may not happen, because the " + "assignment message never gets transmitted. Please " + "be shure not to free in this state. PLEASE FIX!\n"); tbf_timer_stop(tbf); while ((msg = msgb_dequeue(&tbf->llc_queue))) msgb_free(msg); - pdch = &bts->trx[tbf->trx].pdch[tbf->ts]; - pdch->tbf[tbf->tfi] = NULL; + if (tbf->direction == GPRS_RLCMAC_UL_TBF) { + for (ts = 0; ts < 8; ts++) { + pdch = tbf->pdch[ts]; + if (pdch) + pdch->ul_tbf[tbf->tfi] = NULL; + } + } else { + for (ts = 0; ts < 8; ts++) { + pdch = tbf->pdch[ts]; + if (pdch) + pdch->dl_tbf[tbf->tfi] = NULL; + } + } llist_del(&tbf->list); LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF ends here **********\n"); talloc_free(tbf); @@ -203,8 +317,9 @@ const char *tbf_state_name[] = { void tbf_new_state(struct gprs_rlcmac_tbf *tbf, enum gprs_rlcmac_tbf_state state) { - LOGP(DRLCMAC, LOGL_DEBUG, "TBF=%d changes state from %s to %s\n", - tbf->tfi, tbf_state_name[tbf->state], tbf_state_name[state]); + LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d changes state from %s to %s\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, + tbf_state_name[tbf->state], tbf_state_name[state]); tbf->state = state; } @@ -212,11 +327,14 @@ void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, unsigned int seconds, unsigned int microseconds) { if (!osmo_timer_pending(&tbf->timer)) - LOGP(DRLCMAC, LOGL_DEBUG, "Starting TBF=%d timer %u.\n", + LOGP(DRLCMAC, LOGL_DEBUG, "Starting %s TBF=%d timer %u.\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, T); else - LOGP(DRLCMAC, LOGL_DEBUG, "Restarting TBF=%d timer %u while " - "old timer %u pending \n", tbf->tfi, T, tbf->T); + LOGP(DRLCMAC, LOGL_DEBUG, "Restarting %s TBF=%d timer %u " + "while old timer %u pending \n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", + tbf->tfi, T, tbf->T); tbf->T = T; tbf->num_T_exp = 0; @@ -231,7 +349,8 @@ void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf) { if (osmo_timer_pending(&tbf->timer)) { - LOGP(DRLCMAC, LOGL_DEBUG, "Stopping TBF=%d timer %u.\n", + LOGP(DRLCMAC, LOGL_DEBUG, "Stopping %s TBF=%d timer %u.\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->T); osmo_timer_del(&tbf->timer); } @@ -286,7 +405,8 @@ void gprs_rlcmac_enqueue_block(bitvec *block, int len) #endif /* received RLC/MAC block from L1 */ -int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn) +int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len, + uint32_t fn) { unsigned payload = data[0] >> 6; bitvec *block; @@ -294,14 +414,15 @@ int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn) switch (payload) { case GPRS_RLCMAC_DATA_BLOCK: - rc = gprs_rlcmac_rcv_data_block_acknowledged(data, len); + rc = gprs_rlcmac_rcv_data_block_acknowledged(trx, ts, data, + len); break; case GPRS_RLCMAC_CONTROL_BLOCK: block = bitvec_alloc(len); if (!block) return -ENOMEM; bitvec_unpack(block, data); - rc = gprs_rlcmac_rcv_control_block(block, fn); + rc = gprs_rlcmac_rcv_control_block(block, trx, ts, fn); bitvec_free(block); break; case GPRS_RLCMAC_CONTROL_BLOCK_OPT: @@ -417,14 +538,13 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, /* generate uplink assignment */ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, - uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, uint8_t new_tfi, - uint8_t usf, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc, - uint8_t poll) + uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, + struct gprs_rlcmac_tbf *tbf, uint8_t poll) { // TODO We should use our implementation of encode RLC/MAC Control messages. struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; unsigned wp = 0; - int i; + uint8_t ts; bitvec_write_field(dest, wp,0x1,2); // Payload Type bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13) @@ -445,18 +565,18 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, } bitvec_write_field(dest, wp,0x0,1); // Message escape - bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND + bitvec_write_field(dest, wp,bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on - bitvec_write_field(dest, wp,ta,6); // TIMING_ADVANCE_VALUE + bitvec_write_field(dest, wp,tbf->ta,6); // TIMING_ADVANCE_VALUE bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off #if 1 bitvec_write_field(dest, wp,0x1,1); // Frequency Parameters information elements = present - bitvec_write_field(dest, wp,tsc,3); // Training Sequence Code (TSC) + bitvec_write_field(dest, wp,tbf->tsc,3); // Training Sequence Code (TSC) bitvec_write_field(dest, wp,0x0,2); // ARFCN = present - bitvec_write_field(dest, wp,arfcn,10); // ARFCN + bitvec_write_field(dest, wp,tbf->arfcn,10); // ARFCN #else bitvec_write_field(dest, wp,0x0,1); // Frequency Parameters = off #endif @@ -468,16 +588,16 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, bitvec_write_field(dest, wp,0x0,1); // USF_GRANULARITY bitvec_write_field(dest, wp,0x1,1); // switch TFI : on - bitvec_write_field(dest, wp,new_tfi,5);// TFI + bitvec_write_field(dest, wp,tbf->tfi,5);// TFI bitvec_write_field(dest, wp,0x0,1); // bitvec_write_field(dest, wp,0x0,1); // TBF Starting Time = off bitvec_write_field(dest, wp,0x0,1); // Timeslot Allocation - for (i = 0; i < 8; i++) { - if (tn == i) { + for (ts = 0; ts < 8; ts++) { + if (tbf->pdch[ts]) { bitvec_write_field(dest, wp,0x1,1); // USF_TN(i): on - bitvec_write_field(dest, wp,usf,3); // USF_TN(i) + bitvec_write_field(dest, wp,tbf->dir.ul.usf[ts],3); // USF_TN(i) } else bitvec_write_field(dest, wp,0x0,1); // USF_TN(i): off } @@ -487,12 +607,11 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, /* generate downlink assignment */ void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi, - uint8_t old_downlink, uint8_t new_tfi, uint16_t arfcn, - uint8_t tn, uint8_t ta, uint8_t tsc, uint8_t poll) + uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll) { // Packet downlink assignment TS 44.060 11.2.7 - int i; + uint8_t tn; block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header block->RRBP = 0x0; // N+13 @@ -511,35 +630,39 @@ void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi, block->u.Packet_Downlink_Assignment.MAC_MODE = 0x0; // Dynamic Allocation block->u.Packet_Downlink_Assignment.RLC_MODE = 0x0; // RLC acknowledged mode block->u.Packet_Downlink_Assignment.CONTROL_ACK = old_downlink; // NW establishes no new DL TBF for the MS with running timer T3192 - block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION = 0x80 >> tn; // timeslot(s) + block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION = 0; // timeslot(s) + for (tn = 0; tn < 8; tn++) { + if (tbf->pdch[tn]) + block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION |= 0x80 >> tn; // timeslot(s) + } block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_TIMING_ADVANCE_VALUE = 0x1; // TIMING_ADVANCE_VALUE = on - block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE = ta; // TIMING_ADVANCE_VALUE + block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE = tbf->ta; // TIMING_ADVANCE_VALUE block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_IndexAndtimeSlot = 0x0; // TIMING_ADVANCE_INDEX = off block->u.Packet_Downlink_Assignment.Exist_P0_and_BTS_PWR_CTRL_MODE = 0x0; // POWER CONTROL = off block->u.Packet_Downlink_Assignment.Exist_Frequency_Parameters = 0x1; // Frequency Parameters = on - block->u.Packet_Downlink_Assignment.Frequency_Parameters.TSC = tsc; // Training Sequence Code (TSC) + block->u.Packet_Downlink_Assignment.Frequency_Parameters.TSC = tbf->tsc; // Training Sequence Code (TSC) block->u.Packet_Downlink_Assignment.Frequency_Parameters.UnionType = 0x0; // ARFCN = on - block->u.Packet_Downlink_Assignment.Frequency_Parameters.u.ARFCN = arfcn; // ARFCN + block->u.Packet_Downlink_Assignment.Frequency_Parameters.u.ARFCN = tbf->arfcn; // ARFCN block->u.Packet_Downlink_Assignment.Exist_DOWNLINK_TFI_ASSIGNMENT = 0x1; // DOWNLINK TFI ASSIGNMENT = on - block->u.Packet_Downlink_Assignment.DOWNLINK_TFI_ASSIGNMENT = new_tfi; // TFI + block->u.Packet_Downlink_Assignment.DOWNLINK_TFI_ASSIGNMENT = tbf->tfi; // TFI block->u.Packet_Downlink_Assignment.Exist_Power_Control_Parameters = 0x1; // Power Control Parameters = on block->u.Packet_Downlink_Assignment.Power_Control_Parameters.ALPHA = 0x0; // ALPHA - for (i = 0; i < 8; i++) + for (tn = 0; tn < 8; tn++) { - if (tn == i) + if (tbf->pdch[tn]) { - block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[i].Exist = 0x1; // Slot[i] = on - block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[i].GAMMA_TN = 0x0; // GAMMA_TN + block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x1; // Slot[i] = on + block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].GAMMA_TN = 0x0; // GAMMA_TN } else { - block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[i].Exist = 0x0; // Slot[i] = off + block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x0; // Slot[i] = off } } @@ -616,7 +739,7 @@ int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf) struct msgb *llc_pdu; unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + tbf->llc_index; - LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] TFI: %u TLLI: 0x%08x %s\n", tbf->tfi, tbf->tlli, osmo_hexdump(tbf->llc_frame, tbf->llc_index)); + LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] TFI: %u TLLI: 0x%08x len=%d\n", tbf->tfi, tbf->tlli, tbf->llc_index); if (!bctx) { LOGP(DBSSGP, LOGL_ERROR, "No bctx\n"); return -EIO; diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 635a6b11..db0e9ab9 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -46,7 +46,8 @@ struct gprs_rlcmac_pdch { uint8_t tsc; /* TSC of this slot */ uint8_t next_ul_tfi; /* next uplink TBF/TFI to schedule (0..31) */ uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */ - struct gprs_rlcmac_tbf *tbf[32]; /* array of TBF pointers, by TFI */ + struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */ + struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */ uint32_t last_rts_fn; /* store last frame number of RTS */ }; @@ -130,9 +131,12 @@ struct gprs_rlcmac_tbf { uint8_t tfi; uint32_t tlli; uint8_t tlli_valid; - uint8_t trx, ts, tsc; - struct gprs_rlcmac_pdch *pdch; - uint16_t arfcn, ta; + uint8_t trx; + uint16_t arfcn; + uint8_t tsc; + uint8_t first_ts; + struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */ + uint16_t ta; uint8_t llc_frame[LLC_MAX_LEN]; /* current DL or UL frame */ uint16_t llc_index; /* current write/read position of frame */ uint16_t llc_length; /* len of current DL LLC_frame, 0 == no frame */ @@ -143,7 +147,8 @@ struct gprs_rlcmac_tbf { enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state; enum gprs_rlcmac_tbf_poll_state poll_state; - uint32_t poll_fn; + uint32_t poll_fn; /* frame number to poll */ + uint8_t poll_ts; /* timeslot to poll */ uint16_t ws; /* window size */ uint16_t sns; /* sequence number space */ @@ -169,7 +174,7 @@ struct gprs_rlcmac_tbf { char v_n[RLC_MAX_SNS/2]; /* receive state array */ int32_t rx_counter; /* count all received blocks */ uint8_t n3103; /* N3103 counter */ - uint8_t usf; /* USF */ + uint8_t usf[8]; /* list USFs per PDCH (timeslot) */ } ul; } dir; uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */ @@ -184,19 +189,22 @@ struct gprs_rlcmac_tbf { unsigned int num_fT_exp; /* number of consecutive fT expirations */ }; -extern struct llist_head gprs_rlcmac_tbfs; - -int tfi_alloc(uint8_t *_trx, uint8_t *_ts); +extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */ +extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */ -struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts); +int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, + uint8_t use_trx, uint8_t first_ts); -struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction); +struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, + uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t num_ts); -struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction); +struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, + enum gprs_rlcmac_tbf_direction dir); -struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn); +struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, + enum gprs_rlcmac_tbf_direction dir); -int find_free_usf(uint8_t trx, uint8_t ts); +struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts); void tbf_free(struct gprs_rlcmac_tbf *tbf); @@ -216,7 +224,8 @@ enum gprs_rlcmac_block_type { GPRS_RLCMAC_RESERVED = 0x3 }; -int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn); +int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len, + uint32_t fn); int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, @@ -224,13 +233,13 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t poll_fn); void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, - uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, uint8_t new_tfi, - uint8_t usf, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc, - uint8_t poll); + uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, + struct gprs_rlcmac_tbf *tbf, uint8_t poll); void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi, - uint8_t old_downlink, uint8_t new_tfi, uint16_t arfcn, - uint8_t tn, uint8_t ta, uint8_t tsc, uint8_t poll); + uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll); + + void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *tbf, uint8_t final); @@ -243,7 +252,8 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf); int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta); -int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn); +int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, + uint32_t fn); struct msgb *gprs_rlcmac_send_packet_uplink_assignment( struct gprs_rlcmac_tbf *tbf, uint32_t fn); @@ -257,7 +267,8 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, uint8_t ssn, uint8_t *rbb); -int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len); +int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, + uint8_t *data, uint8_t len); struct msgb *gprs_rlcmac_send_data_block_acknowledged( struct gprs_rlcmac_tbf *tbf, uint32_t fn); diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 7beca38f..0e8aca3e 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -64,7 +64,8 @@ struct rlc_li_field { int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for TBF=%d\n", tbf->tfi); + LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for %s TBF=%d\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi); tbf->poll_state = GPRS_RLCMAC_POLL_NONE; @@ -120,9 +121,10 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) } /* Received Uplink RLC control block. */ -int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn) +int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, + uint32_t fn) { - uint8_t tfi = 0; + int8_t tfi = 0; /* must be signed */ uint32_t tlli = 0; struct gprs_rlcmac_tbf *tbf; @@ -134,7 +136,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn) switch (ul_control_block->u.MESSAGE_TYPE) { case MT_PACKET_CONTROL_ACK: tlli = ul_control_block->u.Packet_Control_Acknowledgement.TLLI; - tbf = tbf_by_poll_fn(fn); + tbf = tbf_by_poll_fn(fn, trx, ts); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with " "unknown FN=%u TLL=0x%08x\n", fn, tlli); @@ -171,7 +173,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn) break; case MT_PACKET_DOWNLINK_ACK_NACK: tfi = ul_control_block->u.Packet_Downlink_Ack_Nack.DOWNLINK_TFI; - tbf = tbf_by_poll_fn(fn); + tbf = tbf_by_poll_fn(fn, trx, ts); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET DOWNLINK ACK with " "unknown FN=%u TBF=%d\n", fn, tfi); @@ -191,32 +193,31 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn) ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.RECEIVED_BLOCK_BITMAP); /* check for channel request */ if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) { - uint8_t trx, ts, usf; + uint8_t trx, ts; struct gprs_rlcmac_tbf *ul_tbf; struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack " "message, so we provide one:\n"); uplink_request: - /* create new tbf */ - tfi = tfi_alloc(&trx, &ts); + /* create new TBF, use sme TRX as DL TBF */ + tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, tbf->trx, tbf->first_ts); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ break; } - usf = find_free_usf(trx, ts); - if (usf < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource for USF\n"); + /* FIXME: set number of downlink slots according to + * multislot class */ + ul_tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 1); + if (!ul_tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ break; } - ul_tbf = tbf_alloc(tfi, trx, ts); ul_tbf->tlli = tbf->tlli; ul_tbf->tlli_valid = 1; /* no content resolution */ ul_tbf->ta = tbf->ta; /* use current TA */ - ul_tbf->direction = GPRS_RLCMAC_UL_TBF; - ul_tbf->dir.ul.usf = usf; tbf_new_state(ul_tbf, GPRS_RLCMAC_FLOW); tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); /* schedule uplink assignment */ @@ -235,14 +236,14 @@ uplink_request: } else { if (ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.UnionType) { tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.DOWNLINK_TFI; - tbf = tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF); + tbf = tbf_by_tfi(tfi, trx, ts, GPRS_RLCMAC_DL_TBF); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown downlink TBF=%d\n", tlli); break; } } else { tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.UPLINK_TFI; - tbf = tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF); + tbf = tbf_by_tfi(tfi, trx, ts, GPRS_RLCMAC_UL_TBF); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TBF=%d\n", tlli); break; @@ -250,7 +251,7 @@ uplink_request: } tlli = tbf->tlli; } - LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet ressource request\n", tbf->tfi, tbf->tlli); + LOGP(DRLCMAC, LOGL_INFO, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli); #warning FIXME puts("FIXME: UL request during UL request"); exit(0); @@ -271,7 +272,8 @@ void tbf_timer_cb(void *_tbf) { struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf; - LOGP(DRLCMAC, LOGL_DEBUG, "TBF=%d timer %u expired.\n", tbf->tfi, + LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d timer %u expired.\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->T); tbf->num_T_exp++; @@ -495,8 +497,7 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, if (i != frames - 1) { /* send frame to SGSN */ LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for " - "TBF=%d: %s\n", tbf->tfi, - osmo_hexdump(tbf->llc_frame, tbf->llc_index)); + "TBF=%d: len=%d\n", tbf->tfi, tbf->llc_index); gprs_rlcmac_tx_ul_ud(tbf); tbf->llc_index = 0; /* reset frame space */ /* also check if CV==0, because the frame may fill up the @@ -507,8 +508,7 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, /* send frame to SGSN */ LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for " "TBF=%d that fits precisely in last block: " - "%s\n", tbf->tfi, - osmo_hexdump(tbf->llc_frame, tbf->llc_index)); + "len=%d\n", tbf->tfi, tbf->llc_index); gprs_rlcmac_tx_ul_ud(tbf); tbf->llc_index = 0; /* reset frame space */ } @@ -550,6 +550,7 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, if (final) { tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; + tbf->poll_ts = tbf->first_ts; /* waiting for final acknowledge */ tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK; } else @@ -562,7 +563,8 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, * * The blocks are defragmented and forwarded as LLC frames, if complete. */ -int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) +int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, + uint8_t *data, uint8_t len) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; @@ -592,19 +594,13 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) } /* find TBF inst from given TFI */ - tbf = tbf_by_tfi(rh->tfi, GPRS_RLCMAC_UL_TBF); + tbf = tbf_by_tfi(rh->tfi, trx, ts, GPRS_RLCMAC_UL_TBF); if (!tbf) { LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TBF=%d\n", rh->tfi); return 0; } - if (tbf->direction != GPRS_RLCMAC_UL_TBF) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d not Uplink " - "tbf\n", rh->tfi); - return 0; - } - LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TBF=%d received (V(Q)=%d .. " "V(R)=%d)\n", rh->tfi, tbf->dir.ul.v_q, tbf->dir.ul.v_r); @@ -755,12 +751,14 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( struct msgb *msg; struct gprs_rlcmac_tbf *new_tbf; +#if POLLING_ASSIGNMENT == 1 if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " "sheduled for TBF=%d, so we must wait for uplink " "assignment...\n", tbf->tfi); return NULL; } +#endif /* on down TBF we get the uplink TBF to be assigned. */ if (tbf->direction == GPRS_RLCMAC_DL_TBF) @@ -788,9 +786,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( bitvec_unhex(ass_vec, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); write_packet_uplink_assignment(ass_vec, tbf->tfi, - (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf->tfi, - new_tbf->dir.ul.usf, new_tbf->arfcn, new_tbf->ts, new_tbf->ta, - new_tbf->tsc, POLLING_ASSIGNMENT); + (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf, + POLLING_ASSIGNMENT); bitvec_pack(ass_vec, msgb_put(msg, 23)); RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); @@ -803,6 +800,7 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( FIXME process does not work, also the acknowledgement is not checked. tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; + tbf->poll_ts = tbf->first_ts; tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; #else tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; @@ -816,31 +814,29 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; uint8_t trx, ts; - int tfi, usf; /* must be signed */ + int8_t tfi; /* must be signed */ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide " "one:\n"); // Create new TBF - tfi = tfi_alloc(&trx, &ts); + tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ return -EBUSY; } - usf = find_free_usf(trx, ts); - if (usf < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource for USF\n"); + /* select only one TS, since we don't know the multislot class yet */ + tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 1); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ return -EBUSY; } - tbf = tbf_alloc(tfi, trx, ts); if (qta < 0) qta = 0; if (qta > 252) qta = 252; tbf->ta = qta >> 2; - tbf->direction = GPRS_RLCMAC_UL_TBF; - tbf->dir.ul.usf = usf; tbf_new_state(tbf, GPRS_RLCMAC_FLOW); tbf_timer_start(tbf, 3169, bts->t3169, 0); LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi); @@ -848,7 +844,7 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate Assignment Uplink (AGCH)\n", tbf->tfi); bitvec *immediate_assignment = bitvec_alloc(22) /* without plen */; bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); - int plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->ts, tbf->tsc, tbf->tfi, usf, 0, 0, 0); + int plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0); pcu_l1if_tx_agch(immediate_assignment, plen); bitvec_free(immediate_assignment); @@ -1013,8 +1009,7 @@ do_resend: "header, and we are done\n", chunk, space); LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for " "TBF=%d that fits precisely in last block: " - "%s\n", tbf->tfi, - osmo_hexdump(tbf->llc_frame, tbf->llc_length)); + "len=%d\n", tbf->tfi, tbf->llc_length); /* block is filled, so there is no extension */ *e_pointer |= 0x01; /* fill space */ @@ -1072,9 +1067,8 @@ do_resend: memcpy(data, tbf->llc_frame + tbf->llc_index, chunk); data += chunk; space -= chunk; - LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: %s\n", - tbf->tfi, - osmo_hexdump(tbf->llc_frame, tbf->llc_length)); + LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: " + "len=%d\n", tbf->tfi, tbf->llc_length); /* reset LLC frame */ tbf->llc_index = tbf->llc_length = 0; /* dequeue next LLC frame, if any */ @@ -1150,6 +1144,7 @@ tx_block: /* schedule polling */ tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; + tbf->poll_ts = tbf->first_ts; /* set polling in header */ rh->rrbp = 0; /* N+13 */ @@ -1286,12 +1281,14 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( struct msgb *msg; struct gprs_rlcmac_tbf *new_tbf; +#if POLLING_ASSIGNMENT == 1 if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { - LOGP(DRLCMACDL, LOGL_DEBUG, "Polling is already " + LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already " "sheduled for TBF=%d, so we must wait for downlink " "assignment...\n", tbf->tfi); return NULL; } +#endif /* on uplink TBF we get the downlink TBF to be assigned. */ if (tbf->direction == GPRS_RLCMAC_UL_TBF) @@ -1319,8 +1316,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( LOGP(DRLCMAC, LOGL_INFO, "TBF: START TFI: %u TLLI: 0x%08x Packet Downlink Assignment (PACCH)\n", new_tbf->tfi, new_tbf->tlli); RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); write_packet_downlink_assignment(mac_control_block, tbf->tfi, - (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf->tfi, - new_tbf->arfcn, new_tbf->ts, new_tbf->ta, new_tbf->tsc, + (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf, POLLING_ASSIGNMENT); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n"); encode_gsm_rlcmac_downlink(ass_vec, mac_control_block); @@ -1333,6 +1329,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( #if POLLING_ASSIGNMENT == 1 tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; + tbf->poll_ts = tbf->first_ts; tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; #else tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; @@ -1349,7 +1346,7 @@ static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll, bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); /* use request reference that has maximum distance to current time, * so the assignment will not conflict with possible RACH requests. */ - int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn); + int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn); pcu_l1if_tx_pch(immediate_assignment, plen, imsi); bitvec_free(immediate_assignment); } @@ -1381,8 +1378,8 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, tbf_timer_start(tbf, 1234, 1,0); #else LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment on " - "PACCH, because %slink TBF=%d exists for TLLI=0x%08x\n", - (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "down" : "up", + "PACCH, because %s TBF=%d exists for TLLI=0x%08x\n", + (old_tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", old_tbf->tfi, old_tbf->tlli); old_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; /* use TA from old TBF */ diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index 4a4b85ca..7d9a156f 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -61,36 +61,43 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, poll_fn ++; poll_fn = poll_fn % 2715648; for (tfi = 0; tfi < 32; tfi++) { - tbf = pdch->tbf[tfi]; - /* no TBF for this tfi, go next */ - if (!tbf) - continue; - /* no polling */ - if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) - continue; - /* polling for next uplink block */ - if (tbf->poll_fn == poll_fn) - break; + tbf = pdch->ul_tbf[tfi]; + if (tbf) { + /* no polling */ + if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) + continue; + /* polling for next uplink block */ + if (tbf->poll_fn == poll_fn) + break; + } + tbf = pdch->dl_tbf[tfi]; + if (tbf) { + /* no polling */ + if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) + continue; + /* polling for next uplink block */ + if (tbf->poll_fn == poll_fn) + break; + } } /* found uplink where a block is polled */ if (tfi < 32) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " "TS=%d FN=%d block_nr=%d scheduling free USF for " - "polling at FN=%d of TFI=%d\n", trx, ts, fn, block_nr, - poll_fn, tfi); + "polling at FN=%d of %s TFI=%d\n", trx, ts, fn, + block_nr, poll_fn, + (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", + tfi); /* use free USF */ /* else, we search for uplink ressource */ } else { /* select uplink ressource */ for (i = 0, tfi = pdch->next_ul_tfi; i < 32; i++, tfi = (tfi + 1) & 31) { - tbf = pdch->tbf[tfi]; + tbf = pdch->ul_tbf[tfi]; /* no TBF for this tfi, go next */ if (!tbf) continue; - /* no UL TBF, go next */ - if (tbf->direction != GPRS_RLCMAC_UL_TBF) - continue; /* no UL ressources needed, go next */ /* we don't need to give ressources in FINISHED state, * because we have received all blocks and only poll @@ -99,11 +106,11 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, continue; /* use this USF */ - usf = tbf->dir.ul.usf; + usf = tbf->dir.ul.usf[ts]; LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: " "TRX=%d TS=%d FN=%d block_nr=%d scheduling " "USF=%d for required uplink ressource of " - "TBF=%d\n", trx, ts, fn, block_nr, usf, tfi); + "UL TBF=%d\n", trx, ts, fn, block_nr, usf, tfi); /* next TBF to handle ressource is the next one */ pdch->next_ul_tfi = (tfi + 1) & 31; break; @@ -111,8 +118,11 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, } /* Prio 1: select control message */ - for (tfi = 0; tfi < 32; tfi++) { - tbf = pdch->tbf[tfi]; + for (i = 0; i < 64; i++) { + if (i < 32) + tbf = pdch->ul_tbf[i]; + else + tbf = pdch->dl_tbf[i & 31]; /* no TBF for this tfi, go next */ if (!tbf) continue; @@ -131,7 +141,9 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, msg = gprs_rlcmac_send_uplink_ack(tbf, fn); if (msg) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " - "message at RTS for TBF=%d\n", tfi); + "message at RTS for %s TBF=%d\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", tbf->tfi); break; } } @@ -141,7 +153,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* select downlink ressource */ for (i = 0, tfi = pdch->next_dl_tfi; i < 32; i++, tfi = (tfi + 1) & 31) { - tbf = pdch->tbf[tfi]; + tbf = pdch->dl_tbf[tfi]; /* no TBF for this tfi, go next */ if (!tbf) continue; @@ -154,7 +166,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, continue; LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data " - "message at RTS for TBF=%d\n", tfi); + "message at RTS for DL TBF=%d\n", tfi); /* next TBF to handle ressource is the next one */ pdch->next_dl_tfi = (tfi + 1) & 31; /* generate DL data block */ diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index d0f2e325..a58a1221 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -182,8 +182,8 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind) switch (data_ind->sapi) { case PCU_IF_SAPI_PDTCH: - rc = gprs_rlcmac_rcv_block(data_ind->data, data_ind->len, - data_ind->fn); + rc = gprs_rlcmac_rcv_block(data_ind->trx_nr, data_ind->ts_nr, + data_ind->data, data_ind->len, data_ind->fn); break; default: LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with " @@ -265,7 +265,10 @@ bssgp_failed: bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; for (ts = 0; ts < 8; ts++) { for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].tbf[tfi]; + tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; + if (tbf) + tbf_free(tbf); + tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; if (tbf) tbf_free(tbf); } @@ -369,9 +372,12 @@ bssgp_failed: if (bts->trx[trx].pdch[ts].enable) pcu_tx_act_req(trx, ts, 0); bts->trx[trx].pdch[ts].enable = 0; - /* kick all tbf FIXME: multislot */ + /* kick all TBF on slot */ for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].tbf[tfi]; + tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; + if (tbf) + tbf_free(tbf); + tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; if (tbf) tbf_free(tbf); } @@ -384,8 +390,6 @@ bssgp_failed: static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - int trx, ts, tfi; struct gprs_rlcmac_tbf *tbf; uint32_t elapsed; uint8_t fn13 = time_ind->fn % 13; @@ -400,19 +404,18 @@ static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind) set_current_fn(time_ind->fn); /* check for poll timeout */ - for (trx = 0; trx < 8; trx++) { - for (ts = 0; ts < 8; ts++) { - for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].tbf[tfi]; - if (!tbf) - continue; - if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) - continue; - elapsed = (frame_number - tbf->poll_fn) - % 2715648; - if (elapsed >= 20 && elapsed < 200) - gprs_rlcmac_poll_timeout(tbf); - } + llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) { + if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) { + elapsed = (frame_number - tbf->poll_fn) % 2715648; + if (elapsed >= 20 && elapsed < 200) + gprs_rlcmac_poll_timeout(tbf); + } + } + llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { + if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) { + elapsed = (frame_number - tbf->poll_fn) % 2715648; + if (elapsed >= 20 && elapsed < 200) + gprs_rlcmac_poll_timeout(tbf); } } diff --git a/src/sysmo_sock.cpp b/src/sysmo_sock.cpp index 390f3f69..6b390edc 100644 --- a/src/sysmo_sock.cpp +++ b/src/sysmo_sock.cpp @@ -97,7 +97,10 @@ static void pcu_sock_close(struct pcu_sock_state *state) for (ts = 0; ts < 8; ts++) { bts->trx[trx].pdch[ts].enable = 0; for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].tbf[tfi]; + tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; + if (tbf) + tbf_free(tbf); + tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; if (tbf) tbf_free(tbf); } diff --git a/src/tbf.txt b/src/tbf.txt index 3c06b39c..57254ea3 100644 --- a/src/tbf.txt +++ b/src/tbf.txt @@ -109,3 +109,33 @@ Polling: - The received frame is bad (BFI). - The GSM indicates that the block should have been already received. +Data structures of TBFs and PDCHs: + + There is a global structure for BTS. + + The BTS structure has 8 TRX structures. + + Each TRX structure has 8 PDCH structures, one for each timeslot. + + There are two linked lists of TBF instances: + - uplink TBFs + - downlink TBFs + + Each TBF instance also has: + - a direction + - a TFI of range 0..31 + - an array of 8 PDCH structures, one for each assigned timeslot + - in case of uplink TBF: an array of 8 USFs, one for each assigned timeslot + + Each PDCH structure also has: + - an array of 32 uplink TBFs that are assigned to this PDCH + - an array of 32 downlink TBFs that are assigned to this PDCH + + On creation of a new TBF, it links to all assigned PDCHs. + Each PDCH links to that TBF. The TBF is added to the list of TBFs. + In case of uplink TBF: The allocated USFs are stored for each timeslot. + + On release of a TBF, the link to this PDCH is removed from all assigned + PDCHs. The TBF is removed from the list of TBFs. The TBF is destroyed. + + -- cgit v1.2.3 From f298fa87b948b03ed71bc8538c14778b680612dc Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 13 Jul 2012 14:50:57 +0200 Subject: multislot: Extracted "slot allocation algorithm" from tbf allocator The current available algorithm only supports selecting a single slot for downlink/uplink. (In the future, a multislot algorithm will follow.) --- src/gprs_rlcmac.cpp | 133 ++++++++++++++++++++++++++++------------------- src/gprs_rlcmac.h | 6 ++- src/gprs_rlcmac_data.cpp | 10 ++-- src/pcu_main.cpp | 3 ++ 4 files changed, 92 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index ab04aeab..3db405f2 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -176,17 +176,16 @@ struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts) } struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, - uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t num_ts) + uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t ms_class) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - struct gprs_rlcmac_pdch *pdch; struct gprs_rlcmac_tbf *tbf; - uint8_t ts_count, ts; - int8_t usf, tsc = -1; /* both must be signed */ + int rc; LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n"); - LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF with TFI=%d on TRX=%d.\n", - (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tfi, trx); + LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: TFI=%d TRX=%d " + "MS_CLASS=%d\n", (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", + tfi, trx, ms_class); if (trx >= 8 || first_ts >= 8 || tfi >= 32) return NULL; @@ -199,12 +198,34 @@ struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, tbf->tfi = tfi; tbf->trx = trx; tbf->arfcn = bts->trx[trx].arfcn; - /* assign free TS to TBF, where TFI is free - * for uplink: assign free USF to each uplink TS - * Note that the first TS must be free, because it was selected by - * tfi_alloc(). */ - for (ts_count = 0, ts = first_ts; ts < 8; ts++) { - pdch = &bts->trx[trx].pdch[ts]; + tbf->first_ts = first_ts; + tbf->ms_class = ms_class; + tbf->ws = 64; + tbf->sns = 128; + /* select algorithm according to multislot class */ + if (ms_class) + rc = bts->alloc_algorithm(tbf); + else + rc = alloc_algorithm_a(tbf); + /* if no ressource */ + if (rc < 0) { + talloc_free(tbf); + return NULL; + } + + INIT_LLIST_HEAD(&tbf->llc_queue); + if (dir == GPRS_RLCMAC_UL_TBF) + llist_add(&tbf->list, &gprs_rlcmac_ul_tbfs); + else + llist_add(&tbf->list, &gprs_rlcmac_dl_tbfs); + + return tbf; +} + +#if 0 +int alloc_algorithm_b(struct gprs_rlcmac_tbf *tbf) +{ + pdch = &bts->trx[tbf->trx].pdch[ts]; if (!pdch->enable) continue; if (tsc < 0) @@ -214,55 +235,59 @@ struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, "because it has different TSC than lower TS " "of TRX. In order to allow multislot, all " "slots must be configured with the same TSC!\n", - ts, trx); + ts, tbf->trx); continue; } - if (dir == GPRS_RLCMAC_UL_TBF) { - /* if TFI is free on TS */ - if (!pdch->ul_tbf[tfi]) { - /* if USF available */ - usf = find_free_usf(pdch, ts); - if (usf >= 0) { - LOGP(DRLCMAC, LOGL_DEBUG, " Assign " - "uplink TS=%d USF=%d\n", - ts, usf); - pdch->ul_tbf[tfi] = tbf; - tbf->pdch[ts] = pdch; - ts_count++; - } else - LOGP(DRLCMAC, LOGL_DEBUG, " Skipping " - "TS=%d, no USF available\n", - ts); - } - } else { - /* if TFI is free on TS */ - if (!pdch->dl_tbf[tfi]) { - LOGP(DRLCMAC, LOGL_DEBUG, " Assign downlink " - "TS=%d\n", ts); - pdch->dl_tbf[tfi] = tbf; +#endif + +int alloc_algorithm_a(struct gprs_rlcmac_tbf *tbf) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_pdch *pdch; + uint8_t ts = tbf->first_ts; + int8_t usf; /* must be signed */ + + pdch = &bts->trx[tbf->trx].pdch[ts]; + if (!pdch->enable) { + LOGP(DRLCMAC, LOGL_ERROR, "TS=%d not enabled.", ts); + return -EIO; + } + tbf->tsc = pdch->tsc; + if (tbf->direction == GPRS_RLCMAC_UL_TBF) { + /* if TFI is free on TS */ + if (!pdch->ul_tbf[tbf->tfi]) { + /* if USF available */ + usf = find_free_usf(pdch, ts); + if (usf >= 0) { + LOGP(DRLCMAC, LOGL_DEBUG, " Assign uplink " + "TS=%d USF=%d\n", ts, usf); + pdch->ul_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; - ts_count++; + } else { + LOGP(DRLCMAC, LOGL_NOTICE, " Failed allocating " + "TS=%d, no USF available\n", ts); + return -EBUSY; } + } else { + LOGP(DRLCMAC, LOGL_NOTICE, " Failed allocating " + "TS=%d, TFI is not available\n", ts); + return -EBUSY; + } + } else { + /* if TFI is free on TS */ + if (!pdch->dl_tbf[tbf->tfi]) { + LOGP(DRLCMAC, LOGL_DEBUG, " Assign downlink TS=%d\n", + ts); + pdch->dl_tbf[tbf->tfi] = tbf; + tbf->pdch[ts] = pdch; + } else { + LOGP(DRLCMAC, LOGL_NOTICE, " Failed allocating " + "TS=%d, TFI is not available\n", ts); + return -EBUSY; } - if (ts_count == num_ts) - break; - } - if (!ts_count) { /* implies that direction is uplink */ - LOGP(DRLCMAC, LOGL_NOTICE, "No USF available\n"); - talloc_free(tbf); - return NULL; } - tbf->first_ts = first_ts; - tbf->ws = 64; - tbf->sns = 128; - INIT_LLIST_HEAD(&tbf->llc_queue); - if (dir == GPRS_RLCMAC_UL_TBF) - llist_add(&tbf->list, &gprs_rlcmac_ul_tbfs); - else - llist_add(&tbf->list, &gprs_rlcmac_dl_tbfs); - - return tbf; + return 0; } void tbf_free(struct gprs_rlcmac_tbf *tbf) diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index db0e9ab9..71edf3df 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -71,6 +71,7 @@ struct gprs_rlcmac_bts { uint8_t n3103; uint8_t n3105; struct gprs_rlcmac_trx trx[8]; + int (*alloc_algorithm)(struct gprs_rlcmac_tbf *tbf); }; extern struct gprs_rlcmac_bts *gprs_rlcmac_bts; @@ -135,6 +136,7 @@ struct gprs_rlcmac_tbf { uint16_t arfcn; uint8_t tsc; uint8_t first_ts; + uint8_t ms_class; struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */ uint16_t ta; uint8_t llc_frame[LLC_MAX_LEN]; /* current DL or UL frame */ @@ -196,7 +198,9 @@ int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, uint8_t use_trx, uint8_t first_ts); struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, - uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t num_ts); + uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t ms_class); + +int alloc_algorithm_a(struct gprs_rlcmac_tbf *tbf); struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, enum gprs_rlcmac_tbf_direction dir); diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 0e8aca3e..1b936fc7 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -207,9 +207,9 @@ uplink_request: /* FIXME: send reject */ break; } - /* FIXME: set number of downlink slots according to - * multislot class */ - ul_tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 1); + /* use multislot class of downlink TBF */ + ul_tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, + tbf->ms_class); if (!ul_tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ @@ -825,8 +825,8 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) /* FIXME: send reject */ return -EBUSY; } - /* select only one TS, since we don't know the multislot class yet */ - tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 1); + /* set class to 0, since we don't know the multislot class yet */ + tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2c6d7638..9fd04559 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -183,6 +183,9 @@ int main(int argc, char *argv[]) exit(1); } + if (!bts->alloc_algorithm) + bts->alloc_algorithm = alloc_algorithm_a; + rc = pcu_l1if_open(); if (rc < 0) -- cgit v1.2.3 From 51ab134fa8e7f16b627a038ecbfa2051421261de Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 13 Jul 2012 14:52:50 +0200 Subject: Added parsing of multislot class inside BSSGP PDU --- src/gprs_bssgp_pcu.cpp | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index c4d70afd..5f967eef 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -78,6 +78,39 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) } imsi[j] = '\0'; } + + /* parse ms radio access capability */ + uint8_t ms_class = 0; + if (TLVP_PRESENT(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP)) + { + bitvec *block; + uint8_t cap_len = TLVP_LEN(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP); + uint8_t *cap = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP); + unsigned rp = 0; + + block = bitvec_alloc(cap_len); + bitvec_unpack(block, cap); + bitvec_read_field(block, rp, 4); // Access Technology Type + bitvec_read_field(block, rp, 7); // Length of Access Capabilities + bitvec_read_field(block, rp, 3); // RF Power Capability + if (bitvec_read_field(block, rp, 1)) // A5 Bits Present + bitvec_read_field(block, rp, 7); // A5 Bits + bitvec_read_field(block, rp, 1); // ES IND + bitvec_read_field(block, rp, 1); // PS + bitvec_read_field(block, rp, 1); // VGCS + bitvec_read_field(block, rp, 1); // VBS + if (bitvec_read_field(block, rp, 1)) { // Multislot Cap Present + if (bitvec_read_field(block, rp, 1)) // HSCSD Present + bitvec_read_field(block, rp, 5); // Class + if (bitvec_read_field(block, rp, 1)) { // GPRS Present + ms_class = bitvec_read_field(block, rp, 5); // Class + bitvec_read_field(block, rp, 1); // Ext. + } + if (bitvec_read_field(block, rp, 1)) // SMS Present + bitvec_read_field(block, rp, 4); // SMS Value + bitvec_read_field(block, rp, 4); // SMS Value + } + } LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len); /* check for existing TBF */ @@ -118,9 +151,8 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) /* FIXME: send reject */ return -EBUSY; } - /* FIXME: set number of downlink slots according to multislot - * class */ - tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, tfi, trx, ts, 1); + /* set number of downlink slots according to multislot class */ + tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, tfi, trx, ts, ms_class); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ -- cgit v1.2.3 From 592e04ab6d19612ebde5f4a4b9c1cda67ad055db Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 06:25:37 +0200 Subject: multislot: Rework of handling control channel / polling In order to send control blocks to MS and receive control blocks from MS (polling), it is required to select one timeslot that the MS must be able to send and receive. The allocation algorithm must take care of selecting that slot. --- src/gprs_bssgp_pcu.cpp | 15 ++++- src/gprs_rlcmac.cpp | 166 +++++++++++++++++++++++++++++++--------------- src/gprs_rlcmac.h | 27 ++++++-- src/gprs_rlcmac_data.cpp | 24 +++---- src/gprs_rlcmac_sched.cpp | 114 ++++++++++++++++--------------- src/tbf.txt | 20 ++++++ 6 files changed, 236 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 5f967eef..fb298039 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -123,6 +123,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 */ + if (!tbf->ms_class && ms_class) + tbf->ms_class = ms_class; + tbf_update(tbf); gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL); } else { /* the TBF exists, so we must write it in the queue */ @@ -131,17 +134,24 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) return -ENOMEM; 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, ts, use_trx, first_ts; + uint8_t trx, ts, use_trx, first_ts, ta, ss; /* check for uplink data, so we copy our informations */ if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF))) { use_trx = tbf->trx; first_ts = tbf->first_ts; + ta = tbf->ta; + ss = 0; } else { use_trx = -1; first_ts = -1; + ta = 0; /* FIXME: initial TA */ + ss = 1; /* PCH assignment only allows one timeslot */ } // Create new TBF (any TRX) @@ -152,7 +162,8 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) return -EBUSY; } /* set number of downlink slots according to multislot class */ - tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, tfi, trx, ts, ms_class); + tbf = tbf_alloc(tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ts, ms_class, + ss); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 3db405f2..145049eb 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -154,29 +154,30 @@ struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; - uint8_t tfi; /* only one TBF can poll on specific TS/FN, because scheduler can only * schedule one downlink control block (with polling) at a FN per TS */ - for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; - if (tbf && tbf->state != GPRS_RLCMAC_RELEASING + llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) { + if (tbf->state != GPRS_RLCMAC_RELEASING && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED - && tbf->poll_fn == fn && tbf->poll_ts == ts) + && tbf->poll_fn == fn && tbf->trx == trx + && tbf->control_ts == ts) return tbf; - tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; - if (tbf && tbf->state != GPRS_RLCMAC_RELEASING + } + llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { + if (tbf->state != GPRS_RLCMAC_RELEASING && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED - && tbf->poll_fn == fn && tbf->poll_ts == ts) + && tbf->poll_fn == fn && tbf->trx == trx + && tbf->control_ts == ts) return tbf; } return NULL; } -struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, - uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t ms_class) +struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, + enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, + uint8_t first_ts, uint8_t ms_class, uint8_t single_slot) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; @@ -202,11 +203,21 @@ struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, tbf->ms_class = ms_class; tbf->ws = 64; tbf->sns = 128; - /* select algorithm according to multislot class */ - if (ms_class) - rc = bts->alloc_algorithm(tbf); + /* select algorithm A in case we don't have multislot class info */ + if (single_slot || ms_class == 0) + rc = alloc_algorithm_a(old_tbf, tbf, + bts->alloc_algorithm_curst); else - rc = alloc_algorithm_a(tbf); + rc = bts->alloc_algorithm(old_tbf, tbf, + bts->alloc_algorithm_curst); + /* if no ressource */ + if (rc < 0) { + talloc_free(tbf); + return NULL; + } + /* assign control ts */ + tbf->control_ts = 0xff; + rc = tbf_assign_control_ts(tbf); /* if no ressource */ if (rc < 0) { talloc_free(tbf); @@ -222,31 +233,21 @@ struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, return tbf; } -#if 0 -int alloc_algorithm_b(struct gprs_rlcmac_tbf *tbf) -{ - pdch = &bts->trx[tbf->trx].pdch[ts]; - if (!pdch->enable) - continue; - if (tsc < 0) - tbf->tsc = tsc = pdch->tsc; - else if (tsc != pdch->tsc) { - LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS=%d of TRX=%d, " - "because it has different TSC than lower TS " - "of TRX. In order to allow multislot, all " - "slots must be configured with the same TSC!\n", - ts, tbf->trx); - continue; - } -#endif - -int alloc_algorithm_a(struct gprs_rlcmac_tbf *tbf) +/* Slot Allocation: Algorithm A + * + * Assign single slot for uplink and downlink + */ +int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; uint8_t ts = tbf->first_ts; int8_t usf; /* must be signed */ + LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class " + "%d\n", tbf->ms_class); + pdch = &bts->trx[tbf->trx].pdch[ts]; if (!pdch->enable) { LOGP(DRLCMAC, LOGL_ERROR, "TS=%d not enabled.", ts); @@ -259,43 +260,66 @@ int alloc_algorithm_a(struct gprs_rlcmac_tbf *tbf) /* if USF available */ usf = find_free_usf(pdch, ts); if (usf >= 0) { - LOGP(DRLCMAC, LOGL_DEBUG, " Assign uplink " + LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink " "TS=%d USF=%d\n", ts, usf); pdch->ul_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; } else { - LOGP(DRLCMAC, LOGL_NOTICE, " Failed allocating " - "TS=%d, no USF available\n", ts); + LOGP(DRLCMAC, LOGL_NOTICE, "- Failed " + "allocating TS=%d, no USF available\n", + ts); return -EBUSY; } } else { - LOGP(DRLCMAC, LOGL_NOTICE, " Failed allocating " + LOGP(DRLCMAC, LOGL_NOTICE, "- Failed allocating " "TS=%d, TFI is not available\n", ts); return -EBUSY; } } else { /* if TFI is free on TS */ if (!pdch->dl_tbf[tbf->tfi]) { - LOGP(DRLCMAC, LOGL_DEBUG, " Assign downlink TS=%d\n", + LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d\n", ts); pdch->dl_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; } else { - LOGP(DRLCMAC, LOGL_NOTICE, " Failed allocating " + LOGP(DRLCMAC, LOGL_NOTICE, "- Failed allocating " "TS=%d, TFI is not available\n", ts); return -EBUSY; } } + /* the only one TS is the common TS */ + tbf->first_common_ts = ts; return 0; } -void tbf_free(struct gprs_rlcmac_tbf *tbf) +static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf) { struct gprs_rlcmac_pdch *pdch; - struct msgb *msg; int ts; + if (tbf->direction == GPRS_RLCMAC_UL_TBF) { + for (ts = 0; ts < 8; ts++) { + pdch = tbf->pdch[ts]; + if (pdch) + pdch->ul_tbf[tbf->tfi] = NULL; + tbf->pdch[ts] = NULL; + } + } else { + for (ts = 0; ts < 8; ts++) { + pdch = tbf->pdch[ts]; + if (pdch) + pdch->dl_tbf[tbf->tfi] = NULL; + tbf->pdch[ts] = NULL; + } + } +} + +void tbf_free(struct gprs_rlcmac_tbf *tbf) +{ + struct msgb *msg; + LOGP(DRLCMAC, LOGL_INFO, "Free %s TBF=%d with TLLI=0x%08x.\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli); @@ -312,24 +336,56 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf) tbf_timer_stop(tbf); while ((msg = msgb_dequeue(&tbf->llc_queue))) msgb_free(msg); - if (tbf->direction == GPRS_RLCMAC_UL_TBF) { - for (ts = 0; ts < 8; ts++) { - pdch = tbf->pdch[ts]; - if (pdch) - pdch->ul_tbf[tbf->tfi] = NULL; - } - } else { - for (ts = 0; ts < 8; ts++) { - pdch = tbf->pdch[ts]; - if (pdch) - pdch->dl_tbf[tbf->tfi] = NULL; - } - } + tbf_unlink_pdch(tbf); llist_del(&tbf->list); LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF ends here **********\n"); talloc_free(tbf); } +int tbf_update(struct gprs_rlcmac_tbf *tbf) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_tbf *ul_tbf = NULL; + int rc; + + LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF update **********\n"); + + if (tbf->direction != GPRS_RLCMAC_DL_TBF) + return -EINVAL; + + if (!tbf->ms_class) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Cannot update, no class\n"); + return -EINVAL; + } + + if (tbf->tlli_valid) + ul_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); + + tbf_unlink_pdch(tbf); + rc = bts->alloc_algorithm(ul_tbf, tbf, bts->alloc_algorithm_curst); + /* if no ressource */ + if (rc < 0) { + LOGP(DRLCMAC, LOGL_ERROR, "No ressource after update???\n"); + return -rc; + } + + return 0; +} + +int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf) +{ + if (tbf->control_ts == 0xff) + LOGP(DRLCMAC, LOGL_DEBUG, "- Setting Control TS %d\n", + tbf->control_ts); + else if (tbf->control_ts != tbf->first_common_ts) + LOGP(DRLCMAC, LOGL_DEBUG, "- Changing Control TS %d\n", + tbf->control_ts); + tbf->control_ts = tbf->first_common_ts; + + return 0; +} + + const char *tbf_state_name[] = { "NULL", "ASSIGN", diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 71edf3df..1e6bc0d2 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -71,7 +71,9 @@ struct gprs_rlcmac_bts { uint8_t n3103; uint8_t n3105; struct gprs_rlcmac_trx trx[8]; - int (*alloc_algorithm)(struct gprs_rlcmac_tbf *tbf); + int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust); + uint32_t alloc_algorithm_curst; /* options to customize algorithm */ }; extern struct gprs_rlcmac_bts *gprs_rlcmac_bts; @@ -135,7 +137,10 @@ struct gprs_rlcmac_tbf { uint8_t trx; uint16_t arfcn; uint8_t tsc; - uint8_t first_ts; + uint8_t first_ts; /* first TS used by TBF */ + uint8_t first_common_ts; /* first TS that the phone can send and + reveive simultaniously */ + uint8_t control_ts; /* timeslot control messages and polling */ uint8_t ms_class; struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */ uint16_t ta; @@ -150,7 +155,6 @@ struct gprs_rlcmac_tbf { enum gprs_rlcmac_tbf_poll_state poll_state; uint32_t poll_fn; /* frame number to poll */ - uint8_t poll_ts; /* timeslot to poll */ uint16_t ws; /* window size */ uint16_t sns; /* sequence number space */ @@ -197,10 +201,15 @@ extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */ int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, uint8_t use_trx, uint8_t first_ts); -struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir, - uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t ms_class); +struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, + enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, + uint8_t first_ts, uint8_t ms_class, uint8_t single_slot); -int alloc_algorithm_a(struct gprs_rlcmac_tbf *tbf); +int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust); + +int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust); struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, enum gprs_rlcmac_tbf_direction dir); @@ -212,6 +221,10 @@ struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts); void tbf_free(struct gprs_rlcmac_tbf *tbf); +int tbf_update(struct gprs_rlcmac_tbf *tbf); + +int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf); + void tbf_new_state(struct gprs_rlcmac_tbf *tbf, enum gprs_rlcmac_tbf_state state); @@ -275,7 +288,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len); struct msgb *gprs_rlcmac_send_data_block_acknowledged( - struct gprs_rlcmac_tbf *tbf, uint32_t fn); + struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts); struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, uint32_t fn); diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 1b936fc7..bbbcfd55 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -139,7 +139,8 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, tbf = tbf_by_poll_fn(fn, trx, ts); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with " - "unknown FN=%u TLL=0x%08x\n", fn, tlli); + "unknown FN=%u TLL=0x%08x (TRX %d TS %d)\n", + fn, tlli, trx, ts); break; } tfi = tbf->tfi; @@ -176,7 +177,8 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, tbf = tbf_by_poll_fn(fn, trx, ts); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET DOWNLINK ACK with " - "unknown FN=%u TBF=%d\n", fn, tfi); + "unknown FN=%u TBF=%d (TRX %d TS %d)\n", + fn, tfi, trx, ts); break; } /* reset N3105 */ @@ -208,8 +210,8 @@ uplink_request: break; } /* use multislot class of downlink TBF */ - ul_tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, - tbf->ms_class); + ul_tbf = tbf_alloc(tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, + ts, tbf->ms_class, 0); if (!ul_tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ @@ -286,9 +288,10 @@ void tbf_timer_cb(void *_tbf) #endif case 0: /* assignment */ /* change state to FLOW, so scheduler will start transmission */ - if (tbf->state == GPRS_RLCMAC_ASSIGN) + if (tbf->state == GPRS_RLCMAC_ASSIGN) { tbf_new_state(tbf, GPRS_RLCMAC_FLOW); - else + tbf_assign_control_ts(tbf); + } else LOGP(DRLCMAC, LOGL_ERROR, "Error: TBF is not in assign " "state\n"); break; @@ -550,7 +553,6 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, if (final) { tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; - tbf->poll_ts = tbf->first_ts; /* waiting for final acknowledge */ tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK; } else @@ -800,7 +802,6 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( FIXME process does not work, also the acknowledgement is not checked. tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; - tbf->poll_ts = tbf->first_ts; tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; #else tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; @@ -826,7 +827,7 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) return -EBUSY; } /* set class to 0, since we don't know the multislot class yet */ - tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0); + tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ @@ -861,7 +862,7 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) * The messages are fragmented and forwarded as data blocks. */ struct msgb *gprs_rlcmac_send_data_block_acknowledged( - struct gprs_rlcmac_tbf *tbf, uint32_t fn) + struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct rlc_dl_header *rh; @@ -1144,7 +1145,6 @@ tx_block: /* schedule polling */ tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; - tbf->poll_ts = tbf->first_ts; /* set polling in header */ rh->rrbp = 0; /* N+13 */ @@ -1269,6 +1269,7 @@ 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_update(tbf); gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL); return 0; @@ -1329,7 +1330,6 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( #if POLLING_ASSIGNMENT == 1 tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; - tbf->poll_ts = tbf->first_ts; tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; #else tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index 7d9a156f..f88b09b5 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -36,7 +36,8 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; - struct gprs_rlcmac_tbf *tbf; + struct gprs_rlcmac_tbf *tbf, *poll_tbf = NULL, *dl_ass_tbf = NULL, + *ul_ass_tbf = NULL, *ul_ack_tbf = NULL; uint8_t usf = 0x7; struct msgb *msg = NULL; uint32_t poll_fn; @@ -55,39 +56,50 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* store last frame number of RTS */ pdch->last_rts_fn = fn; - /* check uplink ressource for polling */ + /* check special TBF for events */ poll_fn = fn + 4; if ((block_nr % 3) == 2) poll_fn ++; poll_fn = poll_fn % 2715648; - for (tfi = 0; tfi < 32; tfi++) { - tbf = pdch->ul_tbf[tfi]; - if (tbf) { - /* no polling */ - if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) - continue; - /* polling for next uplink block */ - if (tbf->poll_fn == poll_fn) - break; - } - tbf = pdch->dl_tbf[tfi]; - if (tbf) { - /* no polling */ - if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED) - continue; - /* polling for next uplink block */ - if (tbf->poll_fn == poll_fn) - break; - } + llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) { + /* this trx, this ts */ + if (tbf->trx != trx || tbf->control_ts != ts) + continue; + /* polling for next uplink block */ + if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED + && tbf->poll_fn == poll_fn) + poll_tbf = tbf; + if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) + dl_ass_tbf = tbf; + if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) + ul_ass_tbf = tbf; + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) + ul_ack_tbf = tbf; } - /* found uplink where a block is polled */ - if (tfi < 32) { + llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { + /* this trx, this ts */ + if (tbf->trx != trx || tbf->control_ts != ts) + continue; + /* polling for next uplink block */ + if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED + && tbf->poll_fn == poll_fn) + poll_tbf = tbf; + if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) + dl_ass_tbf = tbf; + if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) + ul_ass_tbf = tbf; + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) + ul_ack_tbf = tbf; + } + + /* check uplink ressource for polling */ + if (poll_tbf) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " "TS=%d FN=%d block_nr=%d scheduling free USF for " "polling at FN=%d of %s TFI=%d\n", trx, ts, fn, block_nr, poll_fn, (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", - tfi); + poll_tbf->tfi); /* use free USF */ /* else, we search for uplink ressource */ } else { @@ -118,34 +130,26 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, } /* Prio 1: select control message */ - for (i = 0; i < 64; i++) { - if (i < 32) - tbf = pdch->ul_tbf[i]; - else - tbf = pdch->dl_tbf[i & 31]; - /* no TBF for this tfi, go next */ - if (!tbf) - continue; - /* schedule PACKET DOWNLINK ASSIGNMENT */ - if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) - msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, - fn); - else - /* schedule PACKET UPLINK ASSIGNMENT */ - if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) - msg = gprs_rlcmac_send_packet_uplink_assignment(tbf, - fn); - else - /* schedule PACKET UPLINK ACK */ - if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) - msg = gprs_rlcmac_send_uplink_ack(tbf, fn); - if (msg) { - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " - "message at RTS for %s TBF=%d\n", - (tbf->direction == GPRS_RLCMAC_UL_TBF) - ? "UL" : "DL", tbf->tfi); - break; - } + /* schedule PACKET DOWNLINK ASSIGNMENT */ + if (dl_ass_tbf) { + tbf = dl_ass_tbf; + msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, fn); + } else + /* schedule PACKET UPLINK ASSIGNMENT */ + if (ul_ass_tbf) { + tbf = ul_ass_tbf; + msg = gprs_rlcmac_send_packet_uplink_assignment(tbf, fn); + } else + /* schedule PACKET UPLINK ACK */ + if (ul_ack_tbf) { + tbf = ul_ack_tbf; + msg = gprs_rlcmac_send_uplink_ack(tbf, fn); + } + if (msg) { + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " + "message at RTS for %s TBF=%d (TRX=%d, TS=%d)\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", tbf->tfi, trx, ts); } /* Prio 2: select data message for downlink */ @@ -166,11 +170,13 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, continue; LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data " - "message at RTS for DL TBF=%d\n", tfi); + "message at RTS for DL TBF=%d (TRX=%d, " + "TS=%d)\n", tfi, trx, ts); /* next TBF to handle ressource is the next one */ pdch->next_dl_tfi = (tfi + 1) & 31; /* generate DL data block */ - msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn); + msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn, + ts); break; } } diff --git a/src/tbf.txt b/src/tbf.txt index 57254ea3..eab58ba5 100644 --- a/src/tbf.txt +++ b/src/tbf.txt @@ -94,11 +94,27 @@ Handling of LLC Frame of downlink TBF and LLC Queue of downlink TBF: If a new LLC PDU is attached to LLC Frame during WAIT RELEASE state, the state is changed to FLOW (downlink flow is assigned to MS). + Handling of LLC Frame on uplink TBF: Received uplink blocks are appended to LLC Frame of TBF. If the PDU is complete, it is forwarded to the upper layer. + +Control TS: + On uplink or downlink assignment, it is required to have one timeslot that + can be used to receive and transmit. This timeslot is used at uplink TBF + to acknowledge and to assign other TBF. This timeslot is used at downlink + TBF to poll acknowledgement and to assign other TBF. + + The first common TS (first_common_ts) is calculated when channels are + allocated. After creation of TBF or after assignment to different TS layout, + the first common TS is used for control TS. + + The first common TS (and so control TS) must not need to be allocated to + MS as uplink TBF. (E.g. in case of non-available USF for this slot) + + Polling: In order to poll uplink control block from MS, a special poll state and frame number is stored at TBF. The scheduler reads that value and will not @@ -109,6 +125,10 @@ Polling: - The received frame is bad (BFI). - The GSM indicates that the block should have been already received. + Because polling requires uplink response from MS, the polling must be + performed at control TS. + + Data structures of TBFs and PDCHs: There is a global structure for BTS. -- cgit v1.2.3 From 5e043dac8c961995f6bd94b6c0206063efea63ec Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 06:51:30 +0200 Subject: Polling for downlink ack/nack is performed only on suitable slot The slot must be the control channel TS, which is selected by the allocation algorithm. The MS must be able to respond at this TS. The counter to trigger polling is incremented until polling has to be performed. Then the counter stops. When the transmission of data block is requested on control channel TS, the counter is reset. The counter-value is also used to poll immediately when the transmission has finished. --- src/gprs_rlcmac_data.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index bbbcfd55..c95f41cf 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -1092,6 +1092,8 @@ do_resend: "done.\n"); li->e = 1; /* we cannot extend */ rh->fbi = 1; /* we indicate final block */ + tbf->dir.dl.tx_counter = ACK_AFTER_FRAMES + 1; + /* + 1 indicates: force polling */ tbf_new_state(tbf, GPRS_RLCMAC_FINISHED); break; } @@ -1116,27 +1118,31 @@ tx_block: len = tbf->rlc_block_len[index]; rh = (struct rlc_dl_header *)data; - /* Increment TX-counter */ - tbf->dir.dl.tx_counter++; - /* Clear Polling, if still set in history buffer */ rh->s_p = 0; /* poll after ACK_AFTER_FRAMES frames, or when final block is tx. */ - if (rh->fbi == 1 || (tbf->dir.dl.tx_counter % ACK_AFTER_FRAMES) == 0) { - if (rh->fbi == 1) { + if (tbf->dir.dl.tx_counter >= ACK_AFTER_FRAMES) { + if (tbf->dir.dl.tx_counter > ACK_AFTER_FRAMES) { + /* if rx_counter is ACK_AFTER_FRAMES + 1, this + * indicates: poll caused by final ack. */ LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " "polling, because final block sent.\n"); - } - if ((tbf->dir.dl.tx_counter % ACK_AFTER_FRAMES) == 0) { + } else { LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " "polling, because %d blocks sent.\n", ACK_AFTER_FRAMES); } + tbf->dir.dl.tx_counter = 0; + /* scheduling not possible, because: */ if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) - LOGP(DRLCMACDL, LOGL_DEBUG, "Polling is already " + LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already " "sheduled for TBF=%d, so we must wait for " "requesting downlink ack\n", tbf->tfi); + else if (tbf->control_ts != ts) + LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be " + "sheduled in this TS %d, waiting for " + "TS %d\n", ts, tbf->control_ts); else { /* start timer whenever we send the final block */ if (rh->fbi == 1) @@ -1149,7 +1155,13 @@ tx_block: /* set polling in header */ rh->rrbp = 0; /* N+13 */ rh->s_p = 1; /* Polling */ + + /* Increment TX-counter */ + tbf->dir.dl.tx_counter++; } + } else { + /* Increment TX-counter */ + tbf->dir.dl.tx_counter++; } /* return data block as message */ -- cgit v1.2.3 From 6664a903652aac7284d22e072a4b64210b6f7d6e Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 06:52:19 +0200 Subject: Downlink transfer is finished if all packets are acknowleged It turned out that the final ack flag may not be set, but all packets have been acknowledged. This patch will finish transfer in case all blocks are acknowledged. --- src/gprs_rlcmac_data.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index c95f41cf..9b3a0953 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -917,9 +917,8 @@ do_resend: * indication from MS. This should never happen if MS works * correctly. */ if (tbf->dir.dl.v_s == tbf->dir.dl.v_a) { - LOGP(DRLCMACDL, LOGL_ERROR, "- MS acked all block " - "(including final block), but did not include " - "FINAL_ACK_INDICATION!\n"); + LOGP(DRLCMACDL, LOGL_ERROR, "- MS acked all block, " + "but we still transmitting!\n"); /* we just send final block again */ index = ((tbf->dir.dl.v_s - 1) & mod_sns_half); goto tx_block; @@ -1251,7 +1250,12 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, "X=Resend-Unacked\n", tbf->dir.dl.v_a, show_v_b, (tbf->dir.dl.v_s - 1) & mod_sns); - return 0; + if (tbf->state == GPRS_RLCMAC_FINISHED + && tbf->dir.dl.v_s == tbf->dir.dl.v_a) { + LOGP(DRLCMACDL, LOGL_NOTICE, "Received final block, " + "bit without final ack inidcation\n"); + } else + return 0; } LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n"); -- cgit v1.2.3 From 53f4725d10f300b0e8d7c2673ea6b1bc4f2ef2f9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 07:10:10 +0200 Subject: Adding multislot allocation algorithm --- src/gprs_rlcmac.cpp | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pcu_main.cpp | 2 +- 2 files changed, 430 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 145049eb..75744716 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -22,6 +22,55 @@ #include #include +/* 3GPP TS 05.02 Annex B.1 */ + +#define MS_NA 255 /* N/A */ +#define MS_A 254 /* 1 with hopping, 0 without */ +#define MS_B 253 /* 1 with hopping, 0 without (change Rx to Tx)*/ +#define MS_C 252 /* 1 with hopping, 0 without (change Tx to Rx)*/ + +struct gprs_ms_multislot_class { + uint8_t rx, tx, sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */ + uint8_t ta, tb, ra, rb; /* Minimum Number of Slots */ + uint8_t type; /* Type of Mobile */ +}; + +struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = { +/* M-S Class Rx Tx Sum Tta Ttb Tra Trb Type */ +/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA }, +/* 1 */ { 1, 1, 2, 3, 2, 4, 2, 1 }, +/* 2 */ { 2, 1, 3, 3, 2, 3, 1, 1 }, +/* 3 */ { 2, 2, 3, 3, 2, 3, 1, 1 }, +/* 4 */ { 3, 1, 4, 3, 1, 3, 1, 1 }, +/* 5 */ { 2, 2, 4, 3, 1, 3, 1, 1 }, +/* 6 */ { 3, 2, 4, 3, 1, 3, 1, 1 }, +/* 7 */ { 3, 3, 4, 3, 1, 3, 1, 1 }, +/* 8 */ { 4, 1, 5, 3, 1, 2, 1, 1 }, +/* 9 */ { 3, 2, 5, 3, 1, 2, 1, 1 }, +/* 10 */ { 4, 2, 5, 3, 1, 2, 1, 1 }, +/* 11 */ { 4, 3, 5, 3, 1, 2, 1, 1 }, +/* 12 */ { 4, 4, 5, 2, 1, 2, 1, 1 }, +/* 13 */ { 3, 3, MS_NA, MS_NA, MS_A, 3, MS_A, 2 }, +/* 14 */ { 4, 4, MS_NA, MS_NA, MS_A, 3, MS_A, 2 }, +/* 15 */ { 5, 5, MS_NA, MS_NA, MS_A, 3, MS_A, 2 }, +/* 16 */ { 6, 6, MS_NA, MS_NA, MS_A, 2, MS_A, 2 }, +/* 17 */ { 7, 7, MS_NA, MS_NA, MS_A, 1, 0, 2 }, +/* 18 */ { 8, 8, MS_NA, MS_NA, 0, 0, 0, 2 }, +/* 19 */ { 6, 2, MS_NA, 3, MS_B, 2, MS_C, 1 }, +/* 20 */ { 6, 3, MS_NA, 3, MS_B, 2, MS_C, 1 }, +/* 21 */ { 6, 4, MS_NA, 3, MS_B, 2, MS_C, 1 }, +/* 22 */ { 6, 4, MS_NA, 2, MS_B, 2, MS_C, 1 }, +/* 23 */ { 6, 6, MS_NA, 2, MS_B, 2, MS_C, 1 }, +/* 24 */ { 8, 2, MS_NA, 3, MS_B, 2, MS_C, 1 }, +/* 25 */ { 8, 3, MS_NA, 3, MS_B, 2, MS_C, 1 }, +/* 26 */ { 8, 4, MS_NA, 3, MS_B, 2, MS_C, 1 }, +/* 27 */ { 8, 4, MS_NA, 2, MS_B, 2, MS_C, 1 }, +/* 28 */ { 8, 6, MS_NA, 2, MS_B, 2, MS_C, 1 }, +/* 29 */ { 8, 8, MS_NA, 2, MS_B, 2, MS_C, 1 }, +/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA }, +/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA }, +}; + LLIST_HEAD(gprs_rlcmac_ul_tbfs); LLIST_HEAD(gprs_rlcmac_dl_tbfs); void *rlcmac_tall_ctx; @@ -294,6 +343,386 @@ int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, return 0; } +/* Slot Allocation: Algorithm B + * + * Assign as many downlink slots as possible. + * Assign one uplink slot. (With free USF) + * + */ +int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_pdch *pdch; + struct gprs_ms_multislot_class *ms_class; + uint8_t Rx, Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */ + uint8_t Tta, Ttb, Tra, Trb, Tt, Tr; /* Minimum Number of Slots */ + uint8_t Type; /* Type of Mobile */ + uint8_t rx_win_min, rx_win_max; + uint8_t tx_win_min, tx_win_max, tx_range; + uint8_t rx_window = 0, tx_window = 0; + const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" }; + uint8_t usf[8]; + int8_t tsc = -1; /* must be signed */ + uint8_t i, ts; + + LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for class " + "%d\n", tbf->ms_class); + + if (tbf->ms_class >= 32) { + LOGP(DRLCMAC, LOGL_ERROR, "Multislot class %d out of range.\n", + tbf->ms_class); + return -EINVAL; + } + + ms_class = &gprs_ms_multislot_class[tbf->ms_class]; + if (ms_class->tx == MS_NA) { + LOGP(DRLCMAC, LOGL_NOTICE, "Multislot class %d not " + "applicable.\n", tbf->ms_class); + return -EINVAL; + } + + Rx = ms_class->rx; + Tx = ms_class->tx; + Sum = ms_class->sum; + Tta = ms_class->ta; + Ttb = ms_class->tb; + Tra = ms_class->ra; + Trb = ms_class->rb; + Type = ms_class->type; + + /* Tta and Ttb may depend on hopping or frequency change */ + if (Ttb == MS_A) { + if (/* FIXME: hopping*/ 0) + Ttb = 1; + else + Ttb = 0; + } + if (Trb == MS_A) { + if (/* FIXME: hopping*/ 0) + Ttb = 1; + else + Ttb = 0; + } + if (Ttb == MS_B) { + /* FIXME: or frequency change */ + if (/* FIXME: hopping*/ 0) + Ttb = 1; + else + Ttb = 0; + } + if (Trb == MS_C) { + /* FIXME: or frequency change */ + if (/* FIXME: hopping*/ 0) + Ttb = 1; + else + Ttb = 0; + } + + LOGP(DRLCMAC, LOGL_DEBUG, "- Rx=%d Tx=%d Sum Rx+Tx=%s Tta=%s Ttb=%d " + " Tra=%d Trb=%d Type=%d\n", Rx, Tx, + (Sum == MS_NA) ? "N/A" : digit[Sum], + (Tta == MS_NA) ? "N/A" : digit[Tta], Ttb, Tra, Trb, Type); + + /* select the values for time contraints */ + if (/* FIXME: monitoring */0) { + /* applicable to type 1 and type 2 */ + Tt = Ttb; + Tr = Tra; + } else { + /* applicable to type 1 and type 2 */ + Tt = Ttb; + Tr = Trb; + } + + /* select a window of Rx slots if available + * The maximum allowed slots depend on RX or the window of available + * slots. + * This must be done for uplink TBF also, because it is the basis + * for calculating control slot and uplink slot(s). */ + rx_win_min = rx_win_max = tbf->first_ts; + for (ts = tbf->first_ts, i = 0; ts < 8; ts++) { + pdch = &bts->trx[tbf->trx].pdch[ts]; + /* check if enabled */ + if (!pdch->enable) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because " + "not enabled\n", ts); + /* increase window for Type 1 */ + if (Type == 1) + i++; + continue; + } + /* check if TSC changes */ + if (tsc < 0) + tbf->tsc = tsc = pdch->tsc; + else if (tsc != pdch->tsc) { + LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of TRX=%d, " + "because it has different TSC than lower TS " + "of TRX. In order to allow multislot, all " + "slots must be configured with the same " + "TSC!\n", ts, tbf->trx); + /* increase window for Type 1 */ + if (Type == 1) + i++; + continue; + } + /* check if TFI for slot is available + * This is only possible for downlink TFI. */ + if (tbf->direction == GPRS_RLCMAC_DL_TBF + && pdch->dl_tbf[tbf->tfi]) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because " + "already assigned to other DL TBF with " + "TFI=%d\n", ts, tbf->tfi); + /* increase window for Type 1 */ + if (Type == 1) + i++; + continue; + } + + rx_window |= (1 << ts); + LOGP(DRLCMAC, LOGL_DEBUG, "- Selected DL TS %d\n", ts); + + /* range of window (required for Type 1) */ + rx_win_max = ts; + + if (++i == Rx) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because slots / " + "window reached maximum alowed Rx size\n"); + break; + } + } + + LOGP(DRLCMAC, LOGL_DEBUG, "- Selected slots for RX: " + "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n", + ((rx_window & 0x01)) ? 'D' : '.', + ((rx_window & 0x02)) ? 'D' : '.', + ((rx_window & 0x04)) ? 'D' : '.', + ((rx_window & 0x08)) ? 'D' : '.', + ((rx_window & 0x10)) ? 'D' : '.', + ((rx_window & 0x20)) ? 'D' : '.', + ((rx_window & 0x40)) ? 'D' : '.', + ((rx_window & 0x80)) ? 'D' : '.'); + + /* reduce window, if existing uplink slots collide RX window */ + if (Type == 1 && old_tbf && old_tbf->direction == GPRS_RLCMAC_UL_TBF) { + uint8_t collide = 0, ul_usage = 0; + int j; + + /* calculate mask of colliding slots */ + for (ts = old_tbf->first_ts; ts < 8; ts++) { + if (old_tbf->pdch[ts]) { + ul_usage |= (1 << ts); + /* mark bits from TS-t .. TS+r */ + for (j = ts - Tt; j != ((ts + Tr + 1) & 7); + j = (j + 1) & 7) + collide |= (1 << j); + } + } + LOGP(DRLCMAC, LOGL_DEBUG, "- Not allowed slots due to existing " + "UL allocation: (TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7) " + " D=downlink x=not usable\n", + ((ul_usage & 0x01)) ? 'D' : ((collide & 0x01))?'x':'.', + ((ul_usage & 0x02)) ? 'D' : ((collide & 0x02))?'x':'.', + ((ul_usage & 0x04)) ? 'D' : ((collide & 0x04))?'x':'.', + ((ul_usage & 0x08)) ? 'D' : ((collide & 0x08))?'x':'.', + ((ul_usage & 0x10)) ? 'D' : ((collide & 0x10))?'x':'.', + ((ul_usage & 0x20)) ? 'D' : ((collide & 0x20))?'x':'.', + ((ul_usage & 0x40)) ? 'D' : ((collide & 0x40))?'x':'.', + ((ul_usage & 0x80)) ? 'D' : ((collide & 0x80))?'x':'.'); + + /* apply massk to reduce tx_window (shifted by 3 slots) */ + rx_window &= ~(collide << 3); + rx_window &= ~(collide >> 5); + LOGP(DRLCMAC, LOGL_DEBUG, "- Remaining slots for RX: " + "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n", + ((rx_window & 0x01)) ? 'D' : '.', + ((rx_window & 0x02)) ? 'D' : '.', + ((rx_window & 0x04)) ? 'D' : '.', + ((rx_window & 0x08)) ? 'D' : '.', + ((rx_window & 0x10)) ? 'D' : '.', + ((rx_window & 0x20)) ? 'D' : '.', + ((rx_window & 0x40)) ? 'D' : '.', + ((rx_window & 0x80)) ? 'D' : '.'); + if (!rx_window) { + LOGP(DRLCMAC, LOGL_NOTICE, "No suitable downlink slots " + "available with current uplink assignment\n"); + return -EBUSY; + } + + /* calculate new min/max */ + for (ts = rx_win_min; ts <= rx_win_max; ts++) { + if ((rx_window & (1 << ts))) + break; + rx_win_min = ts + 1; + LOGP(DRLCMAC, LOGL_NOTICE, "- TS has been deleted, so " + "raising start of DL window to %d\n", + rx_win_min); + } + for (ts = rx_win_max; ts >= rx_win_min; ts--) { + if ((rx_window & (1 << ts))) + break; + rx_win_max = ts - 1; + LOGP(DRLCMAC, LOGL_NOTICE, "- TS has been deleted, so " + "lowering end of DL window to %d\n", + rx_win_max); + } + } + + /* reduce window, to allow at least one uplink TX slot + * this is only required for Type 1 */ + if (Type == 1 && rx_win_max - rx_win_min + 1 + Tt + 1 + Tr > 8) { + rx_win_max = rx_win_min + 7 - Tr - 1 - Tr; + LOGP(DRLCMAC, LOGL_DEBUG, "- Reduce RX window due to time " + "contraints to %d slots\n", + rx_win_max - rx_win_min + 1); + } + + LOGP(DRLCMAC, LOGL_DEBUG, "- RX-Window is: %d..%d\n", rx_win_min, + rx_win_max); + + /* calculate TX window */ + if (Type == 1) { + /* calculate TX window (shifted by 3 timeslots) + * it uses the space between tx_win_max and tx_win_min */ + tx_win_min = (rx_win_max - 2 + Tt) & 7; + tx_win_max = (rx_win_min + 4 - Tr) & 7; + /* calculate the TX window size (might be larger than Tx) */ + tx_range = (tx_win_max - tx_win_min + 1) & 7; + } else { + /* TX and RX simultaniously */ + tx_win_min = rx_win_min; + tx_win_max = 7; + /* TX window size (might be larger than Tx) */ + tx_range = tx_win_max - tx_win_min + 1; + } + + LOGP(DRLCMAC, LOGL_DEBUG, "- TX-Window is: %d..%d\n", tx_win_min, + tx_win_max); + + /* select a window of Tx slots if available + * The maximum allowed slots depend on TX or the window of available + * slots. */ + if (tbf->direction == GPRS_RLCMAC_UL_TBF) { + for (ts = tx_win_min, i = 0; i < tx_range; ts = (ts + 1) & 7) { + pdch = &bts->trx[tbf->trx].pdch[ts]; + /* check if enabled */ + if (!pdch->enable) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, " + "because not enabled\n", ts); + continue; + } + /* check if TSC changes */ + if (tsc < 0) + tbf->tsc = tsc = pdch->tsc; + else if (tsc != pdch->tsc) { + LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of " + "TRX=%d, because it has different TSC " + "than lower TS of TRX. In order to " + "allow multislot, all slots must be " + "configured with the same TSC!\n", + ts, tbf->trx); + /* increase window for Type 1 */ + if (Type == 1) + i++; + continue; + } + /* check if TFI for slot is available */ + if (pdch->ul_tbf[tbf->tfi]) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, " + "because already assigned to other " + "UL TBF with TFI=%d\n", ts, tbf->tfi); + /* increase window for Type 1 */ + if (Type == 1) + i++; + continue; + } + /* check for free usf */ + usf[ts] = find_free_usf(pdch, ts); + if (usf[ts] < 0) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, " + "because no USF available\n", ts); + /* increase window for Type 1 */ + if (Type == 1) + i++; + continue; + } + + tx_window |= (1 << ts); + LOGP(DRLCMAC, LOGL_DEBUG, "- Selected UL TS %d\n", ts); + + if (!(cust & 1)) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because " + "1 slot assigned\n"); + break; + } + if (++i == Tx) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because " + "slots / window reached maximum alowed " + "Tx size\n"); + break; + } + } + + LOGP(DRLCMAC, LOGL_DEBUG, "- Selected TX window: " + "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n", + ((tx_window & 0x01)) ? 'U' : '.', + ((tx_window & 0x02)) ? 'U' : '.', + ((tx_window & 0x04)) ? 'U' : '.', + ((tx_window & 0x08)) ? 'U' : '.', + ((tx_window & 0x10)) ? 'U' : '.', + ((tx_window & 0x20)) ? 'U' : '.', + ((tx_window & 0x40)) ? 'U' : '.', + ((tx_window & 0x80)) ? 'U' : '.'); + + if (!tx_window) { + LOGP(DRLCMAC, LOGL_NOTICE, "No suitable uplink slots " + "available\n"); + return -EBUSY; + } + } + + if (tbf->direction == GPRS_RLCMAC_DL_TBF) { + /* assign downlink */ + if (rx_window == 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots " + "available\n"); + return -EINVAL; + } + for (ts = 0; ts < 8; ts++) { + if ((rx_window & (1 << ts))) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS " + "%d\n", ts); + pdch = &bts->trx[tbf->trx].pdch[ts]; + pdch->dl_tbf[tbf->tfi] = tbf; + tbf->pdch[ts] = pdch; + } + } + } else { + /* assign uplink */ + if (tx_window == 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "No uplink slots " + "available\n"); + return -EINVAL; + } + for (ts = 0; ts < 8; ts++) { + if ((tx_window & (1 << ts))) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS " + "%d\n", ts); + pdch = &bts->trx[tbf->trx].pdch[ts]; + pdch->ul_tbf[tbf->tfi] = tbf; + tbf->pdch[ts] = pdch; + tbf->dir.ul.usf[ts] = usf[ts]; + } + } + } + + /* the timeslot of the TX window start is always + * available in RX window */ + tbf->first_common_ts = tx_win_min; + + return 0; +} + static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf) { struct gprs_rlcmac_pdch *pdch; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 9fd04559..2d7e8ffc 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) } if (!bts->alloc_algorithm) - bts->alloc_algorithm = alloc_algorithm_a; + bts->alloc_algorithm = alloc_algorithm_b; rc = pcu_l1if_open(); -- cgit v1.2.3 From 06f96cd5a72e475db44bda14a9bf86bed4260857 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 07:12:36 +0200 Subject: Added missing TA value assignment --- src/gprs_bssgp_pcu.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index fb298039..945addce 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -171,6 +171,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) } 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); -- cgit v1.2.3 From ee31b78cfd0945e92a8e11e1460e57886cd5b854 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 16:27:01 +0200 Subject: Fixed contention resolution issue In order to do downlink assignment during uplink TBF, the content resolution must be completed. It is completed when the first Packet Uplink Ack/Nack message is transmitted to the mobile. --- src/gprs_rlcmac.h | 1 + src/gprs_rlcmac_data.cpp | 20 +++++++++++++++++--- src/gprs_rlcmac_sched.cpp | 14 ++++++-------- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 1e6bc0d2..ae188f13 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -134,6 +134,7 @@ struct gprs_rlcmac_tbf { uint8_t tfi; uint32_t tlli; uint8_t tlli_valid; + uint8_t contention_resolution_done; /* set after done */ uint8_t trx; uint16_t arfcn; uint8_t tsc; diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 9b3a0953..76cc0332 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -218,7 +218,7 @@ uplink_request: break; } ul_tbf->tlli = tbf->tlli; - ul_tbf->tlli_valid = 1; /* no content resolution */ + ul_tbf->tlli_valid = 1; /* no contention resolution */ ul_tbf->ta = tbf->ta; /* use current TA */ tbf_new_state(ul_tbf, GPRS_RLCMAC_FLOW); tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); @@ -550,6 +550,10 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, bitvec_free(ack_vec); free(mac_control_block); + /* now we must set this flag, so we are allowed to assign downlink + * TBF on PACCH. it is only allowed when TLLI is aknowledged. */ + tbf->contention_resolution_done = 1; + if (final) { tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; @@ -1143,6 +1147,8 @@ tx_block: "sheduled in this TS %d, waiting for " "TS %d\n", ts, tbf->control_ts); else { + LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this " + "TS %d\n", ts); /* start timer whenever we send the final block */ if (rh->fbi == 1) tbf_timer_start(tbf, 3191, bts->t3191, 0); @@ -1308,9 +1314,17 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( #endif /* on uplink TBF we get the downlink TBF to be assigned. */ - if (tbf->direction == GPRS_RLCMAC_UL_TBF) + if (tbf->direction == GPRS_RLCMAC_UL_TBF) { + /* be sure to check first, if contention resolution is done, + * otherwise we cannot send the assignment yet */ + if (!tbf->contention_resolution_done) { + LOGP(DRLCMAC, LOGL_NOTICE, "Cannot assign DL TBF now, " + "because contention resolution is not " + "finished.\n"); + return NULL; + } new_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF); - else + } else new_tbf = tbf; if (!new_tbf) { LOGP(DRLCMACDL, LOGL_ERROR, "We have a schedule for downlink " diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index f88b09b5..cd995166 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -69,12 +69,12 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED && tbf->poll_fn == poll_fn) poll_tbf = tbf; + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) + ul_ack_tbf = tbf; if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) dl_ass_tbf = tbf; if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) ul_ass_tbf = tbf; - if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) - ul_ack_tbf = tbf; } llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { /* this trx, this ts */ @@ -88,8 +88,6 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, dl_ass_tbf = tbf; if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) ul_ass_tbf = tbf; - if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) - ul_ack_tbf = tbf; } /* check uplink ressource for polling */ @@ -134,14 +132,14 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, if (dl_ass_tbf) { tbf = dl_ass_tbf; msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, fn); - } else + } /* schedule PACKET UPLINK ASSIGNMENT */ - if (ul_ass_tbf) { + if (!msg && ul_ass_tbf) { tbf = ul_ass_tbf; msg = gprs_rlcmac_send_packet_uplink_assignment(tbf, fn); - } else + } /* schedule PACKET UPLINK ACK */ - if (ul_ack_tbf) { + if (!msg && ul_ack_tbf) { tbf = ul_ack_tbf; msg = gprs_rlcmac_send_uplink_ack(tbf, fn); } -- cgit v1.2.3 From 52c748ce8f9bc9ae0e919ba9d62c7c03ae7343c6 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 16:33:02 +0200 Subject: Minor fixes of debug output of channel allocation --- src/gprs_rlcmac.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 75744716..a97b6c0d 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -554,7 +554,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, if ((rx_window & (1 << ts))) break; rx_win_min = ts + 1; - LOGP(DRLCMAC, LOGL_NOTICE, "- TS has been deleted, so " + LOGP(DRLCMAC, LOGL_DEBUG, "- TS has been deleted, so " "raising start of DL window to %d\n", rx_win_min); } @@ -562,7 +562,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, if ((rx_window & (1 << ts))) break; rx_win_max = ts - 1; - LOGP(DRLCMAC, LOGL_NOTICE, "- TS has been deleted, so " + LOGP(DRLCMAC, LOGL_DEBUG, "- TS has been deleted, so " "lowering end of DL window to %d\n", rx_win_max); } @@ -682,6 +682,8 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, } if (tbf->direction == GPRS_RLCMAC_DL_TBF) { + uint8_t slotcount = 0; + /* assign downlink */ if (rx_window == 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots " @@ -695,8 +697,12 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, pdch = &bts->trx[tbf->trx].pdch[ts]; pdch->dl_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; + slotcount++; } } + if (slotcount) + LOGP(DRLCMAC, LOGL_INFO, "Using Multislot with %d " + "slots DL\n", slotcount); } else { /* assign uplink */ if (tx_window == 0) { @@ -805,10 +811,10 @@ int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf) { if (tbf->control_ts == 0xff) LOGP(DRLCMAC, LOGL_DEBUG, "- Setting Control TS %d\n", - tbf->control_ts); + tbf->first_common_ts); else if (tbf->control_ts != tbf->first_common_ts) LOGP(DRLCMAC, LOGL_DEBUG, "- Changing Control TS %d\n", - tbf->control_ts); + tbf->first_common_ts); tbf->control_ts = tbf->first_common_ts; return 0; -- cgit v1.2.3 From ab18bab577f706b11fe6ebc3ad4ad2f128fc4d1c Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 16:34:07 +0200 Subject: Set coding scheme on Packet Uplink Ack/Nack message This way the uplink speeds up too. --- src/gprs_rlcmac.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index a97b6c0d..8e10801a 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -1195,6 +1195,7 @@ void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *t char show_v_n[65]; + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; uint8_t rbb = 0; uint16_t i, bbn; uint16_t mod_sns_half = (tbf->sns >> 1) - 1; @@ -1213,7 +1214,7 @@ void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *t block->u.Packet_Uplink_Ack_Nack.UPLINK_TFI = tbf->tfi; // Uplink TFI block->u.Packet_Uplink_Ack_Nack.UnionType = 0x0; // PU_AckNack_GPRS = on - block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.CHANNEL_CODING_COMMAND = 0x0; // CS1 + block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.CHANNEL_CODING_COMMAND = bts->initial_cs - 1; // CS1 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.FINAL_ACK_INDICATION = final; // FINAL ACK INDICATION block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.STARTING_SEQUENCE_NUMBER = tbf->dir.ul.v_r; // STARTING_SEQUENCE_NUMBER // RECEIVE_BLOCK_BITMAP -- cgit v1.2.3 From a9b94074932bff7e4390be52803cd3c5ad956c09 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 19:30:41 +0200 Subject: Only select TLLI, if it is valid (and not unset) --- src/gprs_rlcmac.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 8e10801a..7273362c 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -188,7 +188,7 @@ struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, if (dir == GPRS_RLCMAC_UL_TBF) { llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) { if (tbf->state != GPRS_RLCMAC_RELEASING - && tbf->tlli == tlli) + && tbf->tlli == tlli && tbf->tlli_valid) return tbf; } } else { @@ -793,8 +793,7 @@ int tbf_update(struct gprs_rlcmac_tbf *tbf) return -EINVAL; } - if (tbf->tlli_valid) - ul_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); + ul_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); tbf_unlink_pdch(tbf); rc = bts->alloc_algorithm(ul_tbf, tbf, bts->alloc_algorithm_curst); -- cgit v1.2.3 From c8466f42c5c562da91e170e0942afd09e0cb4406 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 19:34:53 +0200 Subject: Ignore Packet Resource Request --- src/gprs_rlcmac_data.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 76cc0332..bb0b2272 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -124,6 +124,7 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, uint32_t fn) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; int8_t tfi = 0; /* must be signed */ uint32_t tlli = 0; struct gprs_rlcmac_tbf *tbf; @@ -197,7 +198,6 @@ 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) { uint8_t trx, ts; struct gprs_rlcmac_tbf *ul_tbf; - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack " "message, so we provide one:\n"); @@ -253,11 +253,7 @@ uplink_request: } tlli = tbf->tlli; } - LOGP(DRLCMAC, LOGL_INFO, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli); -#warning FIXME -puts("FIXME: UL request during UL request"); exit(0); - - + LOGP(DRLCMAC, LOGL_ERROR, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x FIXME: Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli); break; default: LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] unknown control block received\n"); -- cgit v1.2.3 From 67a19769741625827e3bac838233f3028c4c85cc Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 19:35:46 +0200 Subject: No content resolution is required when UL TBF is requested during DL TBF --- src/gprs_rlcmac_data.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index bb0b2272..1b35d79f 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -219,6 +219,7 @@ uplink_request: } ul_tbf->tlli = tbf->tlli; ul_tbf->tlli_valid = 1; /* no contention resolution */ + ul_tbf->contention_resolution_done = 1; ul_tbf->ta = tbf->ta; /* use current TA */ tbf_new_state(ul_tbf, GPRS_RLCMAC_FLOW); tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); -- cgit v1.2.3 From 67e4f2f1fdba2048082311cc08a36d4758427cd3 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 15 Jul 2012 19:36:49 +0200 Subject: If we already sent final Packet Uplink Ack/Nack, request DL TBF on PCH If network does not respond fast enough, the MS might already received final Packet Uplink Ack/Nack, so we need to assign new DL TBF on PCH. --- src/gprs_rlcmac_data.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 1b35d79f..8e195b8c 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -1397,7 +1397,8 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, old_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF); else old_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); - if (old_tbf) { + if (old_tbf && (old_tbf->state != GPRS_RLCMAC_FINISHED || + old_tbf->ul_ack_state != GPRS_RLCMAC_UL_ACK_WAIT_ACK)) { #ifdef DEBUG_DL_ASS_IDLE LOGP(DRLCMAC, LOGL_ERROR, "We must wait for current TBF to be " "released.\n"); -- cgit v1.2.3 From f54a89e8813b850f1c92d722db9dc0220c58b70b Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 16 Jul 2012 11:56:11 +0200 Subject: Change polling interval for Packet Downlink Ack/Nack This lowers the risk for stalling of transmit window. --- src/gprs_rlcmac_data.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 8e195b8c..edb91992 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -22,8 +22,11 @@ #include #include -/* After receiving these framess, we send ack/nack. */ -#define ACK_AFTER_FRAMES 20 +/* After receiving these frames, we send ack/nack. */ +#define SEND_ACK_AFTER_FRAMES 20 + +/* After sending these frames, we poll for ack/nack. */ +#define POLL_ACK_AFTER_FRAMES 10 /* If acknowledgement to uplink/downlin assignmentshould be polled */ #define POLLING_ASSIGNMENT 0 @@ -717,9 +720,9 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, /* If TLLI is included or if we received half of the window, we send * an ack/nack */ if (rh->si || rh->ti || tbf->state == GPRS_RLCMAC_FINISHED - || (tbf->dir.ul.rx_counter % ACK_AFTER_FRAMES) == 0) { + || (tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) { if (rh->si) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " + LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, " "because MS is stalled.\n"); } if (rh->ti) { @@ -730,10 +733,10 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " "because last block has CV==0.\n"); } - if ((tbf->dir.ul.rx_counter % ACK_AFTER_FRAMES) == 0) { + if ((tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) { LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " "because %d frames received.\n", - ACK_AFTER_FRAMES); + SEND_ACK_AFTER_FRAMES); } if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) { /* trigger sending at next RTS */ @@ -1092,8 +1095,8 @@ do_resend: "done.\n"); li->e = 1; /* we cannot extend */ rh->fbi = 1; /* we indicate final block */ - tbf->dir.dl.tx_counter = ACK_AFTER_FRAMES + 1; - /* + 1 indicates: force polling */ + tbf->dir.dl.tx_counter = POLL_ACK_AFTER_FRAMES + 1; + /* + 1 indicates: first final ack */ tbf_new_state(tbf, GPRS_RLCMAC_FINISHED); break; } @@ -1121,17 +1124,18 @@ tx_block: /* Clear Polling, if still set in history buffer */ rh->s_p = 0; - /* poll after ACK_AFTER_FRAMES frames, or when final block is tx. */ - if (tbf->dir.dl.tx_counter >= ACK_AFTER_FRAMES) { - if (tbf->dir.dl.tx_counter > ACK_AFTER_FRAMES) { - /* if rx_counter is ACK_AFTER_FRAMES + 1, this + /* poll after POLL_ACK_AFTER_FRAMES frames, or when final block is tx. + */ + if (tbf->dir.dl.tx_counter >= POLL_ACK_AFTER_FRAMES) { + if (tbf->dir.dl.tx_counter > POLL_ACK_AFTER_FRAMES) { + /* if rx_counter is POLL_ACK_AFTER_FRAMES + 1, this * indicates: poll caused by final ack. */ LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " "polling, because final block sent.\n"); } else { LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " "polling, because %d blocks sent.\n", - ACK_AFTER_FRAMES); + POLL_ACK_AFTER_FRAMES); } tbf->dir.dl.tx_counter = 0; /* scheduling not possible, because: */ -- cgit v1.2.3 From 0f13c4014785069022cedeee28cc4d865dcf0668 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 16 Jul 2012 11:59:23 +0200 Subject: Check for downlink sequence is out of range This may happen, if Packer Downlink Assignment was not received by MS, so old TBF with old sequence number is still alive. In this case we free TBF. --- src/gprs_rlcmac_data.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index edb91992..1264cec5 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -131,6 +131,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, int8_t tfi = 0; /* must be signed */ uint32_t tlli = 0; struct gprs_rlcmac_tbf *tbf; + int rc; RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t)); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++\n"); @@ -193,10 +194,14 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet Downlink Ack/Nack\n", tbf->tfi, tbf->tlli); tbf->poll_state = GPRS_RLCMAC_POLL_NONE; - gprs_rlcmac_downlink_ack(tbf, + rc = gprs_rlcmac_downlink_ack(tbf, ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.FINAL_ACK_INDICATION, ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.STARTING_SEQUENCE_NUMBER, ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.RECEIVED_BLOCK_BITMAP); + if (rc == 1) { + tbf_free(tbf); + break; + } /* check for channel request */ if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) { uint8_t trx, ts; @@ -1228,8 +1233,15 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, } } } else { - LOGP(DRLCMACDL, LOGL_DEBUG, "- ack range is out of " - "V(A)..V(S) range\n"); + /* this might happpen, if the downlink assignment + * was not received by ms and the ack refers + * to previous TBF + * FIXME: we should implement polling for + * control ack!*/ + LOGP(DRLCMACDL, LOGL_NOTICE, "- ack range is out of " + "V(A)..V(S) range (DL TBF=%d) Free TFB!\n", + tbf->tfi); + return 1; /* indicate to free TBF */ } /* raise V(A), if possible */ -- cgit v1.2.3 From 4b470ffe07fb9906e68687809c5153102244d2b8 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 16 Jul 2012 12:02:40 +0200 Subject: Changed log levels, to indicate abnormal events --- src/gprs_rlcmac_data.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 1264cec5..10bc0177 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -73,7 +73,7 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) tbf->poll_state = GPRS_RLCMAC_POLL_NONE; if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " "CONTROL ACK for PACKET UPLINK ACK\n"); tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; if (tbf->state == GPRS_RLCMAC_FINISHED) { @@ -81,7 +81,8 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) tbf->dir.ul.n3103++; if (tbf->dir.ul.n3103 == bts->n3103) { - LOGP(DRLCMAC, LOGL_DEBUG, "- N3103 exceeded\n"); + LOGP(DRLCMAC, LOGL_NOTICE, + "- N3103 exceeded\n"); tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); tbf_timer_start(tbf, 3169, bts->t3169, 0); return 0; @@ -91,17 +92,17 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) } } else if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " "CONTROL ACK for PACKET UPLINK ASSIGNMENT.\n"); tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; } else if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " "CONTROL ACK for PACKET DOWNLINK ASSIGNMENT.\n"); tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; /* in case out downlink assigment failed: */ if (tbf->state == GPRS_RLCMAC_ASSIGN) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Assignment failed\n"); + LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment failed\n"); tbf_free(tbf); } } else @@ -109,16 +110,17 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " " DOWNLINK ACK.\n"); tbf->dir.dl.n3105++; if (tbf->dir.dl.n3105 == bts->n3105) { - LOGP(DRLCMAC, LOGL_DEBUG, "- N3105 exceeded\n"); + LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n"); tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); tbf_timer_start(tbf, 3195, bts->t3195, 0); return 0; } - } + } else + LOGP(DRLCMAC, LOGL_ERROR, "- Poll Timeout, but no event!\n"); return 0; } @@ -916,7 +918,7 @@ do_resend: "because all blocks have been transmitted.\n", tbf->dir.dl.v_a); else - LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, " + LOGP(DRLCMACDL, LOGL_NOTICE, "- Restarting at BSN %d, " "because all window is stalled.\n", tbf->dir.dl.v_a); /* If V(S) == V(A) and finished state, we would have received @@ -1207,8 +1209,8 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, } show_rbb[64] = '\0'; LOGP(DRLCMACDL, LOGL_DEBUG, "- ack: (BSN=%d)\"%s\"" - "(BSN=%d) 1=ACK o=NACK\n", ssn - 64, show_rbb, - ssn - 1); + "(BSN=%d) 1=ACK o=NACK\n", (ssn - 64) & mod_sns, + show_rbb, (ssn - 1) & mod_sns); /* apply received array to receive state (SSN-64..SSN-1) */ /* calculate distance of ssn from V(S) */ @@ -1272,12 +1274,11 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, if (tbf->state == GPRS_RLCMAC_FINISHED && tbf->dir.dl.v_s == tbf->dir.dl.v_a) { LOGP(DRLCMACDL, LOGL_NOTICE, "Received final block, " - "bit without final ack inidcation\n"); + "but without final ack inidcation\n"); } else return 0; - } - - LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n"); + } else + LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n"); /* check for LLC PDU in the LLC Queue */ msg = msgb_dequeue(&tbf->llc_queue); -- cgit v1.2.3 From 8389fd0513d05d6b2776627e910d582910ff17ce Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 18 Jul 2012 10:06:48 +0200 Subject: Update to version 3 of PCU socket interface (includes version check) --- src/pcu_l1_if.cpp | 7 +++++++ src/pcuif_proto.h | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index a58a1221..ee0d9bed 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -255,6 +255,13 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) struct gprs_rlcmac_tbf *tbf; int i; + if (info_ind->version != PCU_IF_VERSION) { + fprintf(stderr, "PCU interface version number of BTS (%d) is " + "different (%d).\nPlease re-compile!\n", + info_ind->version, PCU_IF_VERSION); + exit(-1); + } + LOGP(DL1IF, LOGL_DEBUG, "Info indication received:\n"); if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) { diff --git a/src/pcuif_proto.h b/src/pcuif_proto.h index 3609f79d..493f058c 100644 --- a/src/pcuif_proto.h +++ b/src/pcuif_proto.h @@ -1,19 +1,22 @@ #ifndef _PCUIF_PROTO_H #define _PCUIF_PROTO_H +#define PCU_IF_VERSION 0x03 + /* msg_type */ #define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ #define PCU_IF_MSG_DATA_IND 0x02 /* receive data from given channel */ -#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send data to given chan. */ -#define PCU_IF_MSG_RACH_IND 0x22 /* receive rach */ +#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send request */ +#define PCU_IF_MSG_RACH_IND 0x22 /* receive RACH */ #define PCU_IF_MSG_INFO_IND 0x32 /* retrieve BTS info */ #define PCU_IF_MSG_ACT_REQ 0x40 /* activate/deactivate PDCH */ -#define PCU_IF_MSG_TIME_IND 0x52 /* gsm time indication */ +#define PCU_IF_MSG_TIME_IND 0x52 /* GSM time indication */ +#define PCU_IF_MSG_PAG_REQ 0x60 /* paging request */ /* sapi */ #define PCU_IF_SAPI_RACH 0x01 /* channel request on CCCH */ -#define PCU_IF_SAPI_AGCH 0x02 /* assignment on CCCH */ -#define PCU_IF_SAPI_PCH 0x03 /* paging request on CCCH */ +#define PCU_IF_SAPI_AGCH 0x02 /* assignment on AGCH */ +#define PCU_IF_SAPI_PCH 0x03 /* paging/assignment on PCH */ #define PCU_IF_SAPI_BCCH 0x04 /* SI on BCCH */ #define PCU_IF_SAPI_PDTCH 0x05 /* packet data/control/ccch block */ #define PCU_IF_SAPI_PRACH 0x06 /* packet random access channel */ @@ -70,11 +73,14 @@ struct gsm_pcu_if_info_trx { uint8_t pdch_mask; /* PDCH channels per TS */ uint8_t spare; uint8_t tsc[8]; /* TSC per channel */ + uint32_t hlayer1; } __attribute__ ((packed)); struct gsm_pcu_if_info_ind { + uint32_t version; uint32_t flags; struct gsm_pcu_if_info_trx trx[8]; /* TRX infos per BTS */ + uint8_t bsic; /* RAI */ uint16_t mcc, mnc, lac, rac; /* NSE */ @@ -117,6 +123,12 @@ struct gsm_pcu_if_time_ind { uint32_t fn; } __attribute__ ((packed)); +struct gsm_pcu_if_pag_req { + uint8_t sapi; + uint8_t chan_needed; + uint8_t identity_lv[9]; +} __attribute__ ((packed)); + struct gsm_pcu_if { /* context based information */ uint8_t msg_type; /* message type */ @@ -131,6 +143,7 @@ struct gsm_pcu_if { struct gsm_pcu_if_info_ind info_ind; struct gsm_pcu_if_act_req act_req; struct gsm_pcu_if_time_ind time_ind; + struct gsm_pcu_if_pag_req pag_req; } u; } __attribute__ ((packed)); -- cgit v1.2.3 From 2b91464862270d72800b6dcc5a521f933fbbd489 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 19 Jul 2012 13:06:26 +0200 Subject: Added paging for RR connection on PACCH of active TBFs Untested --- src/gprs_rlcmac.cpp | 209 ++++++++++++++++++++++++++++++++++++++++++++++ src/gprs_rlcmac.h | 23 +++++ src/gprs_rlcmac_sched.cpp | 4 + src/pcu_l1_if.cpp | 73 ++++++++++------ 4 files changed, 282 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 7273362c..27cc908a 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -73,6 +73,11 @@ struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = { LLIST_HEAD(gprs_rlcmac_ul_tbfs); LLIST_HEAD(gprs_rlcmac_dl_tbfs); +llist_head *gprs_rlcmac_tbfs_lists[] = { + &gprs_rlcmac_ul_tbfs, + &gprs_rlcmac_dl_tbfs, + NULL +}; void *rlcmac_tall_ctx; /* FIXME: spread ressources over multiple TRX. Also add option to use same @@ -950,6 +955,172 @@ int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len, return rc; } +/* add paging to paging queue(s) */ +int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + uint8_t l, trx, ts, any_tbf = 0; + struct gprs_rlcmac_tbf *tbf; + struct gprs_rlcmac_paging *pag; + uint8_t slot_mask[8]; + int8_t first_ts; /* must be signed */ + + LOGP(DRLCMAC, LOGL_INFO, "Add CS paging\n"); + + /* collect slots to page + * Mark slots for every TBF, but only mark one of it. + * Mark only the first slot found. + * Don't mark, if TBF uses a different slot that is already marked. */ + memset(slot_mask, 0, sizeof(slot_mask)); + for (l = 0; gprs_rlcmac_tbfs_lists[l]; l++) { + llist_for_each_entry(tbf, gprs_rlcmac_tbfs_lists[l], list) { + first_ts = -1; + for (ts = 0; ts < 8; ts++) { + if (tbf->pdch[ts]) { + /* remember the first slot found */ + if (first_ts < 0) + first_ts = ts; + /* break, if we already marked a slot */ + if ((slot_mask[tbf->trx] & (1 << ts))) + break; + } + } + /* mark first slot found, if none is marked already */ + if (ts == 8 && first_ts >= 0) { + LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses " + "TRX=%d TS=%d, so we mark\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", + tbf->tfi, tbf->trx, ts); + slot_mask[tbf->trx] |= (1 << first_ts); + } else + LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses " + "already marked TRX=%d TS=%d\n", + (tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", + tbf->tfi, tbf->trx, ts); + } + } + + /* Now we have a list of marked slots. Every TBF uses at least one + * of these slots. */ + + /* schedule paging to all marked slots */ + for (trx = 0; trx < 8; trx++) { + if (slot_mask[trx] == 0) + continue; + any_tbf = 1; + for (ts = 0; ts < 8; ts++) { + if ((slot_mask[trx] & (1 << ts))) { + /* schedule */ + pag = talloc_zero(rlcmac_tall_ctx, + struct gprs_rlcmac_paging); + if (!pag) + return -ENOMEM; + pag->chan_needed = chan_needed; + memcpy(pag->identity_lv, identity_lv, + identity_lv[0] + 1); + llist_add(&pag->list, + &bts->trx[trx].pdch[ts].paging_list); + LOGP(DRLCMAC, LOGL_INFO, "Paging on TRX=%d" + "TS=%d\n", trx, ts); + } + } + } + + if (!any_tbf) { + LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n"); + } + + return 0; +} + +struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging( + struct gprs_rlcmac_pdch *pdch) +{ + struct gprs_rlcmac_paging *pag; + + pag = llist_entry(pdch->paging_list.next, + struct gprs_rlcmac_paging, list); + llist_del(&pag->list); + + return pag; +} + +struct msgb *gprs_rlcmac_send_packet_paging_request( + struct gprs_rlcmac_pdch *pdch) +{ + struct gprs_rlcmac_paging *pag; + struct msgb *msg; + unsigned wp = 0, len; + + /* no paging, no message */ + pag = gprs_rlcmac_dequeue_paging(pdch); + if (!pag) + return NULL; + + LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n"); + + /* alloc message */ + msg = msgb_alloc(23, "pag ctrl block"); + if (!msg) + return NULL; + bitvec *pag_vec = bitvec_alloc(23); + if (!pag_vec) { + msgb_free(msg); + return NULL; + } + wp = write_packet_paging_request(pag_vec); + + /* loop until message is full */ + while (pag) { + /* try to add paging */ + if ((pag->identity_lv[1] & 0x07) == 4) { + /* TMSI */ + LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n", + ntohl(*((uint32_t *)(pag->identity_lv + 1)))); + len = 1 + 1 + 32 + 2 + 1; + if (pag->identity_lv[0] != 5) { + LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with " + "MI != 5 octets!\n"); + break; + } + } else { + /* MI */ + LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n", + osmo_hexdump(pag->identity_lv + 1, + pag->identity_lv[0])); + len = 1 + 1 + 4 + (pag->identity_lv[0] << 3) + 2 + 1; + if (pag->identity_lv[0] > 8) { + LOGP(DRLCMAC, LOGL_ERROR, "Paging with " + "MI > 8 octets!\n"); + break; + } + } + if (wp + len > 184) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule " + "next time\n"); + /* put back paging record, because does not fit */ + llist_add_tail(&pag->list, &pdch->paging_list); + break; + } + write_repeated_page_info(pag_vec, wp, pag->identity_lv[0], + pag->identity_lv + 1, pag->chan_needed); + + pag = gprs_rlcmac_dequeue_paging(pdch); + } + + bitvec_pack(pag_vec, msgb_put(msg, 23)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n"); + decode_gsm_rlcmac_downlink(pag_vec, mac_control_block); + LOGPC(DCSN1, LOGL_NOTICE, "\n"); + LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n"); + bitvec_free(pag_vec); + + return msg; +} + // GSM 04.08 9.1.18 Immediate assignment int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, @@ -1248,6 +1419,44 @@ void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *t block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.Exist_Power_Control_Parameters = 0x0; } +unsigned write_packet_paging_request(bitvec * dest) +{ + unsigned wp = 0; + + bitvec_write_field(dest, wp,0x1,2); // Payload Type + bitvec_write_field(dest, wp,0x0,3); // No polling + bitvec_write_field(dest, wp,0x0,3); // Uplink state flag + bitvec_write_field(dest, wp,0x22,6); // MESSAGE TYPE + + bitvec_write_field(dest, wp,0x0,1); // No PERSISTENCE_LEVEL + bitvec_write_field(dest, wp,0x0,1); // No NLN + + return wp; +} + +unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len, + uint8_t *identity, uint8_t chan_needed) +{ + bitvec_write_field(dest, wp,0x1,1); // RR connection paging + + if ((identity[0] & 0x07) == 4) { + bitvec_write_field(dest, wp,0x0,1); // TMSI + identity++; + len--; + } else { + bitvec_write_field(dest, wp,0x0,1); // MI + bitvec_write_field(dest, wp,len,4); // MI len + } + while (len) { + bitvec_write_field(dest, wp,*identity++,8); // MI data + len--; + } + bitvec_write_field(dest, wp,chan_needed,2); // CHANNEL_NEEDED + bitvec_write_field(dest, wp,0x0,1); // No eMLPP_PRIORITY + + return wp; +} + /* Send Uplink unit-data to SGSN. */ int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf) { diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index ae188f13..ce278796 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -48,6 +48,7 @@ struct gprs_rlcmac_pdch { uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */ struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */ struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */ + struct llist_head paging_list; /* list of paging messages */ uint32_t last_rts_fn; /* store last frame number of RTS */ }; @@ -199,6 +200,15 @@ struct gprs_rlcmac_tbf { extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */ extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */ +/* + * paging entry + */ +struct gprs_rlcmac_paging { + struct llist_head list; + uint8_t chan_needed; + uint8_t identity_lv[9]; +}; + int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, uint8_t use_trx, uint8_t first_ts); @@ -285,6 +295,11 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, uint8_t ssn, uint8_t *rbb); +unsigned write_packet_paging_request(bitvec * dest); + +unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len, + uint8_t *identity, uint8_t chan_needed); + int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len); @@ -297,4 +312,12 @@ 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_add_paging(uint8_t chan_needed, uint8_t *identity_lv); + +struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging( + struct gprs_rlcmac_pdch *pdch); + +struct msgb *gprs_rlcmac_send_packet_paging_request( + struct gprs_rlcmac_pdch *pdch); + #endif // GPRS_RLCMAC_H diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index cd995166..661dfbc1 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -143,6 +143,10 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, tbf = ul_ack_tbf; msg = gprs_rlcmac_send_uplink_ack(tbf, fn); } + /* schedule PACKET PAGING REQUEST */ + if (!msg && !llist_empty(&pdch->paging_list)) { + msg = gprs_rlcmac_send_packet_paging_request(pdch); + } if (msg) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " "message at RTS for %s TBF=%d (TRX=%d, TS=%d)\n", diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index ee0d9bed..615d8944 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -247,12 +247,34 @@ static int pcu_rx_rach_ind(struct gsm_pcu_if_rach_ind *rach_ind) return rc; } +int flush_pdch(struct gprs_rlcmac_pdch *pdch) +{ + uint8_t tfi; + struct gprs_rlcmac_tbf *tbf; + struct gprs_rlcmac_paging *pag; + + /* kick all TBF on slot */ + for (tfi = 0; tfi < 32; tfi++) { + tbf = pdch->ul_tbf[tfi]; + if (tbf) + tbf_free(tbf); + tbf = pdch->dl_tbf[tfi]; + if (tbf) + tbf_free(tbf); + } + /* flush all pending paging messages */ + while ((pag = gprs_rlcmac_dequeue_paging(pdch))) + talloc_free(pag); + + return 0; +} + static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_pdch *pdch; int rc = 0; - int trx, ts, tfi; - struct gprs_rlcmac_tbf *tbf; + int trx, ts; int i; if (info_ind->version != PCU_IF_VERSION) { @@ -270,16 +292,8 @@ bssgp_failed: /* free all TBF */ for (trx = 0; trx < 8; trx++) { bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; - for (ts = 0; ts < 8; ts++) { - for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; - if (tbf) - tbf_free(tbf); - tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; - if (tbf) - tbf_free(tbf); - } - } + for (ts = 0; ts < 8; ts++) + flush_pdch(&bts->trx[trx].pdch[ts]); } gprs_bssgp_destroy(); return 0; @@ -366,28 +380,21 @@ bssgp_failed: for (trx = 0; trx < 8; trx++) { bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; for (ts = 0; ts < 8; ts++) { + pdch = &bts->trx[trx].pdch[ts]; if ((info_ind->trx[trx].pdch_mask & (1 << ts))) { /* FIXME: activate dynamically at RLCMAC */ - if (!bts->trx[trx].pdch[ts].enable) + if (!pdch->enable) pcu_tx_act_req(trx, ts, 1); - bts->trx[trx].pdch[ts].enable = 1; - bts->trx[trx].pdch[ts].tsc = - info_ind->trx[trx].tsc[ts]; + pdch->enable = 1; + pdch->tsc = info_ind->trx[trx].tsc[ts]; + INIT_LLIST_HEAD(&pdch->paging_list); LOGP(DL1IF, LOGL_INFO, "PDCH: trx=%d ts=%d\n", trx, ts); } else { - if (bts->trx[trx].pdch[ts].enable) + if (pdch->enable) pcu_tx_act_req(trx, ts, 0); - bts->trx[trx].pdch[ts].enable = 0; - /* kick all TBF on slot */ - for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; - if (tbf) - tbf_free(tbf); - tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; - if (tbf) - tbf_free(tbf); - } + pdch->enable = 0; + flush_pdch(pdch); } } } @@ -429,6 +436,15 @@ static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind) return 0; } +static int pcu_rx_pag_req(struct gsm_pcu_if_pag_req *pag_req) +{ + LOGP(DL1IF, LOGL_DEBUG, "Paging request received: chan_needed=%d " + "length=%d\n", pag_req->chan_needed, pag_req->identity_lv[0]); + + return gprs_rlcmac_add_paging(pag_req->chan_needed, + pag_req->identity_lv); +} + int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) { int rc = 0; @@ -449,6 +465,9 @@ int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) case PCU_IF_MSG_TIME_IND: rc = pcu_rx_time_ind(&pcu_prim->u.time_ind); break; + case PCU_IF_MSG_PAG_REQ: + rc = pcu_rx_pag_req(&pcu_prim->u.pag_req); + break; default: LOGP(DL1IF, LOGL_ERROR, "Received unknwon PCU msg type %d\n", msg_type); -- cgit v1.2.3 From 3b7461c1b39f424d41f30613560abd8a6fda375e Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 20 Jul 2012 11:19:59 +0200 Subject: Fixed Paging RR on PACCH Addition to 2b91464862270d72800b6dcc5a521f933fbbd489 --- src/gprs_rlcmac.cpp | 22 ++++++++++++++-------- src/gprs_rlcmac_sched.cpp | 12 ++++++++---- src/pcu_l1_if.cpp | 20 ++++++++++++-------- 3 files changed, 34 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 27cc908a..d1f0b549 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -965,7 +965,8 @@ int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv) uint8_t slot_mask[8]; int8_t first_ts; /* must be signed */ - LOGP(DRLCMAC, LOGL_INFO, "Add CS paging\n"); + LOGP(DRLCMAC, LOGL_INFO, "Add RR paging: chan-needed=%d MI=%s\n", + chan_needed, osmo_hexdump(identity_lv + 1, identity_lv[0])); /* collect slots to page * Mark slots for every TBF, but only mark one of it. @@ -991,7 +992,7 @@ int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv) "TRX=%d TS=%d, so we mark\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", - tbf->tfi, tbf->trx, ts); + tbf->tfi, tbf->trx, first_ts); slot_mask[tbf->trx] |= (1 << first_ts); } else LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses " @@ -1022,15 +1023,14 @@ int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv) identity_lv[0] + 1); llist_add(&pag->list, &bts->trx[trx].pdch[ts].paging_list); - LOGP(DRLCMAC, LOGL_INFO, "Paging on TRX=%d" - "TS=%d\n", trx, ts); + LOGP(DRLCMAC, LOGL_INFO, "Paging on PACCH of " + "TRX=%d TS=%d\n", trx, ts); } } } - if (!any_tbf) { + if (!any_tbf) LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n"); - } return 0; } @@ -1040,6 +1040,8 @@ struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging( { struct gprs_rlcmac_paging *pag; + if (llist_empty(&pdch->paging_list)) + return NULL; pag = llist_entry(pdch->paging_list.next, struct gprs_rlcmac_paging, list); llist_del(&pag->list); @@ -1079,7 +1081,7 @@ struct msgb *gprs_rlcmac_send_packet_paging_request( /* TMSI */ LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n", ntohl(*((uint32_t *)(pag->identity_lv + 1)))); - len = 1 + 1 + 32 + 2 + 1; + len = 1 + 1 + 1 + 32 + 2 + 1; if (pag->identity_lv[0] != 5) { LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with " "MI != 5 octets!\n"); @@ -1090,7 +1092,7 @@ struct msgb *gprs_rlcmac_send_packet_paging_request( LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n", osmo_hexdump(pag->identity_lv + 1, pag->identity_lv[0])); - len = 1 + 1 + 4 + (pag->identity_lv[0] << 3) + 2 + 1; + len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1; if (pag->identity_lv[0] > 8) { LOGP(DRLCMAC, LOGL_ERROR, "Paging with " "MI > 8 octets!\n"); @@ -1428,6 +1430,8 @@ unsigned write_packet_paging_request(bitvec * dest) bitvec_write_field(dest, wp,0x0,3); // Uplink state flag bitvec_write_field(dest, wp,0x22,6); // MESSAGE TYPE + bitvec_write_field(dest, wp,0x0,2); // Page Mode + bitvec_write_field(dest, wp,0x0,1); // No PERSISTENCE_LEVEL bitvec_write_field(dest, wp,0x0,1); // No NLN @@ -1437,6 +1441,8 @@ unsigned write_packet_paging_request(bitvec * dest) unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len, uint8_t *identity, uint8_t chan_needed) { + bitvec_write_field(dest, wp,0x1,1); // Repeated Page info exists + bitvec_write_field(dest, wp,0x1,1); // RR connection paging if ((identity[0] & 0x07) == 4) { diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index 661dfbc1..f6af9b71 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -143,16 +143,20 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, tbf = ul_ack_tbf; msg = gprs_rlcmac_send_uplink_ack(tbf, fn); } - /* schedule PACKET PAGING REQUEST */ - if (!msg && !llist_empty(&pdch->paging_list)) { - msg = gprs_rlcmac_send_packet_paging_request(pdch); - } if (msg) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " "message at RTS for %s TBF=%d (TRX=%d, TS=%d)\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, trx, ts); } + /* schedule PACKET PAGING REQUEST */ + if (!msg && !llist_empty(&pdch->paging_list)) { + msg = gprs_rlcmac_send_packet_paging_request(pdch); + if (msg) + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging " + "request message at RTS for (TRX=%d, TS=%d)\n", + trx, ts); + } /* Prio 2: select data message for downlink */ if (!msg) { diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 615d8944..00030d66 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -292,8 +292,10 @@ bssgp_failed: /* free all TBF */ for (trx = 0; trx < 8; trx++) { bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; - for (ts = 0; ts < 8; ts++) - flush_pdch(&bts->trx[trx].pdch[ts]); + for (ts = 0; ts < 8; ts++) { + if (bts->trx[trx].pdch[ts].enable) + flush_pdch(&bts->trx[trx].pdch[ts]); + } } gprs_bssgp_destroy(); return 0; @@ -383,18 +385,20 @@ bssgp_failed: pdch = &bts->trx[trx].pdch[ts]; if ((info_ind->trx[trx].pdch_mask & (1 << ts))) { /* FIXME: activate dynamically at RLCMAC */ - if (!pdch->enable) + if (!pdch->enable) { pcu_tx_act_req(trx, ts, 1); - pdch->enable = 1; + INIT_LLIST_HEAD(&pdch->paging_list); + pdch->enable = 1; + } pdch->tsc = info_ind->trx[trx].tsc[ts]; - INIT_LLIST_HEAD(&pdch->paging_list); LOGP(DL1IF, LOGL_INFO, "PDCH: trx=%d ts=%d\n", trx, ts); } else { - if (pdch->enable) + if (pdch->enable) { pcu_tx_act_req(trx, ts, 0); - pdch->enable = 0; - flush_pdch(pdch); + pdch->enable = 0; + flush_pdch(pdch); + } } } } -- cgit v1.2.3 From 8b761a34190656884409bd61d0b0483ed0f14898 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 20 Jul 2012 21:50:31 +0200 Subject: VTY: Added option to force given CS and ignore the scheme given by BTS --- src/gprs_rlcmac.h | 7 ++++- src/pcu_l1_if.cpp | 10 ++++--- src/pcu_vty.c | 87 ++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 79 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index ce278796..42439e2e 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -20,6 +20,7 @@ #ifndef GPRS_RLCMAC_H #define GPRS_RLCMAC_H +#ifdef __cplusplus #include #include #include @@ -28,6 +29,7 @@ extern "C" { #include #include } +#endif /* This special feature will delay assignment of downlink TBF by one second, * in case there is already a TBF. @@ -63,6 +65,7 @@ struct gprs_rlcmac_bts { uint8_t cs3; uint8_t cs4; uint8_t initial_cs; + uint8_t force_cs; /* 0=use from BTS 1=use from VTY */ uint8_t t3142; uint8_t t3169; uint8_t t3191; @@ -79,6 +82,7 @@ struct gprs_rlcmac_bts { extern struct gprs_rlcmac_bts *gprs_rlcmac_bts; +#ifdef __cplusplus /* * TBF instance */ @@ -149,7 +153,7 @@ struct gprs_rlcmac_tbf { uint8_t llc_frame[LLC_MAX_LEN]; /* current DL or UL frame */ uint16_t llc_index; /* current write/read position of frame */ uint16_t llc_length; /* len of current DL LLC_frame, 0 == no frame */ - llist_head llc_queue; /* queued LLC DL data */ + struct llist_head llc_queue; /* queued LLC DL data */ enum gprs_rlcmac_tbf_dl_ass_state dl_ass_state; enum gprs_rlcmac_tbf_ul_ass_state ul_ass_state; @@ -319,5 +323,6 @@ struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging( struct msgb *gprs_rlcmac_send_packet_paging_request( struct gprs_rlcmac_pdch *pdch); +#endif #endif // GPRS_RLCMAC_H diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 00030d66..e5fbad98 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -374,10 +374,12 @@ bssgp_failed: bts->n3103 = info_ind->n3103; bts->n3105 = info_ind->n3105; } - if (info_ind->initial_cs < 1 || info_ind->initial_cs > 4) - bts->initial_cs = 1; - else - bts->initial_cs = info_ind->initial_cs; + if (!bts->force_cs) { + if (info_ind->initial_cs < 1 || info_ind->initial_cs > 4) + bts->initial_cs = 1; + else + bts->initial_cs = info_ind->initial_cs; + } for (trx = 0; trx < 8; trx++) { bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 7e8af43b..179080bb 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -1,27 +1,18 @@ /* OsmoBTS VTY interface */ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - +#include +#include +#include #include "pcu_vty.h" - +#include "gprs_rlcmac.h" enum node_type pcu_vty_go_parent(struct vty *vty) { switch (vty->node) { #if 0 case TRX_NODE: - vty->node = BTS_NODE; + vty->node = PCU_NODE; { struct gsm_bts_trx *trx = vty->index; vty->index = trx->bts; @@ -31,29 +22,32 @@ enum node_type pcu_vty_go_parent(struct vty *vty) default: vty->node = CONFIG_NODE; } - return vty->node; + return (enum node_type) vty->node; } int pcu_vty_is_config_node(struct vty *vty, int node) { switch (node) { -#if 0 - case TRX_NODE: - case BTS_NODE: + case PCU_NODE: return 1; -#endif default: return 0; } } +static struct cmd_node pcu_node = { + (enum node_type) PCU_NODE, + "%s(pcu)#", + 1, +}; + gDEFUN(ournode_exit, ournode_exit_cmd, "exit", "Exit current node, go down to provious node") { switch (vty->node) { #if 0 case TRXV_NODE: - vty->node = BTS_NODE; + vty->node = PCU_NODE; { struct gsm_bts_trx *trx = vty->index; vty->index = trx->bts; @@ -80,6 +74,52 @@ gDEFUN(ournode_end, ournode_end_cmd, "end", return CMD_SUCCESS; } +static int config_write_pcu(struct vty *vty) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + vty_out(vty, "pcu%s", VTY_NEWLINE); + if (bts->force_cs) + vty_out(vty, " cs %d%s", bts->initial_cs, VTY_NEWLINE); +} + +/* per-BTS configuration */ +DEFUN(cfg_pcu, + cfg_pcu_cmd, + "pcu", + "BTS specific configure") +{ + vty->node = PCU_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_cs, + cfg_pcu_cs_cmd, + "cs <1-4>", + "Set the Coding Scheme to be used, (overrides BTS config)\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + uint8_t cs = atoi(argv[0]); + + bts->force_cs = 1; + bts->initial_cs = cs; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_no_cs, + cfg_pcu_no_cs_cmd, + "no cs", + NO_STR "Don't force given Coding Scheme, (use BTS config)\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->force_cs = 0; + + return CMD_SUCCESS; +} + static const char pcu_copyright[] = "Copyright (C) 2012 by ...\r\n" "License GNU GPL version 2 or later\r\n" @@ -100,5 +140,12 @@ int pcu_vty_init(const struct log_info *cat) logging_vty_add_cmds(cat); + install_node(&pcu_node, config_write_pcu); + install_element(CONFIG_NODE, &cfg_pcu_cmd); + install_default(PCU_NODE); + install_element(PCU_NODE, &cfg_pcu_cs_cmd); + install_element(PCU_NODE, &cfg_pcu_no_cs_cmd); + install_element(PCU_NODE, &ournode_end_cmd); + return 0; } -- cgit v1.2.3 From 24131bf55bc010e8238b7b1bb2b761dae4137dee Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 21 Jul 2012 11:09:58 +0200 Subject: Add check of lifetime of LLC frame If lifetime expires of queued LLC frames, they are discarded. The number of discarded frames and the sum of their octets are reported to SGSN via LLC-DISCARDED message. The lifetime can be overridden via VTY. The value can be centi-seconds or "infinite". --- src/gprs_bssgp_pcu.cpp | 37 +++++++++++++++++++++++++++++++++-- src/gprs_rlcmac.h | 1 + src/gprs_rlcmac_data.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++-- src/pcu_vty.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 945addce..217acdb9 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -111,6 +111,21 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) bitvec_read_field(block, rp, 4); // SMS Value } } + /* get lifetime */ + uint16_t delay_csec = 0xffff; + if (TLVP_PRESENT(tp, BSSGP_IE_PDU_LIFETIME)) + { + uint8_t lt_len = TLVP_LEN(tp, BSSGP_IE_PDU_LIFETIME); + uint16_t *lt = (uint16_t *) TLVP_VAL(tp, BSSGP_IE_PDU_LIFETIME); + if (lt_len == 2) + delay_csec = ntohs(*lt); + else + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP invalid length of " + "PDU_LIFETIME IE\n"); + } else + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP missing mandatory " + "PDU_LIFETIME IE\n"); + LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len); /* check for existing TBF */ @@ -128,10 +143,28 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) tbf_update(tbf); gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL); } else { - /* the TBF exists, so we must write it in the queue */ - struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue"); + /* the TBF exists, so we must write it in the queue + * we prepend lifetime in front of PDU */ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + 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 (bts->force_llc_lifetime) + delay_csec = 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 */ diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 42439e2e..71ff6086 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -66,6 +66,7 @@ struct gprs_rlcmac_bts { uint8_t cs4; uint8_t initial_cs; uint8_t force_cs; /* 0=use from BTS 1=use from VTY */ + uint16_t force_llc_lifetime; /* overrides lifetime from SGSN */ uint8_t t3142; uint8_t t3169; uint8_t t3191; diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 10bc0177..2f67bd0a 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -22,6 +22,11 @@ #include #include +extern "C" { +int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli, + uint8_t num_frames, uint32_t num_octets); +} + /* After receiving these frames, we send ack/nack. */ #define SEND_ACK_AFTER_FRAMES 20 @@ -868,6 +873,44 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) * DL data block flow */ +static struct msgb *llc_dequeue(struct gprs_rlcmac_tbf *tbf) +{ + struct msgb *msg; + struct timeval *tv, tv_now; + uint32_t octets = 0, frames = 0; + + gettimeofday(&tv_now, NULL); + + while ((msg = msgb_dequeue(&tbf->llc_queue))) { + tv = (struct timeval *)msg->data; + msgb_pull(msg, sizeof(*tv)); + if (tv->tv_sec /* not infinite */ + && (tv_now.tv_sec > tv->tv_sec /* and secs expired */ + || (tv_now.tv_sec == tv->tv_sec /* .. or if secs equal .. */ + && tv_now.tv_usec > tv->tv_usec))) { /* .. usecs expired */ + LOGP(DRLCMACDL, LOGL_NOTICE, "Discarding LLC PDU of " + "DL TBF=%d, because lifetime limit reached\n", + tbf->tfi); + frames++; + octets += msg->len; + msgb_free(msg); + continue; + } + break; + } + + if (frames) { + if (frames > 0xff) + frames = 0xff; + if (octets > 0xffffff) + octets = 0xffffff; + bssgp_tx_llc_discarded(bctx, tbf->tlli, frames, octets); + } + + return msg; +} + + /* send DL data block * * The messages are fragmented and forwarded as data blocks. @@ -1083,7 +1126,7 @@ do_resend: /* reset LLC frame */ tbf->llc_index = tbf->llc_length = 0; /* dequeue next LLC frame, if any */ - msg = msgb_dequeue(&tbf->llc_queue); + msg = llc_dequeue(tbf); if (msg) { LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC for " "TBF=%d (len=%d)\n", tbf->tfi, msg->len); @@ -1281,7 +1324,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n"); /* check for LLC PDU in the LLC Queue */ - msg = msgb_dequeue(&tbf->llc_queue); + msg = llc_dequeue(tbf); if (!msg) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 179080bb..2413f21d 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -81,6 +81,11 @@ static int config_write_pcu(struct vty *vty) vty_out(vty, "pcu%s", VTY_NEWLINE); if (bts->force_cs) vty_out(vty, " cs %d%s", bts->initial_cs, VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) + vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); + else if (bts->force_llc_lifetime) + vty_out(vty, " queue lifetime %d%s", bts->force_llc_lifetime, + VTY_NEWLINE); } /* per-BTS configuration */ @@ -120,6 +125,48 @@ DEFUN(cfg_pcu_no_cs, return CMD_SUCCESS; } +#define QUEUE_STR "Packet queue options\n" +#define LIFETIME_STR "Set lifetime limit of LLC frame in centi-seconds " \ + "(overrides the value given by SGSN)\n" + +DEFUN(cfg_pcu_queue_lifetime, + cfg_pcu_queue_lifetime_cmd, + "queue lifetime <1-65534>", + QUEUE_STR LIFETIME_STR "Lifetime in centi-seconds") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + uint8_t csec = atoi(argv[0]); + + bts->force_llc_lifetime = csec; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_queue_lifetime_inf, + cfg_pcu_queue_lifetime_inf_cmd, + "queue lifetime infinite", + QUEUE_STR LIFETIME_STR "Infinite lifetime") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->force_llc_lifetime = 0xffff; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_no_queue_lifetime, + cfg_pcu_no_queue_lifetime_cmd, + "no queue lifetime", + NO_STR QUEUE_STR "Disable lifetime limit of LLC frame (use value given " + "by SGSN)\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->force_llc_lifetime = 0; + + return CMD_SUCCESS; +} + static const char pcu_copyright[] = "Copyright (C) 2012 by ...\r\n" "License GNU GPL version 2 or later\r\n" @@ -145,6 +192,9 @@ int pcu_vty_init(const struct log_info *cat) install_default(PCU_NODE); install_element(PCU_NODE, &cfg_pcu_cs_cmd); install_element(PCU_NODE, &cfg_pcu_no_cs_cmd); + install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd); + install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd); + install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd); install_element(PCU_NODE, &ournode_end_cmd); return 0; -- cgit v1.2.3 From 3022a70eb11d992adbfbc8811b79a0530cfb6920 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 Jul 2012 22:58:22 +0200 Subject: Makefile.am: rename executable name from pcu to osmo-pcu This makes more sense since the entire repository is called this way --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 041831fa..215476a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,7 @@ endif noinst_PROGRAMS = \ RLCMACTest \ - pcu + osmo-pcu noinst_HEADERS = \ gprs_debug.h \ @@ -66,8 +66,8 @@ RLCMACTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) -pcu_SOURCES = pcu_main.cpp -pcu_LDADD = \ +osmo_pcu_SOURCES = pcu_main.cpp +osmo_pcu_LDADD = \ libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOCORE_LIBS) \ -- cgit v1.2.3 From da62859231cbe25ff7772e3d2389e15e5f8b4d8a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 Jul 2012 22:59:08 +0200 Subject: Makefile.am: Actually install the pcu during 'make install' --- src/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 215476a0..3a68927a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,7 +45,9 @@ libgprs_la_SOURCES += \ endif noinst_PROGRAMS = \ - RLCMACTest \ + RLCMACTest + +bin_PROGRAMS = \ osmo-pcu noinst_HEADERS = \ -- cgit v1.2.3 From a1503fa3567e2837d809cd77b857bd617448f2fd Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 22 Jul 2012 08:58:09 +0200 Subject: VTY: Select timeslot allocation algorithm via VTY The selections are: single slot or multislot --- src/gprs_rlcmac.h | 16 ++++++++++------ src/pcu_vty.c | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 71ff6086..55aef9d7 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -221,12 +221,6 @@ struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t ms_class, uint8_t single_slot); -int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, - struct gprs_rlcmac_tbf *tbf, uint32_t cust); - -int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, - struct gprs_rlcmac_tbf *tbf, uint32_t cust); - struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, enum gprs_rlcmac_tbf_direction dir); @@ -324,6 +318,16 @@ struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging( struct msgb *gprs_rlcmac_send_packet_paging_request( struct gprs_rlcmac_pdch *pdch); + +extern "C" { +#endif +int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust); + +int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, + struct gprs_rlcmac_tbf *tbf, uint32_t cust); +#ifdef __cplusplus +} #endif #endif // GPRS_RLCMAC_H diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 2413f21d..e5d37658 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -86,6 +86,11 @@ static int config_write_pcu(struct vty *vty) else if (bts->force_llc_lifetime) vty_out(vty, " queue lifetime %d%s", bts->force_llc_lifetime, VTY_NEWLINE); + if (bts->alloc_algorithm == alloc_algorithm_a) + vty_out(vty, " alloc-algorithm a%s", VTY_NEWLINE); + if (bts->alloc_algorithm == alloc_algorithm_b) + vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE); + } /* per-BTS configuration */ @@ -167,6 +172,27 @@ DEFUN(cfg_pcu_no_queue_lifetime, return CMD_SUCCESS; } +DEFUN(cfg_pcu_alloc, + cfg_pcu_alloc_cmd, + "alloc-algorithm (a|b)", + "Select slot allocation algorithm to use when assigning timeslots on " + "PACCH\nSingle slot is assigned only\nMultiple slots are assigned for " + "semi-duplex operation") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + switch (argv[0][0]) { + case 'a': + bts->alloc_algorithm = alloc_algorithm_a; + break; + case 'b': + bts->alloc_algorithm = alloc_algorithm_b; + break; + } + + return CMD_SUCCESS; +} + static const char pcu_copyright[] = "Copyright (C) 2012 by ...\r\n" "License GNU GPL version 2 or later\r\n" @@ -195,6 +221,7 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd); install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd); install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd); + install_element(PCU_NODE, &cfg_pcu_alloc_cmd); install_element(PCU_NODE, &ournode_end_cmd); return 0; -- cgit v1.2.3 From 642c7d3f5b3a199cf69b88d21056cbfffd748595 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 23 Jul 2012 17:58:55 +0200 Subject: Fix: We don't use timer to define when assignment is complete on PACCH Instead we use the event of sending assignment message. Then we set the TBF state to 'FLOW'. --- src/gprs_rlcmac.h | 3 +-- src/gprs_rlcmac_data.cpp | 28 +++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 55aef9d7..8a8351d6 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -93,8 +93,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,500000/* wait for assignment, before transmitting DL */ -#define Tassign_pacch 0,100000/* wait for assignment, before transmitting DL */ +#define Tassign_agch 0,800000/* FIXME: we need a confirm from BTS */ enum gprs_rlcmac_tbf_state { GPRS_RLCMAC_NULL = 0, /* new created TBF */ diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 2f67bd0a..4109161d 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -174,11 +174,31 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] DOWNLINK ASSIGNED TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; + if (tbf->direction == GPRS_RLCMAC_UL_TBF) + tbf = tbf_by_tlli(tbf->tlli, + GPRS_RLCMAC_DL_TBF); + if (!tbf) { + LOGP(DRLCMAC, LOGL_ERROR, "Got ACK, but DL " + "TBF is gone\n"); + break; + } + tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + tbf_assign_control_ts(tbf); break; } if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] UPLINK ASSIGNED TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; + if (tbf->direction == GPRS_RLCMAC_DL_TBF) + tbf = tbf_by_tlli(tbf->tlli, + GPRS_RLCMAC_UL_TBF); + if (!tbf) { + LOGP(DRLCMAC, LOGL_ERROR, "Got ACK, but UL " + "TBF is gone\n"); + break; + } + tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + tbf_assign_control_ts(tbf); break; } LOGP(DRLCMAC, LOGL_ERROR, "Error: received PACET CONTROL ACK " @@ -236,7 +256,7 @@ uplink_request: ul_tbf->tlli_valid = 1; /* no contention resolution */ ul_tbf->contention_resolution_done = 1; ul_tbf->ta = tbf->ta; /* use current TA */ - tbf_new_state(ul_tbf, GPRS_RLCMAC_FLOW); + tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN); tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); /* schedule uplink assignment */ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; @@ -821,6 +841,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; #else tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; + tbf_new_state(new_tbf, GPRS_RLCMAC_FLOW); + tbf_assign_control_ts(new_tbf); #endif return msg; @@ -1420,6 +1442,8 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; #else tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; + tbf_new_state(new_tbf, GPRS_RLCMAC_FLOW); + tbf_assign_control_ts(new_tbf); #endif return msg; @@ -1474,8 +1498,6 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, tbf->ta = old_tbf->ta; /* change state */ tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); - /* start timer */ - tbf_timer_start(tbf, 0, Tassign_pacch); #endif } else { LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment for TBF=%d on PCH, no TBF exist (IMSI=%s)\n", tbf->tfi, imsi); -- cgit v1.2.3 From 7438df7d705fe34932da0b482bcf14cc67146094 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 23 Jul 2012 18:04:49 +0200 Subject: Fix: Send downlink assignment on PCH twice to make reception more safe If the mobile is not fast enough switching back to CCCH, the second assignment, which is sent later is usefull in this case. --- src/gprs_rlcmac_data.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 4109161d..7610dcb6 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -1505,10 +1505,12 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI!\n"); return; } - /* send immediate assignment */ - gprs_rlcmac_downlink_assignment(tbf, 0, imsi); /* change state */ tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); + /* send immediate assignment */ + gprs_rlcmac_downlink_assignment(tbf, 0, imsi); + /* send immediate assignment */ + gprs_rlcmac_downlink_assignment(tbf, 0, imsi); /* start timer */ tbf_timer_start(tbf, 0, Tassign_agch); } -- cgit v1.2.3 From bc65586917eed2ac5a6ac00551b4f35935d0426c Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 23 Jul 2012 18:13:31 +0200 Subject: Fix: Kill pending downlink TBF, if mobile requests uplink TBF on RACH If the mobile misses assignment, it changes back to idle mode. In this case we must kill the pending downlink TBF, because it is not used by mobile and we can assign a new downlink TBF for new downlink data. (We may not have two downlink TBF with same TLLI!) --- src/gprs_rlcmac_data.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 7610dcb6..2a4c7b1a 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -644,6 +644,8 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, /* get TLLI */ if (!tbf->tlli_valid) { + struct gprs_rlcmac_tbf *dl_tbf; + /* no TLLI yet */ if (!rh->ti) { LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d without " @@ -659,6 +661,13 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, tbf->tlli_valid = 1; LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of " "UL DATA TBF=%d.\n", tbf->tlli, rh->tfi); + if ((dl_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF))) { + LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from " + "TLLI=0x%08x while DL TBF=%d still exists. " + "Killing pending DL TBF\n", tbf->tlli, + dl_tbf->tfi); + tbf_free(dl_tbf); + } /* already have TLLI, but we stille get another one */ } else if (rh->ti) { uint32_t tlli; -- cgit v1.2.3 From 7f5352c17bf08cbeba44849978ee984832f3e510 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 23 Jul 2012 18:20:36 +0200 Subject: Fix: gprs_rlcmac_trigger_downlink_assignment() selects correct channel In order to select correct channel (PCH or PACCH), a tbf pointer is set in case of PACCH. The tbf pointer points to TBF whose PACCH is used. --- src/gprs_bssgp_pcu.cpp | 12 +++++++++--- src/gprs_rlcmac.h | 4 ++-- src/gprs_rlcmac_data.cpp | 23 ++++++++--------------- 3 files changed, 19 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 217acdb9..d4a65574 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -141,7 +141,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) if (!tbf->ms_class && ms_class) tbf->ms_class = ms_class; tbf_update(tbf); - gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL); + 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 */ @@ -173,18 +173,24 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) } } else { uint8_t trx, ts, use_trx, first_ts, ta, ss; + struct gprs_rlcmac_tbf *old_tbf; /* check for uplink data, so we copy our informations */ - if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF))) { + tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); + if (tbf && tbf->contention_resolution_done + && (tbf->state != GPRS_RLCMAC_FINISHED + || tbf->ul_ack_state != GPRS_RLCMAC_UL_ACK_WAIT_ACK)) { use_trx = tbf->trx; first_ts = tbf->first_ts; ta = tbf->ta; ss = 0; + old_tbf = tbf; } else { use_trx = -1; first_ts = -1; ta = 0; /* FIXME: initial TA */ ss = 1; /* PCH assignment only allows one timeslot */ + old_tbf = NULL; } // Create new TBF (any TRX) @@ -216,7 +222,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) * 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, imsi); + gprs_rlcmac_trigger_downlink_assignment(tbf, old_tbf, imsi); } return 0; diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 8a8351d6..41fd2067 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -287,8 +287,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( struct msgb *gprs_rlcmac_send_packet_downlink_assignment( struct gprs_rlcmac_tbf *tbf, uint32_t fn); -void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, - uint8_t old_downlink, char *imsi); +void gprs_rlcmac_trigger_downlink_assignment(struct gprs_rlcmac_tbf *tbf, + struct gprs_rlcmac_tbf *old_tbf, char *imsi); int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, uint8_t ssn, uint8_t *rbb); diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 2a4c7b1a..e2549d41 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -315,7 +315,7 @@ void tbf_timer_cb(void *_tbf) switch (tbf->T) { #ifdef DEBUG_DL_ASS_IDLE case 1234: - gprs_rlcmac_trigger_downlink_assignment(tbf, 0, debug_imsi); + gprs_rlcmac_trigger_downlink_assignment(tbf, NULL, debug_imsi); break; #endif case 0: /* assignment */ @@ -1380,7 +1380,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, "because another LLC PDU has arrived in between\n"); memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset RLC states */ tbf_update(tbf); - gprs_rlcmac_trigger_downlink_assignment(tbf, 1, NULL); + gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); return 0; } @@ -1406,7 +1406,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( /* be sure to check first, if contention resolution is done, * otherwise we cannot send the assignment yet */ if (!tbf->contention_resolution_done) { - LOGP(DRLCMAC, LOGL_NOTICE, "Cannot assign DL TBF now, " + LOGP(DRLCMAC, LOGL_DEBUG, "Cannot assign DL TBF now, " "because contention resolution is not " "finished.\n"); return NULL; @@ -1472,11 +1472,9 @@ static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll, } /* depending on the current TBF, we assign on PACCH or AGCH */ -void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, - uint8_t old_downlink, char *imsi) +void gprs_rlcmac_trigger_downlink_assignment(struct gprs_rlcmac_tbf *tbf, + struct gprs_rlcmac_tbf *old_tbf, char *imsi) { - gprs_rlcmac_tbf *old_tbf; - #ifdef DEBUG_DL_ASS_IDLE strncpy(debug_imsi, imsi); LOGP(DRLCMAC, LOGL_ERROR, "**** DEBUGGING DOWNLINK ASSIGNMENT ****\n"); @@ -1486,12 +1484,7 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, tbf_timer_stop(tbf); /* check for downlink tbf: */ - if (old_downlink) - old_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF); - else - old_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); - if (old_tbf && (old_tbf->state != GPRS_RLCMAC_FINISHED || - old_tbf->ul_ack_state != GPRS_RLCMAC_UL_ACK_WAIT_ACK)) { + if (old_tbf) { #ifdef DEBUG_DL_ASS_IDLE LOGP(DRLCMAC, LOGL_ERROR, "We must wait for current TBF to be " "released.\n"); @@ -1500,8 +1493,8 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, #else LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment on " "PACCH, because %s TBF=%d exists for TLLI=0x%08x\n", - (old_tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", - old_tbf->tfi, old_tbf->tlli); + (old_tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", old_tbf->tfi, old_tbf->tlli); old_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; /* use TA from old TBF */ tbf->ta = old_tbf->ta; -- cgit v1.2.3 From b3ded4cf98d0ad877f4dc541e938cd6126bc9e5d Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Tue, 24 Jul 2012 10:47:24 +0200 Subject: Added debugging of downlink bandwidth --- src/gprs_debug.cpp | 1 + src/gprs_debug.h | 1 + src/gprs_rlcmac.cpp | 3 +++ src/gprs_rlcmac.h | 3 +++ src/gprs_rlcmac_data.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 32 insertions(+) (limited to 'src') diff --git a/src/gprs_debug.cpp b/src/gprs_debug.cpp index bc19b77e..2b9b690b 100644 --- a/src/gprs_debug.cpp +++ b/src/gprs_debug.cpp @@ -40,6 +40,7 @@ static const struct log_info_cat default_categories[] = { {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1}, {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1}, {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_INFO, 1}, + {"DRLCMACBW", "\033[1;31m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_INFO, 1}, {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO , 1}, {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, }; diff --git a/src/gprs_debug.h b/src/gprs_debug.h index b5b42767..1a5f01a0 100644 --- a/src/gprs_debug.h +++ b/src/gprs_debug.h @@ -34,6 +34,7 @@ enum { DRLCMACDL, DRLCMACUL, DRLCMACSCHED, + DRLCMACBW, DBSSGP, DPCU, aDebug_LastEntry diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index d1f0b549..e54c5b0c 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -278,6 +278,9 @@ struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, return NULL; } + /* set timestamp */ + gettimeofday(&tbf->bw_tv, NULL); + INIT_LLIST_HEAD(&tbf->llc_queue); if (dir == GPRS_RLCMAC_UL_TBF) llist_add(&tbf->list, &gprs_rlcmac_ul_tbfs); diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 41fd2067..7291f77a 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -199,6 +199,9 @@ struct gprs_rlcmac_tbf { struct osmo_gsm_timer_list gsm_timer; unsigned int fT; /* fTxxxx number */ unsigned int num_fT_exp; /* number of consecutive fT expirations */ + + struct timeval bw_tv; /* timestamp for bandwidth calculation */ + uint32_t bw_octets; /* number of octets transmitted since bw_tv */ }; extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */ diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index e2549d41..687a75da 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -941,6 +941,28 @@ static struct msgb *llc_dequeue(struct gprs_rlcmac_tbf *tbf) return msg; } +static int gprs_rlcmac_debug_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets) +{ + struct timeval now_tv, *bw_tv = &tbf->bw_tv; + uint32_t elapsed; + + tbf->bw_octets += octets; + + gettimeofday(&now_tv, NULL); + elapsed = ((now_tv.tv_sec - bw_tv->tv_sec) << 7) + + ((now_tv.tv_usec - bw_tv->tv_usec) << 7) / 1000000; + if (elapsed < 128) + return 0; + + LOGP(DRLCMACBW, LOGL_DEBUG, "DL Bandwitdh of TLLI=0x%08x: %d KBits/s\n", + tbf->tlli, tbf->bw_octets / elapsed); + + /* reset bandwidth values timestamp */ + memcpy(bw_tv, &now_tv, sizeof(struct timeval)); + tbf->bw_octets = 0; + + return 0; +} /* send DL data block * @@ -1095,6 +1117,7 @@ do_resend: LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for " "TBF=%d that fits precisely in last block: " "len=%d\n", tbf->tfi, tbf->llc_length); + gprs_rlcmac_debug_bw(tbf, tbf->llc_length); /* block is filled, so there is no extension */ *e_pointer |= 0x01; /* fill space */ @@ -1154,6 +1177,7 @@ do_resend: space -= chunk; LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: " "len=%d\n", tbf->tfi, tbf->llc_length); + gprs_rlcmac_debug_bw(tbf, tbf->llc_length); /* reset LLC frame */ tbf->llc_index = tbf->llc_length = 0; /* dequeue next LLC frame, if any */ -- cgit v1.2.3 From d6a8db65a530fad2696ffd3c250020e393c4c340 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 25 Jul 2012 08:38:21 +0200 Subject: Cleanup by splitting gprs_rlcmac_rcv_rts_block() into seperate methods --- src/gprs_rlcmac_sched.cpp | 286 +++++++++++++++++++++++++++------------------- 1 file changed, 171 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index f6af9b71..efd8a9ef 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -21,40 +21,14 @@ #include #include -extern struct llist_head block_queue; - -static uint8_t rlcmac_dl_idle[23] = { - 0x47, /* control without optional header octets, no polling, USF=111 */ - 0x94, /* dummy downlink control message, paging mode 00 */ - 0x2b, /* no persistance level, 7 bits spare pattern */ - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b -}; - -int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, - uint32_t fn, uint8_t block_nr) +uint32_t sched_poll(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr, + struct gprs_rlcmac_tbf **poll_tbf, + struct gprs_rlcmac_tbf **ul_ack_tbf, + struct gprs_rlcmac_tbf **dl_ass_tbf, + struct gprs_rlcmac_tbf **ul_ass_tbf) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - struct gprs_rlcmac_pdch *pdch; - struct gprs_rlcmac_tbf *tbf, *poll_tbf = NULL, *dl_ass_tbf = NULL, - *ul_ass_tbf = NULL, *ul_ack_tbf = NULL; - uint8_t usf = 0x7; - struct msgb *msg = NULL; + struct gprs_rlcmac_tbf *tbf; uint32_t poll_fn; - uint8_t i, tfi; - - if (trx >= 8 || ts >= 8) - return -EINVAL; - pdch = &bts->trx[trx].pdch[ts]; - - if (!pdch->enable) { - LOGP(DRLCMACSCHED, LOGL_ERROR, "Received RTS on disabled PDCH: " - "TRX=%d TS=%d\n", trx, ts); - return -EIO; - } - - /* store last frame number of RTS */ - pdch->last_rts_fn = fn; /* check special TBF for events */ poll_fn = fn + 4; @@ -68,13 +42,13 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* polling for next uplink block */ if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED && tbf->poll_fn == poll_fn) - poll_tbf = tbf; + *poll_tbf = tbf; if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) - ul_ack_tbf = tbf; + *ul_ack_tbf = tbf; if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) - dl_ass_tbf = tbf; + *dl_ass_tbf = tbf; if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) - ul_ass_tbf = tbf; + *ul_ass_tbf = tbf; } llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { /* this trx, this ts */ @@ -83,51 +57,60 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* polling for next uplink block */ if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED && tbf->poll_fn == poll_fn) - poll_tbf = tbf; + *poll_tbf = tbf; if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) - dl_ass_tbf = tbf; + *dl_ass_tbf = tbf; if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) - ul_ass_tbf = tbf; + *ul_ass_tbf = tbf; } - /* check uplink ressource for polling */ - if (poll_tbf) { + return poll_fn; +} + +uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn, + uint8_t block_nr, struct gprs_rlcmac_pdch *pdch) +{ + struct gprs_rlcmac_tbf *tbf; + uint8_t usf = 0x07; + uint8_t i, tfi; + + /* select uplink ressource */ + for (i = 0, tfi = pdch->next_ul_tfi; i < 32; + i++, tfi = (tfi + 1) & 31) { + tbf = pdch->ul_tbf[tfi]; + /* no TBF for this tfi, go next */ + if (!tbf) + continue; + /* no UL ressources needed, go next */ + /* we don't need to give ressources in FINISHED state, + * because we have received all blocks and only poll + * for packet control ack. */ + if (tbf->state != GPRS_RLCMAC_FLOW) + continue; + + /* use this USF */ + usf = tbf->dir.ul.usf[ts]; LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " - "TS=%d FN=%d block_nr=%d scheduling free USF for " - "polling at FN=%d of %s TFI=%d\n", trx, ts, fn, - block_nr, poll_fn, - (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", - poll_tbf->tfi); - /* use free USF */ - /* else, we search for uplink ressource */ - } else { - /* select uplink ressource */ - for (i = 0, tfi = pdch->next_ul_tfi; i < 32; - i++, tfi = (tfi + 1) & 31) { - tbf = pdch->ul_tbf[tfi]; - /* no TBF for this tfi, go next */ - if (!tbf) - continue; - /* no UL ressources needed, go next */ - /* we don't need to give ressources in FINISHED state, - * because we have received all blocks and only poll - * for packet control ack. */ - if (tbf->state != GPRS_RLCMAC_FLOW) - continue; - - /* use this USF */ - usf = tbf->dir.ul.usf[ts]; - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: " - "TRX=%d TS=%d FN=%d block_nr=%d scheduling " - "USF=%d for required uplink ressource of " - "UL TBF=%d\n", trx, ts, fn, block_nr, usf, tfi); - /* next TBF to handle ressource is the next one */ - pdch->next_ul_tfi = (tfi + 1) & 31; - break; - } + "TS=%d FN=%d block_nr=%d scheduling USF=%d for " + "required uplink ressource of UL TBF=%d\n", trx, ts, fn, + block_nr, usf, tfi); + /* next TBF to handle ressource is the next one */ + pdch->next_ul_tfi = (tfi + 1) & 31; + break; } - /* Prio 1: select control message */ + return usf; +} + +struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn, + uint8_t block_nr, struct gprs_rlcmac_pdch *pdch, + struct gprs_rlcmac_tbf *ul_ack_tbf, + struct gprs_rlcmac_tbf *dl_ass_tbf, + struct gprs_rlcmac_tbf *ul_ass_tbf) +{ + struct msgb *msg = NULL; + struct gprs_rlcmac_tbf *tbf = NULL; + /* schedule PACKET DOWNLINK ASSIGNMENT */ if (dl_ass_tbf) { tbf = dl_ass_tbf; @@ -143,64 +126,137 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, tbf = ul_ack_tbf; msg = gprs_rlcmac_send_uplink_ack(tbf, fn); } + /* any message */ if (msg) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " "message at RTS for %s TBF=%d (TRX=%d, TS=%d)\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, trx, ts); + return msg; } /* schedule PACKET PAGING REQUEST */ - if (!msg && !llist_empty(&pdch->paging_list)) { - msg = gprs_rlcmac_send_packet_paging_request(pdch); - if (msg) - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging " - "request message at RTS for (TRX=%d, TS=%d)\n", - trx, ts); + if (llist_empty(&pdch->paging_list)) + return NULL; + msg = gprs_rlcmac_send_packet_paging_request(pdch); + if (msg) + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request " + "message at RTS for (TRX=%d, TS=%d)\n", trx, ts); + + return msg; +} + +struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn, + uint8_t block_nr, struct gprs_rlcmac_pdch *pdch) +{ + struct msgb *msg = NULL; + struct gprs_rlcmac_tbf *tbf = NULL; + uint8_t i, tfi; + + /* select downlink ressource */ + for (i = 0, tfi = pdch->next_dl_tfi; i < 32; + i++, tfi = (tfi + 1) & 31) { + tbf = pdch->dl_tbf[tfi]; + /* no TBF for this tfi, go next */ + if (!tbf) + continue; + /* no DL TBF, go next */ + if (tbf->direction != GPRS_RLCMAC_DL_TBF) + continue; + /* no DL ressources needed, go next */ + if (tbf->state != GPRS_RLCMAC_FLOW + && tbf->state != GPRS_RLCMAC_FINISHED) + 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 */ + pdch->next_dl_tfi = (tfi + 1) & 31; + /* generate DL data block */ + msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn, + ts); + break; } - /* Prio 2: select data message for downlink */ - if (!msg) { - /* select downlink ressource */ - for (i = 0, tfi = pdch->next_dl_tfi; i < 32; - i++, tfi = (tfi + 1) & 31) { - tbf = pdch->dl_tbf[tfi]; - /* no TBF for this tfi, go next */ - if (!tbf) - continue; - /* no DL TBF, go next */ - if (tbf->direction != GPRS_RLCMAC_DL_TBF) - continue; - /* no DL ressources needed, go next */ - if (tbf->state != GPRS_RLCMAC_FLOW - && tbf->state != GPRS_RLCMAC_FINISHED) - 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 */ - pdch->next_dl_tfi = (tfi + 1) & 31; - /* generate DL data block */ - msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn, - ts); - break; - } + return msg; +} +static uint8_t rlcmac_dl_idle[23] = { + 0x47, /* control without optional header octets, no polling, USF=111 */ + 0x94, /* dummy downlink control message, paging mode 00 */ + 0x2b, /* no persistance level, 7 bits spare pattern */ + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b +}; + +struct msgb *sched_dummy(void) +{ + struct msgb *msg; + + msg = msgb_alloc(23, "rlcmac_dl_idle"); + if (!msg) + return NULL; + memcpy(msgb_put(msg, 23), rlcmac_dl_idle, 23); + + return msg; +} + +int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, + uint32_t fn, uint8_t block_nr) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_pdch *pdch; + struct gprs_rlcmac_tbf *poll_tbf = NULL, *dl_ass_tbf = NULL, + *ul_ass_tbf = NULL, *ul_ack_tbf = NULL; + uint8_t usf = 0x7; + struct msgb *msg = NULL; + uint32_t poll_fn; + + if (trx >= 8 || ts >= 8) + return -EINVAL; + pdch = &bts->trx[trx].pdch[ts]; + + if (!pdch->enable) { + LOGP(DRLCMACSCHED, LOGL_ERROR, "Received RTS on disabled PDCH: " + "TRX=%d TS=%d\n", trx, ts); + return -EIO; } + /* store last frame number of RTS */ + pdch->last_rts_fn = fn; + + poll_fn = sched_poll(trx, ts, fn, block_nr, &poll_tbf, &ul_ack_tbf, + &dl_ass_tbf, &ul_ass_tbf); + /* check uplink ressource for polling */ + if (poll_tbf) + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " + "TS=%d FN=%d block_nr=%d scheduling free USF for " + "polling at FN=%d of %s TFI=%d\n", trx, ts, fn, + block_nr, poll_fn, + (poll_tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", poll_tbf->tfi); + /* use free USF */ + /* else, we search for uplink ressource */ + else + usf = sched_select_uplink(trx, ts, fn, block_nr, pdch); + + /* Prio 1: select control message */ + msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ack_tbf, + dl_ass_tbf, ul_ass_tbf); + + /* Prio 2: select data message for downlink */ + if (!msg) + msg = sched_select_downlink(trx, ts, fn, block_nr, pdch); + /* Prio 3: send dummy contol message */ - if (!msg) { - msg = msgb_alloc(23, "rlcmac_dl_idle"); - if (!msg) - return -ENOMEM; - memcpy(msgb_put(msg, 23), rlcmac_dl_idle, 23); - } + if (!msg) + msg = sched_dummy(); + + if (!msg) + return -ENOMEM; /* msg is now available */ /* set USF */ msg->data[0] = (msg->data[0] & 0xf8) | usf; -// printf("len=%d, date=%s\n", msg->len, osmo_hexdump(msg->data, msg->len)); - /* send PDTCH/PACCH to L1 */ pcu_l1if_tx_pdtch(msg, trx, ts, arfcn, fn, block_nr); -- cgit v1.2.3 From 6681bb8d0c847ad59a1e6109689ec322884e8e27 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 25 Jul 2012 08:48:44 +0200 Subject: Replaced malloc() by talloc_zero() to be able to track memeory leaks --- src/gprs_rlcmac.cpp | 9 +++++---- src/gprs_rlcmac_data.cpp | 17 ++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index e54c5b0c..c9279c5e 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -78,7 +78,7 @@ llist_head *gprs_rlcmac_tbfs_lists[] = { &gprs_rlcmac_dl_tbfs, NULL }; -void *rlcmac_tall_ctx; +extern void *tall_pcu_ctx; /* FIXME: spread ressources over multiple TRX. Also add option to use same * TRX in case of existing TBF for TLLI in the other direction. */ @@ -245,7 +245,7 @@ struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, if (trx >= 8 || first_ts >= 8 || tfi >= 32) return NULL; - tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf); + tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_tbf); if (!tbf) return NULL; @@ -1017,7 +1017,7 @@ int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv) for (ts = 0; ts < 8; ts++) { if ((slot_mask[trx] & (1 << ts))) { /* schedule */ - pag = talloc_zero(rlcmac_tall_ctx, + pag = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_paging); if (!pag) return -ENOMEM; @@ -1116,12 +1116,13 @@ struct msgb *gprs_rlcmac_send_packet_paging_request( } bitvec_pack(pag_vec, msgb_put(msg, 23)); - RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n"); decode_gsm_rlcmac_downlink(pag_vec, mac_control_block); LOGPC(DCSN1, LOGL_NOTICE, "\n"); LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n"); bitvec_free(pag_vec); + talloc_free(mac_control_block); return msg; } diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 687a75da..58985e0d 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -22,6 +22,8 @@ #include #include +extern void *tall_pcu_ctx; + extern "C" { int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli, uint8_t num_frames, uint32_t num_octets); @@ -140,7 +142,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, struct gprs_rlcmac_tbf *tbf; int rc; - RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t)); + RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)talloc_zero(tall_pcu_ctx, RlcMacUplink_t); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++\n"); decode_gsm_rlcmac_uplink(rlc_block, ul_control_block); LOGPC(DCSN1, LOGL_NOTICE, "\n"); @@ -294,7 +296,7 @@ uplink_request: default: LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] unknown control block received\n"); } - free(ul_control_block); + talloc_free(ul_control_block); return 1; } @@ -575,12 +577,12 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, } bitvec_unhex(ack_vec, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); - RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); write_packet_uplink_ack(mac_control_block, tbf, final); encode_gsm_rlcmac_downlink(ack_vec, mac_control_block); bitvec_pack(ack_vec, msgb_put(msg, 23)); bitvec_free(ack_vec); - free(mac_control_block); + talloc_free(mac_control_block); /* now we must set this flag, so we are allowed to assign downlink * TBF on PACCH. it is only allowed when TLLI is aknowledged. */ @@ -836,12 +838,13 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf, POLLING_ASSIGNMENT); bitvec_pack(ass_vec, msgb_put(msg, 23)); - RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); decode_gsm_rlcmac_downlink(ass_vec, mac_control_block); LOGPC(DCSN1, LOGL_NOTICE, "\n"); LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Uplink Assignment -------------------------\n"); bitvec_free(ass_vec); + talloc_free(mac_control_block); #if POLLING_ASSIGNMENT == 1 FIXME process does not work, also the acknowledgement is not checked. @@ -1457,7 +1460,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( bitvec_unhex(ass_vec, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); LOGP(DRLCMAC, LOGL_INFO, "TBF: START TFI: %u TLLI: 0x%08x Packet Downlink Assignment (PACCH)\n", new_tbf->tfi, new_tbf->tlli); - RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); write_packet_downlink_assignment(mac_control_block, tbf->tfi, (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf, POLLING_ASSIGNMENT); @@ -1467,7 +1470,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Downlink Assignment -------------------------\n"); bitvec_pack(ass_vec, msgb_put(msg, 23)); bitvec_free(ass_vec); - free(mac_control_block); + talloc_free(mac_control_block); #if POLLING_ASSIGNMENT == 1 tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; -- cgit v1.2.3 From ba1cd9bbc222bd62a4d1ef4bbb6d380347f04f5f Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 25 Jul 2012 09:14:09 +0200 Subject: Fixed two issues found by clang, pointed out by Holger --- src/gprs_bssgp_pcu.cpp | 3 +++ src/gprs_rlcmac.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index d4a65574..c4d27e85 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -235,6 +235,9 @@ int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_ uint8_t pdu_type = bgph->pdu_type; unsigned rc = 0; + if (!bctx) + return -EINVAL; + /* If traffic is received on a BVC that is marked as blocked, the * received PDU shall not be accepted and a STATUS PDU (Cause value: * BVC Blocked) shall be sent to the peer entity on the signalling BVC */ diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index c9279c5e..a827d363 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -370,7 +370,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, uint8_t tx_win_min, tx_win_max, tx_range; uint8_t rx_window = 0, tx_window = 0; const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" }; - uint8_t usf[8]; + int8_t usf[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; /* must be signed */ int8_t tsc = -1; /* must be signed */ uint8_t i, ts; -- cgit v1.2.3 From 0b0f2c06952391b75fa9989f4fcfa5412694fadb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 23 Jul 2012 10:47:33 +0200 Subject: misc: Add the libosmocore CFLAGS to the CPPFLAGS libosmocore might not be in the standard include path, add the CFLAGS to the preprocessor flags. This is fixing the build on the Osmocom Jenkins. --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 3a68927a..e52a597b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ # along with this program. If not, see . # -AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) +AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) AM_CXXFLAGS = -Wall -ldl -pthread noinst_LTLIBRARIES = libgprs.la -- cgit v1.2.3 From ef42540f0db9d305c542672044ba4faa2f074b10 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 25 Jul 2012 15:47:03 +0200 Subject: Be sure to priorize uplink assignment (PACCH) This is required because uplink assignment (PACCH) is done on a request by mobile, so the mobile expects that it get this assignment in return. After that we may assign downlink. --- src/gprs_rlcmac_sched.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index efd8a9ef..003f5032 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -23,9 +23,9 @@ uint32_t sched_poll(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr, struct gprs_rlcmac_tbf **poll_tbf, - struct gprs_rlcmac_tbf **ul_ack_tbf, + struct gprs_rlcmac_tbf **ul_ass_tbf, struct gprs_rlcmac_tbf **dl_ass_tbf, - struct gprs_rlcmac_tbf **ul_ass_tbf) + struct gprs_rlcmac_tbf **ul_ack_tbf) { struct gprs_rlcmac_tbf *tbf; uint32_t poll_fn; @@ -104,23 +104,23 @@ uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn, struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr, struct gprs_rlcmac_pdch *pdch, - struct gprs_rlcmac_tbf *ul_ack_tbf, + struct gprs_rlcmac_tbf *ul_ass_tbf, struct gprs_rlcmac_tbf *dl_ass_tbf, - struct gprs_rlcmac_tbf *ul_ass_tbf) + struct gprs_rlcmac_tbf *ul_ack_tbf) { struct msgb *msg = NULL; struct gprs_rlcmac_tbf *tbf = NULL; - /* schedule PACKET DOWNLINK ASSIGNMENT */ - if (dl_ass_tbf) { - tbf = dl_ass_tbf; - msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, fn); - } - /* schedule PACKET UPLINK ASSIGNMENT */ - if (!msg && ul_ass_tbf) { + /* schedule PACKET UPLINK ASSIGNMENT (high priority) */ + if (ul_ass_tbf) { tbf = ul_ass_tbf; msg = gprs_rlcmac_send_packet_uplink_assignment(tbf, fn); } + /* schedule PACKET DOWNLINK ASSIGNMENT (low priotiry) */ + if (!msg && dl_ass_tbf) { + tbf = dl_ass_tbf; + msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, fn); + } /* schedule PACKET UPLINK ACK */ if (!msg && ul_ack_tbf) { tbf = ul_ack_tbf; @@ -223,8 +223,8 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* store last frame number of RTS */ pdch->last_rts_fn = fn; - poll_fn = sched_poll(trx, ts, fn, block_nr, &poll_tbf, &ul_ack_tbf, - &dl_ass_tbf, &ul_ass_tbf); + poll_fn = sched_poll(trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf, + &dl_ass_tbf, &ul_ack_tbf); /* check uplink ressource for polling */ if (poll_tbf) LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " @@ -239,8 +239,8 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, usf = sched_select_uplink(trx, ts, fn, block_nr, pdch); /* Prio 1: select control message */ - msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ack_tbf, - dl_ass_tbf, ul_ass_tbf); + msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ass_tbf, + dl_ass_tbf, ul_ack_tbf); /* Prio 2: select data message for downlink */ if (!msg) -- cgit v1.2.3 From 4b55962e556b344131dce67fde2b46a602da8c81 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 26 Jul 2012 07:58:33 +0200 Subject: Minor changes on comments of scheduler --- src/gprs_rlcmac_sched.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index 003f5032..9ffdfb64 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -111,17 +111,17 @@ struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn, struct msgb *msg = NULL; struct gprs_rlcmac_tbf *tbf = NULL; - /* schedule PACKET UPLINK ASSIGNMENT (high priority) */ + /* schedule PACKET UPLINK ASSIGNMENT (1st priority) */ if (ul_ass_tbf) { tbf = ul_ass_tbf; msg = gprs_rlcmac_send_packet_uplink_assignment(tbf, fn); } - /* schedule PACKET DOWNLINK ASSIGNMENT (low priotiry) */ + /* schedule PACKET DOWNLINK ASSIGNMENT (2nd priotiry) */ if (!msg && dl_ass_tbf) { tbf = dl_ass_tbf; msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, fn); } - /* schedule PACKET UPLINK ACK */ + /* schedule PACKET UPLINK ACK (3rd priority) */ if (!msg && ul_ack_tbf) { tbf = ul_ack_tbf; msg = gprs_rlcmac_send_uplink_ack(tbf, fn); -- cgit v1.2.3 From 08e93cdc3fe54df7753170e973d119c6bbbb6181 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 26 Jul 2012 08:13:06 +0200 Subject: Use final_ack_sent and contention_resolution_done to define ongoing UL TBF Both flags can be used to determine wether assignment must be sent on PCH or on AGCH. Before contention resolution is done, mobile will ignore downlink assinment. When final uplink acknowledge was sent, the mobile will go back to PCH after reception of akcnowledge. --- src/gprs_bssgp_pcu.cpp | 5 ++--- src/gprs_rlcmac.h | 3 ++- src/gprs_rlcmac_data.cpp | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index c4d27e85..9b977f29 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -177,9 +177,8 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) /* check for uplink data, so we copy our informations */ tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); - if (tbf && tbf->contention_resolution_done - && (tbf->state != GPRS_RLCMAC_FINISHED - || tbf->ul_ack_state != GPRS_RLCMAC_UL_ACK_WAIT_ACK)) { + if (tbf && tbf->dir.ul.contention_resolution_done + && !tbf->dir.ul.final_ack_sent) { use_trx = tbf->trx; first_ts = tbf->first_ts; ta = tbf->ta; diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 7291f77a..fc4173de 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -139,7 +139,6 @@ struct gprs_rlcmac_tbf { uint8_t tfi; uint32_t tlli; uint8_t tlli_valid; - uint8_t contention_resolution_done; /* set after done */ uint8_t trx; uint16_t arfcn; uint8_t tsc; @@ -187,6 +186,8 @@ struct gprs_rlcmac_tbf { int32_t rx_counter; /* count all received blocks */ uint8_t n3103; /* N3103 counter */ uint8_t usf[8]; /* list USFs per PDCH (timeslot) */ + uint8_t contention_resolution_done; /* set after done */ + uint8_t final_ack_sent; /* set if we sent final ack */ } ul; } dir; uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */ diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 58985e0d..69cfe136 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -256,7 +256,7 @@ uplink_request: } ul_tbf->tlli = tbf->tlli; ul_tbf->tlli_valid = 1; /* no contention resolution */ - ul_tbf->contention_resolution_done = 1; + ul_tbf->dir.ul.contention_resolution_done = 1; ul_tbf->ta = tbf->ta; /* use current TA */ tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN); tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); @@ -586,13 +586,14 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, /* now we must set this flag, so we are allowed to assign downlink * TBF on PACCH. it is only allowed when TLLI is aknowledged. */ - tbf->contention_resolution_done = 1; + tbf->dir.ul.contention_resolution_done = 1; if (final) { tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; /* waiting for final acknowledge */ tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK; + tbf->dir.ul.final_ack_sent = 1; } else tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; @@ -1432,7 +1433,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( if (tbf->direction == GPRS_RLCMAC_UL_TBF) { /* be sure to check first, if contention resolution is done, * otherwise we cannot send the assignment yet */ - if (!tbf->contention_resolution_done) { + if (!tbf->dir.ul.contention_resolution_done) { LOGP(DRLCMAC, LOGL_DEBUG, "Cannot assign DL TBF now, " "because contention resolution is not " "finished.\n"); -- cgit v1.2.3 From 802bb6eac834b8beffc5eb47a583842fb31d6e52 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 6 Aug 2012 11:15:05 +0200 Subject: Adding polling for packet control ack at packet downlink/uplink assignment --- src/gprs_rlcmac.h | 3 +- src/gprs_rlcmac_data.cpp | 91 +++++++++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index fc4173de..e3fd9914 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -176,7 +176,6 @@ 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 */ - uint8_t n3105; /* N3105 counter */ } dl; struct { uint16_t bsn; /* block sequence number */ @@ -193,6 +192,8 @@ struct gprs_rlcmac_tbf { uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */ uint8_t rlc_block_len[RLC_MAX_SNS/2]; /* block len of history */ + uint8_t n3105; /* N3105 counter */ + struct osmo_timer_list timer; unsigned int T; /* Txxxx number */ unsigned int num_T_exp; /* number of consecutive T expirations */ diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 69cfe136..f56d848e 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -35,8 +35,9 @@ int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli, /* After sending these frames, we poll for ack/nack. */ #define POLL_ACK_AFTER_FRAMES 10 -/* If acknowledgement to uplink/downlin assignmentshould be polled */ -#define POLLING_ASSIGNMENT 0 +/* If acknowledgement to uplink/downlink assignmentshould be polled */ +#define POLLING_ASSIGNMENT_DL 1 +#define POLLING_ASSIGNMENT_UL 1 extern "C" { /* TS 04.60 10.2.2 */ @@ -99,28 +100,44 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) } } else if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " "CONTROL ACK for PACKET UPLINK ASSIGNMENT.\n"); tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; + tbf->n3105++; + if (tbf->n3105 == bts->n3105) { + LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n"); + tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); + tbf_timer_start(tbf, 3195, bts->t3195, 0); + return 0; + } + /* reschedule UL assignment */ + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; } else if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " "CONTROL ACK for PACKET DOWNLINK ASSIGNMENT.\n"); tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; - /* in case out downlink assigment failed: */ - if (tbf->state == GPRS_RLCMAC_ASSIGN) { - LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment failed\n"); - tbf_free(tbf); + tbf->n3105++; + if (tbf->n3105 == bts->n3105) { + LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n"); + tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); + tbf_timer_start(tbf, 3195, bts->t3195, 0); + return 0; } + /* reschedule DL assignment */ + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; } else - if (tbf->direction == GPRS_RLCMAC_DL_TBF) - { + if (tbf->direction == GPRS_RLCMAC_DL_TBF) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " " DOWNLINK ACK.\n"); - tbf->dir.dl.n3105++; - if (tbf->dir.dl.n3105 == bts->n3105) { + tbf->n3105++; + if (tbf->n3105 == bts->n3105) { LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n"); tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); tbf_timer_start(tbf, 3195, bts->t3195, 0); @@ -175,6 +192,8 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, } if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] DOWNLINK ASSIGNED TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + /* reset N3105 */ + tbf->n3105 = 0; tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; if (tbf->direction == GPRS_RLCMAC_UL_TBF) tbf = tbf_by_tlli(tbf->tlli, @@ -190,6 +209,8 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, } if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] UPLINK ASSIGNED TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + /* reset N3105 */ + tbf->n3105 = 0; tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; if (tbf->direction == GPRS_RLCMAC_DL_TBF) tbf = tbf_by_tlli(tbf->tlli, @@ -216,7 +237,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, break; } /* reset N3105 */ - tbf->dir.dl.n3105 = 0; + tbf->n3105 = 0; /* stop timer T3191 */ tbf_timer_stop(tbf); tlli = tbf->tlli; @@ -801,7 +822,7 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( struct msgb *msg; struct gprs_rlcmac_tbf *new_tbf; -#if POLLING_ASSIGNMENT == 1 +#if POLLING_ASSIGNMENT_UL == 1 if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " "sheduled for TBF=%d, so we must wait for uplink " @@ -837,7 +858,7 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); write_packet_uplink_assignment(ass_vec, tbf->tfi, (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf, - POLLING_ASSIGNMENT); + POLLING_ASSIGNMENT_UL); bitvec_pack(ass_vec, msgb_put(msg, 23)); RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); @@ -847,8 +868,7 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( bitvec_free(ass_vec); talloc_free(mac_control_block); -#if POLLING_ASSIGNMENT == 1 - FIXME process does not work, also the acknowledgement is not checked. +#if POLLING_ASSIGNMENT_UL == 1 tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; @@ -1419,15 +1439,22 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( { struct msgb *msg; struct gprs_rlcmac_tbf *new_tbf; + int poll_ass_dl = POLLING_ASSIGNMENT_DL; -#if POLLING_ASSIGNMENT == 1 - if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { - LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already " - "sheduled for TBF=%d, so we must wait for downlink " - "assignment...\n", tbf->tfi); - return NULL; + if (poll_ass_dl && tbf->direction == GPRS_RLCMAC_DL_TBF + && tbf->control_ts != tbf->first_common_ts) { + LOGP(DRLCMAC, LOGL_NOTICE, "Cannot poll for downlink " + "assigment, because MS cannot reply.\n"); + poll_ass_dl = 0; + } + if (poll_ass_dl) { + if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { + LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already sheduled " + "for TBF=%d, so we must wait for downlink " + "assignment...\n", tbf->tfi); + return NULL; + } } -#endif /* on uplink TBF we get the downlink TBF to be assigned. */ if (tbf->direction == GPRS_RLCMAC_UL_TBF) { @@ -1464,7 +1491,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); write_packet_downlink_assignment(mac_control_block, tbf->tfi, (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf, - POLLING_ASSIGNMENT); + poll_ass_dl); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n"); encode_gsm_rlcmac_downlink(ass_vec, mac_control_block); LOGPC(DCSN1, LOGL_NOTICE, "\n"); @@ -1473,15 +1500,15 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( bitvec_free(ass_vec); talloc_free(mac_control_block); -#if POLLING_ASSIGNMENT == 1 - tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; - tbf->poll_fn = (fn + 13) % 2715648; - tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; -#else - tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; - tbf_new_state(new_tbf, GPRS_RLCMAC_FLOW); - tbf_assign_control_ts(new_tbf); -#endif + if (poll_ass_dl) { + tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; + tbf->poll_fn = (fn + 13) % 2715648; + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; + } else { + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; + tbf_new_state(new_tbf, GPRS_RLCMAC_FLOW); + tbf_assign_control_ts(new_tbf); + } return msg; } -- cgit v1.2.3 From 14db19ed11d38f0d6f08bb1d6139b7b90f4fdc37 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 6 Aug 2012 15:03:03 +0200 Subject: Adding flags for debugging assignment and polling timeout --- src/gprs_bssgp_pcu.cpp | 1 + src/gprs_rlcmac.h | 10 ++++++ src/gprs_rlcmac_data.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 9b977f29..374baf63 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -138,6 +138,7 @@ 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; 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 e3fd9914..27933bde 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -132,9 +132,19 @@ enum gprs_rlcmac_tbf_direction { GPRS_RLCMAC_UL_TBF }; +#define GPRS_RLCMAC_FLAG_CCCH 0 /* assignment on CCCH */ +#define GPRS_RLCMAC_FLAG_PACCH 1 /* assignment on PACCH */ +#define GPRS_RLCMAC_FLAG_UL_DATA 2 /* uplink data received */ +#define GPRS_RLCMAC_FLAG_DL_ACK 3 /* downlink acknowledge received */ +#define GPRS_RLCMAC_FLAG_TO_UL_ACK 4 +#define GPRS_RLCMAC_FLAG_TO_DL_ACK 5 +#define GPRS_RLCMAC_FLAG_TO_UL_ASS 6 +#define GPRS_RLCMAC_FLAG_TO_DL_ASS 7 + struct gprs_rlcmac_tbf { struct llist_head list; enum gprs_rlcmac_tbf_state state; + uint32_t state_flags; enum gprs_rlcmac_tbf_direction direction; uint8_t tfi; uint32_t tlli; diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index f56d848e..d59153f7 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -73,6 +73,24 @@ struct rlc_li_field { } __attribute__ ((packed)); } +static int gprs_rlcmac_diag(struct gprs_rlcmac_tbf *tbf) +{ + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) + LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on CCCH\n"); + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) + LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on PACCH\n"); + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_UL_DATA))) + LOGP(DRLCMAC, LOGL_NOTICE, "- Uplink data was received\n"); + else if (tbf->direction == GPRS_RLCMAC_UL_TBF) + LOGP(DRLCMAC, LOGL_NOTICE, "- No uplink data received yet\n"); + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) + LOGP(DRLCMAC, LOGL_NOTICE, "- Downlink ACK was received\n"); + else if (tbf->direction == GPRS_RLCMAC_DL_TBF) + LOGP(DRLCMAC, LOGL_NOTICE, "- No downlink ACK received yet\n"); + + return 0; +} + int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for %s TBF=%d\n", @@ -81,8 +99,12 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) tbf->poll_state = GPRS_RLCMAC_POLL_NONE; if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) { - LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " - "CONTROL ACK for PACKET UPLINK ACK\n"); + if (!(tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK))) { + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " + "PACKET CONTROL ACK for PACKET UPLINK ACK\n"); + gprs_rlcmac_diag(tbf); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK); + } tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; if (tbf->state == GPRS_RLCMAC_FINISHED) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; @@ -102,8 +124,13 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " - "CONTROL ACK for PACKET UPLINK ASSIGNMENT.\n"); + if (!(tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS))) { + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " + "PACKET CONTROL ACK for PACKET UPLINK " + "ASSIGNMENT.\n"); + gprs_rlcmac_diag(tbf); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS); + } tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; tbf->n3105++; if (tbf->n3105 == bts->n3105) { @@ -118,8 +145,13 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " - "CONTROL ACK for PACKET DOWNLINK ASSIGNMENT.\n"); + if (!(tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS))) { + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " + "PACKET CONTROL ACK for PACKET DOWNLINK " + "ASSIGNMENT.\n"); + gprs_rlcmac_diag(tbf); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS); + } tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; tbf->n3105++; if (tbf->n3105 == bts->n3105) { @@ -134,8 +166,12 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) if (tbf->direction == GPRS_RLCMAC_DL_TBF) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling PACKET " - " DOWNLINK ACK.\n"); + if (!(tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) { + LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " + "PACKET DOWNLINK ACK.\n"); + gprs_rlcmac_diag(tbf); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK); + } tbf->n3105++; if (tbf->n3105 == bts->n3105) { LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n"); @@ -187,6 +223,13 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) { LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; + if ((tbf->state_flags & + (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK))) { + tbf->state_flags &= + ~(1 << GPRS_RLCMAC_FLAG_TO_UL_ACK); + LOGP(DRLCMAC, LOGL_NOTICE, "Recovered uplink " + "ack\n"); + } tbf_free(tbf); break; } @@ -204,6 +247,13 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, break; } tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + if ((tbf->state_flags & + (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS))) { + tbf->state_flags &= + ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ASS); + LOGP(DRLCMAC, LOGL_NOTICE, "Recovered downlink " + "assignment\n"); + } tbf_assign_control_ts(tbf); break; } @@ -221,6 +271,13 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, break; } tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + if ((tbf->state_flags & + (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS))) { + tbf->state_flags &= + ~(1 << GPRS_RLCMAC_FLAG_TO_UL_ASS); + LOGP(DRLCMAC, LOGL_NOTICE, "Recovered uplink " + "assignment\n"); + } tbf_assign_control_ts(tbf); break; } @@ -236,6 +293,11 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, fn, tfi, trx, ts); break; } + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_DL_ACK); + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) { + tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ACK); + LOGP(DRLCMAC, LOGL_NOTICE, "Recovered downlink ack\n"); + } /* reset N3105 */ tbf->n3105 = 0; /* stop timer T3191 */ @@ -280,6 +342,7 @@ uplink_request: ul_tbf->dir.ul.contention_resolution_done = 1; ul_tbf->ta = tbf->ta; /* use current TA */ tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN); + ul_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH); tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); /* schedule uplink assignment */ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; @@ -355,6 +418,7 @@ void tbf_timer_cb(void *_tbf) case 3195: LOGP(DRLCMAC, LOGL_NOTICE, "TBF T%d timeout during " "transsmission\n", tbf->T); + gprs_rlcmac_diag(tbf); /* fall through */ case 3193: LOGP(DRLCMAC, LOGL_DEBUG, "TBF will be freed due to timeout\n"); @@ -662,6 +726,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, rh->tfi); return 0; } + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA); LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TBF=%d received (V(Q)=%d .. " "V(R)=%d)\n", rh->tfi, tbf->dir.ul.v_q, tbf->dir.ul.v_r); @@ -910,6 +975,7 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) qta = 252; tbf->ta = qta >> 2; tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH); tbf_timer_start(tbf, 3169, bts->t3169, 0); LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi); LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26); @@ -1427,6 +1493,7 @@ 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_update(tbf); gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL); @@ -1555,6 +1622,7 @@ void gprs_rlcmac_trigger_downlink_assignment(struct gprs_rlcmac_tbf *tbf, tbf->ta = old_tbf->ta; /* change state */ tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH); #endif } else { LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment for TBF=%d on PCH, no TBF exist (IMSI=%s)\n", tbf->tfi, imsi); @@ -1564,6 +1632,7 @@ 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); /* send immediate assignment */ gprs_rlcmac_downlink_assignment(tbf, 0, imsi); /* send immediate assignment */ -- cgit v1.2.3 From 309ce743767d321565d8c63f0d78563154db3cd9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Tue, 7 Aug 2012 15:31:16 +0200 Subject: Fix: tfi_alloc() has some signed attributes --- src/gprs_rlcmac.cpp | 2 +- src/gprs_rlcmac.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index a827d363..956d52fc 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -84,7 +84,7 @@ extern void *tall_pcu_ctx; * TRX in case of existing TBF for TLLI in the other direction. */ /* search for free TFI and return TFI, TRX and first TS */ int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, - uint8_t use_trx, uint8_t first_ts) + int8_t use_trx, int8_t first_ts) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 27933bde..6bdef6be 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -229,7 +229,7 @@ struct gprs_rlcmac_paging { }; int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, - uint8_t use_trx, uint8_t first_ts); + int8_t use_trx, int8_t first_ts); struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, -- cgit v1.2.3 From cbcd124588abf91be129aee3f37505ca60706de9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Tue, 7 Aug 2012 15:48:21 +0200 Subject: Fix: Add timer for downlink TBF in assignment state This is required, since the UL TBF which is used to assign downlink TBF may be freed due to timeouts. --- src/gprs_rlcmac.h | 3 ++- src/gprs_rlcmac_data.cpp | 32 +++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 6bdef6be..e1c8343f 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -93,7 +93,8 @@ 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,800000 /* FIXME: we need a confirm from BTS */ +#define Tassign_pacch 2,0 /* timeout for pacch assigment */ enum gprs_rlcmac_tbf_state { GPRS_RLCMAC_NULL = 0, /* new created TBF */ diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index d59153f7..a1bed3c6 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -247,6 +247,8 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, break; } tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + /* stop pending assignment timer */ + tbf_timer_stop(tbf); if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS))) { tbf->state_flags &= @@ -405,13 +407,24 @@ void tbf_timer_cb(void *_tbf) break; #endif case 0: /* assignment */ - /* change state to FLOW, so scheduler will start transmission */ - 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"); + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) { + if (tbf->state == GPRS_RLCMAC_ASSIGN) { + LOGP(DRLCMAC, LOGL_NOTICE, "Releasing due to " + "PACCH assignment timeout.\n"); + tbf_free(tbf); + } else + LOGP(DRLCMAC, LOGL_ERROR, "Error: TBF is not " + "in assign state\n"); + } + if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) { + /* change state to FLOW, so scheduler will start transmission */ + 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"); + } break; case 3169: case 3191: @@ -1575,6 +1588,9 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; tbf_new_state(new_tbf, GPRS_RLCMAC_FLOW); tbf_assign_control_ts(new_tbf); + /* stop pending assignment timer */ + tbf_timer_stop(new_tbf); + } return msg; @@ -1623,6 +1639,8 @@ 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_PACCH); + /* start timer */ + tbf_timer_start(tbf, 0, Tassign_pacch); #endif } else { LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment for TBF=%d on PCH, no TBF exist (IMSI=%s)\n", tbf->tfi, imsi); -- cgit v1.2.3 From 07e97cf8a551b05d7f5f3f9583b68b2eff0f1c23 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Tue, 7 Aug 2012 16:00:56 +0200 Subject: Adding single block allocation It is mandatory to support it because MS may request a single block. In this case the network must assign a single block. It is possible to force single block allocation for all uplink requests on RACH. (VTY option) --- src/gprs_rlcmac.cpp | 117 ++++++++++++++++++++----- src/gprs_rlcmac.h | 21 ++++- src/gprs_rlcmac_data.cpp | 213 +++++++++++++++++++++++++++++++++------------- src/gprs_rlcmac_sched.cpp | 40 +++++++-- src/pcu_l1_if.cpp | 15 +++- src/pcu_vty.c | 28 ++++++ 6 files changed, 344 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 956d52fc..1aeb9b18 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -879,6 +879,67 @@ void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf) } } +/* starting time for assigning single slot + * This offset must be a multiple of 13. */ +#define AGCH_START_OFFSET 52 + +LLIST_HEAD(gprs_rlcmac_sbas); + +int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta) +{ + + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_pdch *pdch; + struct gprs_rlcmac_sba *sba; + uint8_t trx, ts; + uint32_t fn; + + sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba); + if (!sba) + return -ENOMEM; + + for (trx = 0; trx < 8; trx++) { + for (ts = 0; ts < 8; ts++) { + pdch = &bts->trx[trx].pdch[ts]; + if (!pdch->enable) + continue; + break; + } + if (ts < 8) + break; + } + if (trx == 8) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n"); + return -EINVAL; + } + + fn = (pdch->last_rts_fn + AGCH_START_OFFSET) % 2715648; + + sba->trx = trx; + sba->ts = ts; + sba->fn = fn; + sba->ta = ta; + + llist_add(&sba->list, &gprs_rlcmac_sbas); + + *_trx = trx; + *_ts = ts; + *_fn = fn; + return 0; +} + +struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn) +{ + struct gprs_rlcmac_sba *sba; + + llist_for_each_entry(sba, &gprs_rlcmac_sbas, list) { + if (sba->trx == trx && sba->ts == ts && sba->fn == fn) + return sba; + } + + return NULL; +} + #if 0 static void tbf_gsm_timer_cb(void *_tbf) { @@ -1129,9 +1190,9 @@ struct msgb *gprs_rlcmac_send_packet_paging_request( // GSM 04.08 9.1.18 Immediate assignment int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, - uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, + uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t tfi, uint8_t usf, uint32_t tlli, - uint8_t polling, uint32_t poll_fn) + uint8_t polling, uint32_t fn, uint8_t single_block) { unsigned wp = 0; uint8_t plen; @@ -1157,9 +1218,9 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, //10.5.2.30 Request Reference bitvec_write_field(dest, wp,ra,8); // RA - bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1' - bitvec_write_field(dest, wp,fn % 51,6); // T3 - bitvec_write_field(dest, wp,fn % 26,5); // T2 + bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1' + bitvec_write_field(dest, wp,ref_fn % 51,6); // T3 + bitvec_write_field(dest, wp,ref_fn % 26,5); // T2 // 10.5.2.40 Timing Advance bitvec_write_field(dest, wp,0x0,2); // spare @@ -1193,9 +1254,9 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX if (polling) { bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present - bitvec_write_field(dest, wp,(poll_fn / (26 * 51)) % 32,5); // T1' - bitvec_write_field(dest, wp,poll_fn % 51,6); // T3 - bitvec_write_field(dest, wp,poll_fn % 26,5); // T2 + bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1' + bitvec_write_field(dest, wp,fn % 51,6); // T3 + bitvec_write_field(dest, wp,fn % 26,5); // T2 } else { bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present } @@ -1209,20 +1270,32 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, // GMS 04.08 10.5.2.37b 10.5.2.16 bitvec_write_field(dest, wp, 3, 2); // "HH" bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment - bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation - bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity - bitvec_write_field(dest, wp, 0, 1); // POLLING - bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic - bitvec_write_field(dest, wp, usf, 3); // USF - bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY - bitvec_write_field(dest, wp, 0 , 1); // "0" power control: Not Present - bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND - bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING - bitvec_write_field(dest, wp, 1 , 1); // "1" Alpha : Present - bitvec_write_field(dest, wp, 0, 4); // Alpha - bitvec_write_field(dest, wp, 0, 5); // Gamma - bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG - bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG + if (single_block) { + bitvec_write_field(dest, wp, 0, 1); // Block Allocation : Single Block Allocation + bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present + bitvec_write_field(dest, wp, 0, 4); // Alpha + bitvec_write_field(dest, wp, 0, 5); // Gamma + bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG + bitvec_write_field(dest, wp, 1, 1); // TBF_STARTING_TIME_FLAG + bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1' + bitvec_write_field(dest, wp,fn % 51,6); // T3 + bitvec_write_field(dest, wp,fn % 26,5); // T2 + } else { + bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation + bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity + bitvec_write_field(dest, wp, 0, 1); // POLLING + bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic + bitvec_write_field(dest, wp, usf, 3); // USF + bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY + bitvec_write_field(dest, wp, 0, 1); // "0" power control: Not Present + bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND + bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING + bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present + bitvec_write_field(dest, wp, 0, 4); // Alpha + bitvec_write_field(dest, wp, 0, 5); // Gamma + bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG + bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG + } } return plen; diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index e1c8343f..5890bf06 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -79,6 +79,7 @@ struct gprs_rlcmac_bts { int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf, struct gprs_rlcmac_tbf *tbf, uint32_t cust); uint32_t alloc_algorithm_curst; /* options to customize algorithm */ + uint8_t force_two_phase; }; extern struct gprs_rlcmac_bts *gprs_rlcmac_bts; @@ -219,6 +220,7 @@ struct gprs_rlcmac_tbf { extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */ extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */ +extern struct llist_head gprs_rlcmac_sbas; /* list of single block allocs */ /* * paging entry @@ -229,6 +231,21 @@ struct gprs_rlcmac_paging { uint8_t identity_lv[9]; }; +/* + * single block allocation entry + */ +struct gprs_rlcmac_sba { + struct llist_head list; + uint8_t trx; + uint8_t ts; + uint32_t fn; + uint8_t ta; +}; + +int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta); + +struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn); + int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, int8_t use_trx, int8_t first_ts); @@ -270,9 +287,9 @@ int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len, uint32_t fn); int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, - uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, + uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling, - uint32_t poll_fn); + uint32_t fn, uint8_t single_block); void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index a1bed3c6..98ce1b4b 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -185,11 +185,61 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) return 0; } +static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap) +{ + int i; + + for (i = 0; i < cap->Count_MS_RA_capability_value; i++) { + if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability) + continue; + if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_GPRS_multislot_class) + continue; + return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.GPRS_multislot_class; + } + + return 0; +} + +static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, int8_t first_ts, + 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, ts; + struct gprs_rlcmac_tbf *tbf; + uint8_t tfi; + + /* create new TBF, use sme TRX as DL TBF */ + tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, use_trx, first_ts); + 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(dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 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) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; int8_t tfi = 0; /* must be signed */ uint32_t tlli = 0; struct gprs_rlcmac_tbf *tbf; @@ -318,34 +368,10 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, } /* check for channel request */ if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) { - uint8_t trx, ts; - struct gprs_rlcmac_tbf *ul_tbf; - LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack " "message, so we provide one:\n"); -uplink_request: - /* create new TBF, use sme TRX as DL TBF */ - tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, tbf->trx, tbf->first_ts); - if (tfi < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - break; - } - /* use multislot class of downlink TBF */ - ul_tbf = tbf_alloc(tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, - ts, tbf->ms_class, 0); - if (!ul_tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - break; - } - ul_tbf->tlli = tbf->tlli; - ul_tbf->tlli_valid = 1; /* no contention resolution */ - ul_tbf->dir.ul.contention_resolution_done = 1; - ul_tbf->ta = tbf->ta; /* use current TA */ - tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN); - ul_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH); - tbf_timer_start(ul_tbf, 3169, bts->t3169, 0); + + alloc_ul_tbf(tbf->trx, tbf->first_ts, tbf->ms_class, tbf->tlli, tbf->ta, tbf); /* schedule uplink assignment */ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; } @@ -355,7 +381,23 @@ uplink_request: tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI; tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); if (!tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TLLI=0x%08x\n", tlli); + uint8_t ms_class = 0; + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF " + "in packet ressource request of single " + "block, so we provide one:\n"); + if (ul_control_block->u.Packet_Resource_Request.Exist_MS_Radio_Access_capability) + 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, ts, ms_class, tlli, 0, NULL); +#warning FIXME TA!!! + if (!tbf) + break; + /* set control ts to current MS's TS, until assignment complete */ + LOGP(DRLCMAC, LOGL_DEBUG, "Change control TS to %d until assinment is complete.\n", ts); + tbf->control_ts = ts; + /* schedule uplink assignment */ + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; break; } tfi = tbf->tfi; @@ -658,11 +700,18 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, int final = (tbf->state == GPRS_RLCMAC_FINISHED); struct msgb *msg; - if (final && tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { - LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " - "sheduled for TBF=%d, so we must wait for final uplink " - "ack...\n", tbf->tfi); + if (final) { + if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { + LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " + "sheduled for TBF=%d, so we must wait for " + "final uplink ack...\n", tbf->tfi); return NULL; + } + if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) { + LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " + "scheduled for single block allocation...\n"); + return NULL; + } } msg = msgb_alloc(23, "rlcmac_ul_ack"); @@ -907,6 +956,11 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( "assignment...\n", tbf->tfi); return NULL; } + if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) { + LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for " + "single block allocation...\n"); + return NULL; + } #endif /* on down TBF we get the uplink TBF to be assigned. */ @@ -935,8 +989,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( bitvec_unhex(ass_vec, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); write_packet_uplink_assignment(ass_vec, tbf->tfi, - (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf, - POLLING_ASSIGNMENT_UL); + (tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli, + tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL); bitvec_pack(ass_vec, msgb_put(msg, 23)); RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); @@ -965,37 +1019,73 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) struct gprs_rlcmac_tbf *tbf; uint8_t trx, ts; int8_t tfi; /* must be signed */ + uint8_t sb = 0; + uint32_t sb_fn = 0; + int rc; + uint8_t plen; LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide " "one:\n"); - // Create new TBF - tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1); - if (tfi < 0) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - return -EBUSY; - } - /* set class to 0, since we don't know the multislot class yet */ - tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1); - if (!tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); - /* FIXME: send reject */ - return -EBUSY; + if ((ra & 0xf8) == 0x70) { + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block " + "allocation\n"); + sb = 1; + } else if (bts->force_two_phase) { + LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single phase access, " + "but we force two phase access\n"); + sb = 1; } if (qta < 0) qta = 0; if (qta > 252) qta = 252; - tbf->ta = qta >> 2; - tbf_new_state(tbf, GPRS_RLCMAC_FLOW); - tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH); - tbf_timer_start(tbf, 3169, bts->t3169, 0); - LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi); - LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26); - LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate Assignment Uplink (AGCH)\n", tbf->tfi); + if (sb) { + rc = sba_alloc(&trx, &ts, &sb_fn, qta >> 2); + if (rc < 0) + return rc; + LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] RACH qbit-ta=%d " + "ra=0x%02x, Fn=%d (%d,%d,%d)\n", qta, ra, Fn, + (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26); + LOGP(DRLCMAC, LOGL_INFO, "TX: Immediate Assignment Uplink " + "(AGCH)\n"); + } else { + // Create new TBF + tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1); + if (tfi < 0) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return -EBUSY; + } + /* set class to 0, since we don't know the multislot class yet */ + tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); + /* FIXME: send reject */ + return -EBUSY; + } + tbf->ta = qta >> 2; + tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH); + tbf_timer_start(tbf, 3169, bts->t3169, 0); + LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", + tbf->tfi); + LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH " + "qbit-ta=%d ra=0x%02x, Fn=%d (%d,%d,%d)\n", tbf->tfi, + qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26); + LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate " + "Assignment Uplink (AGCH)\n", tbf->tfi); + } bitvec *immediate_assignment = bitvec_alloc(22) /* without plen */; - bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); - int plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0); + bitvec_unhex(immediate_assignment, + "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); + if (sb) + plen = write_immediate_assignment(immediate_assignment, 0, ra, + Fn, qta >> 2, bts->trx[trx].arfcn, ts, + bts->trx[trx].pdch[ts].tsc, 0, 0, 0, 0, sb_fn, 1); + else + plen = write_immediate_assignment(immediate_assignment, 0, ra, + Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, + tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0, 0); pcu_l1if_tx_agch(immediate_assignment, plen); bitvec_free(immediate_assignment); @@ -1355,6 +1445,10 @@ tx_block: LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be " "sheduled in this TS %d, waiting for " "TS %d\n", ts, tbf->control_ts); + else if (sba_find(tbf->trx, ts, (fn + 13) % 2715648)) + LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be " + "sheduled, because single block alllocation " + "already exists\n"); else { LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this " "TS %d\n", ts); @@ -1534,6 +1628,11 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( "assignment...\n", tbf->tfi); return NULL; } + if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) { + LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " + "scheduled for single block allocation...\n"); + return NULL; + } } /* on uplink TBF we get the downlink TBF to be assigned. */ @@ -1604,7 +1703,7 @@ static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll, bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); /* use request reference that has maximum distance to current time, * so the assignment will not conflict with possible RACH requests. */ - int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn); + int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn, 0); pcu_l1if_tx_pch(immediate_assignment, plen, imsi); bitvec_free(immediate_assignment); } diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index 9ffdfb64..b5deeb0e 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -67,6 +67,26 @@ uint32_t sched_poll(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr, return poll_fn; } +uint32_t sched_sba(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr) +{ + uint32_t sba_fn; + struct gprs_rlcmac_sba *sba; + + /* check special TBF for events */ + sba_fn = fn + 4; + if ((block_nr % 3) == 2) + sba_fn ++; + sba_fn = sba_fn % 2715648; + sba = sba_find(trx, ts, sba_fn); + if (sba) { + llist_del(&sba->list); + talloc_free(sba); + return sba_fn; + } + + return 0xffffffff; +} + uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr, struct gprs_rlcmac_pdch *pdch) { @@ -135,14 +155,15 @@ struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn, return msg; } /* schedule PACKET PAGING REQUEST */ - if (llist_empty(&pdch->paging_list)) - return NULL; - msg = gprs_rlcmac_send_packet_paging_request(pdch); - if (msg) + if (!llist_empty(&pdch->paging_list)) + msg = gprs_rlcmac_send_packet_paging_request(pdch); + if (msg) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request " "message at RTS for (TRX=%d, TS=%d)\n", trx, ts); + return msg; + } - return msg; + return NULL; } struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn, @@ -208,7 +229,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, *ul_ass_tbf = NULL, *ul_ack_tbf = NULL; uint8_t usf = 0x7; struct msgb *msg = NULL; - uint32_t poll_fn; + uint32_t poll_fn, sba_fn; if (trx >= 8 || ts >= 8) return -EINVAL; @@ -234,6 +255,13 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, (poll_tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", poll_tbf->tfi); /* use free USF */ + /* else. check for sba */ + else if ((sba_fn = sched_sba(trx, ts, fn, block_nr) != 0xffffffff)) + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " + "TS=%d FN=%d block_nr=%d scheduling free USF for " + "single block allocation at FN=%d\n", trx, ts, fn, + block_nr, sba_fn); + /* use free USF */ /* else, we search for uplink ressource */ else usf = sched_select_uplink(trx, ts, fn, block_nr, pdch); diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index e5fbad98..2ed023a3 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -247,11 +247,12 @@ static int pcu_rx_rach_ind(struct gsm_pcu_if_rach_ind *rach_ind) return rc; } -int flush_pdch(struct gprs_rlcmac_pdch *pdch) +int flush_pdch(struct gprs_rlcmac_pdch *pdch, uint8_t trx, uint8_t ts) { uint8_t tfi; struct gprs_rlcmac_tbf *tbf; struct gprs_rlcmac_paging *pag; + struct gprs_rlcmac_sba *sba, *sba2; /* kick all TBF on slot */ for (tfi = 0; tfi < 32; tfi++) { @@ -266,6 +267,13 @@ int flush_pdch(struct gprs_rlcmac_pdch *pdch) while ((pag = gprs_rlcmac_dequeue_paging(pdch))) talloc_free(pag); + llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) { + if (sba->trx == trx && sba->ts == ts) { + llist_del(&sba->list); + talloc_free(sba); + } + } + return 0; } @@ -294,7 +302,8 @@ bssgp_failed: bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; for (ts = 0; ts < 8; ts++) { if (bts->trx[trx].pdch[ts].enable) - flush_pdch(&bts->trx[trx].pdch[ts]); + flush_pdch(&bts->trx[trx].pdch[ts], + trx, ts); } } gprs_bssgp_destroy(); @@ -399,7 +408,7 @@ bssgp_failed: if (pdch->enable) { pcu_tx_act_req(trx, ts, 0); pdch->enable = 0; - flush_pdch(pdch); + flush_pdch(pdch, trx, ts); } } } diff --git a/src/pcu_vty.c b/src/pcu_vty.c index e5d37658..39a1b722 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -90,6 +90,8 @@ static int config_write_pcu(struct vty *vty) vty_out(vty, " alloc-algorithm a%s", VTY_NEWLINE); if (bts->alloc_algorithm == alloc_algorithm_b) vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE); + if (bts->force_two_phase) + vty_out(vty, " two-phase-access%s", VTY_NEWLINE); } @@ -193,6 +195,30 @@ DEFUN(cfg_pcu_alloc, return CMD_SUCCESS; } +DEFUN(cfg_pcu_two_phase, + cfg_pcu_two_phase_cmd, + "two-phase-access", + "Force two phase access when MS requests single phase access\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->force_two_phase = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_no_two_phase, + cfg_pcu_no_two_phase_cmd, + "no two-phase-access", + NO_STR "Only use two phase access when requested my MS\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->force_two_phase = 0; + + return CMD_SUCCESS; +} + static const char pcu_copyright[] = "Copyright (C) 2012 by ...\r\n" "License GNU GPL version 2 or later\r\n" @@ -222,6 +248,8 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd); install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd); install_element(PCU_NODE, &cfg_pcu_alloc_cmd); + install_element(PCU_NODE, &cfg_pcu_two_phase_cmd); + install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd); install_element(PCU_NODE, &ournode_end_cmd); return 0; -- cgit v1.2.3 From adb2f185387fd2d6a40a8bdceb336132f8dd19ca Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Tue, 7 Aug 2012 17:06:08 +0200 Subject: Assign TFI to complete TRX, not just one TS This is required, since we may change slot allocation. In case of a change, we do not want to be unable to change, if the same TFI on one of the other slots is already in use by a different TBF (having same TFI, but on different slot). --- src/gprs_rlcmac.cpp | 81 +++++++++++++++--------------------------------- src/gprs_rlcmac.h | 4 ++- src/gprs_rlcmac_data.cpp | 6 ++-- src/sysmo_sock.cpp | 17 +++++----- 4 files changed, 39 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 1aeb9b18..cfd3ad9f 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -120,9 +120,9 @@ int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts, LOGP(DRLCMAC, LOGL_DEBUG, "Searching for first unallocated TFI: " "TRX=%d first TS=%d\n", trx, ts); if (dir == GPRS_RLCMAC_UL_TBF) - tbfp = pdch->ul_tbf; + tbfp = bts->trx[trx].ul_tbf; else - tbfp = pdch->dl_tbf; + tbfp = bts->trx[trx].dl_tbf; for (tfi = 0; tfi < 32; tfi++) { if (!tbfp[tfi]) break; @@ -163,19 +163,19 @@ static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch, uint8_t ts) } /* lookup TBF Entity (by TFI) */ -struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, +struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir) { struct gprs_rlcmac_tbf *tbf; struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - if (tfi >= 32 || trx >= 8 || ts >= 8) + if (tfi >= 32 || trx >= 8) return NULL; if (dir == GPRS_RLCMAC_UL_TBF) - tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; + tbf = bts->trx[trx].ul_tbf[tfi]; else - tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; + tbf = bts->trx[trx].dl_tbf[tfi]; if (!tbf) return NULL; @@ -312,38 +312,24 @@ int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, } tbf->tsc = pdch->tsc; if (tbf->direction == GPRS_RLCMAC_UL_TBF) { - /* if TFI is free on TS */ - if (!pdch->ul_tbf[tbf->tfi]) { - /* if USF available */ - usf = find_free_usf(pdch, ts); - if (usf >= 0) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink " - "TS=%d USF=%d\n", ts, usf); - pdch->ul_tbf[tbf->tfi] = tbf; - tbf->pdch[ts] = pdch; - } else { - LOGP(DRLCMAC, LOGL_NOTICE, "- Failed " - "allocating TS=%d, no USF available\n", - ts); - return -EBUSY; - } - } else { - LOGP(DRLCMAC, LOGL_NOTICE, "- Failed allocating " - "TS=%d, TFI is not available\n", ts); - return -EBUSY; - } - } else { - /* if TFI is free on TS */ - if (!pdch->dl_tbf[tbf->tfi]) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d\n", - ts); - pdch->dl_tbf[tbf->tfi] = tbf; + /* if USF available */ + usf = find_free_usf(pdch, ts); + if (usf >= 0) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink " + "TS=%d USF=%d\n", ts, usf); + bts->trx[tbf->trx].ul_tbf[tbf->tfi] = tbf; + pdch->ul_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; } else { - LOGP(DRLCMAC, LOGL_NOTICE, "- Failed allocating " - "TS=%d, TFI is not available\n", ts); + LOGP(DRLCMAC, LOGL_NOTICE, "- Failed " + "allocating TS=%d, no USF available\n", ts); return -EBUSY; } + } else { + LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d\n", ts); + bts->trx[tbf->trx].dl_tbf[tbf->tfi] = tbf; + pdch->dl_tbf[tbf->tfi] = tbf; + tbf->pdch[ts] = pdch; } /* the only one TS is the common TS */ tbf->first_common_ts = ts; @@ -474,18 +460,6 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, i++; continue; } - /* check if TFI for slot is available - * This is only possible for downlink TFI. */ - if (tbf->direction == GPRS_RLCMAC_DL_TBF - && pdch->dl_tbf[tbf->tfi]) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because " - "already assigned to other DL TBF with " - "TFI=%d\n", ts, tbf->tfi); - /* increase window for Type 1 */ - if (Type == 1) - i++; - continue; - } rx_window |= (1 << ts); LOGP(DRLCMAC, LOGL_DEBUG, "- Selected DL TS %d\n", ts); @@ -634,16 +608,6 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, i++; continue; } - /* check if TFI for slot is available */ - if (pdch->ul_tbf[tbf->tfi]) { - LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, " - "because already assigned to other " - "UL TBF with TFI=%d\n", ts, tbf->tfi); - /* increase window for Type 1 */ - if (Type == 1) - i++; - continue; - } /* check for free usf */ usf[ts] = find_free_usf(pdch, ts); if (usf[ts] < 0) { @@ -703,6 +667,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS " "%d\n", ts); pdch = &bts->trx[tbf->trx].pdch[ts]; + bts->trx[tbf->trx].dl_tbf[tbf->tfi] = tbf; pdch->dl_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; slotcount++; @@ -723,6 +688,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS " "%d\n", ts); pdch = &bts->trx[tbf->trx].pdch[ts]; + bts->trx[tbf->trx].ul_tbf[tbf->tfi] = tbf; pdch->ul_tbf[tbf->tfi] = tbf; tbf->pdch[ts] = pdch; tbf->dir.ul.usf[ts] = usf[ts]; @@ -739,10 +705,12 @@ int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; int ts; if (tbf->direction == GPRS_RLCMAC_UL_TBF) { + bts->trx[tbf->trx].ul_tbf[tbf->tfi] = NULL; for (ts = 0; ts < 8; ts++) { pdch = tbf->pdch[ts]; if (pdch) @@ -750,6 +718,7 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf) tbf->pdch[ts] = NULL; } } else { + bts->trx[tbf->trx].dl_tbf[tbf->tfi] = NULL; for (ts = 0; ts < 8; ts++) { pdch = tbf->pdch[ts]; if (pdch) diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 5890bf06..a5ac7750 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -57,6 +57,8 @@ struct gprs_rlcmac_pdch { struct gprs_rlcmac_trx { uint16_t arfcn; struct gprs_rlcmac_pdch pdch[8]; + struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */ + struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */ }; struct gprs_rlcmac_bts { @@ -253,7 +255,7 @@ struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t ms_class, uint8_t single_slot); -struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts, +struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir); struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 98ce1b4b..265aed6a 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -404,14 +404,14 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, } else { if (ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.UnionType) { tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.DOWNLINK_TFI; - tbf = tbf_by_tfi(tfi, trx, ts, GPRS_RLCMAC_DL_TBF); + tbf = tbf_by_tfi(tfi, trx, GPRS_RLCMAC_DL_TBF); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown downlink TBF=%d\n", tlli); break; } } else { tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.UPLINK_TFI; - tbf = tbf_by_tfi(tfi, trx, ts, GPRS_RLCMAC_UL_TBF); + tbf = tbf_by_tfi(tfi, trx, GPRS_RLCMAC_UL_TBF); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TBF=%d\n", tlli); break; @@ -782,7 +782,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, } /* find TBF inst from given TFI */ - tbf = tbf_by_tfi(rh->tfi, trx, ts, GPRS_RLCMAC_UL_TBF); + tbf = tbf_by_tfi(rh->tfi, trx, GPRS_RLCMAC_UL_TBF); if (!tbf) { LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TBF=%d\n", rh->tfi); diff --git a/src/sysmo_sock.cpp b/src/sysmo_sock.cpp index 6b390edc..e3b95168 100644 --- a/src/sysmo_sock.cpp +++ b/src/sysmo_sock.cpp @@ -94,16 +94,15 @@ static void pcu_sock_close(struct pcu_sock_state *state) /* disable all slots, kick all TBFs */ for (trx = 0; trx < 8; trx++) { - for (ts = 0; ts < 8; ts++) { + for (ts = 0; ts < 8; ts++) bts->trx[trx].pdch[ts].enable = 0; - for (tfi = 0; tfi < 32; tfi++) { - tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi]; - if (tbf) - tbf_free(tbf); - tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi]; - if (tbf) - tbf_free(tbf); - } + for (tfi = 0; tfi < 32; tfi++) { + tbf = bts->trx[trx].ul_tbf[tfi]; + if (tbf) + tbf_free(tbf); + tbf = bts->trx[trx].dl_tbf[tfi]; + if (tbf) + tbf_free(tbf); } } -- cgit v1.2.3 From 4b39dd1c00ee5b835bd83161e8d66a0eb796a8c9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 23 Sep 2012 05:03:56 +0200 Subject: Replace local definitions by header gprs_bssgp_bss.h --- src/gprs_bssgp_pcu.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h index 7d5f3767..2d661886 100644 --- a/src/gprs_bssgp_pcu.h +++ b/src/gprs_bssgp_pcu.h @@ -29,17 +29,14 @@ extern "C" { #include #include #include +#include #include -int bssgp_tx_bvc_reset(struct bssgp_bvc_ctx *bctx, uint16_t bvci, uint8_t cause); - -int bssgp_tx_ul_ud(struct bssgp_bvc_ctx *bctx, uint32_t tlli, const uint8_t *qos_profile, struct msgb *llc_pdu); - struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei); } #include -#define QOS_PROFILE 0 +#define QOS_PROFILE 4 #define BSSGP_HDR_LEN 53 #define NS_HDR_LEN 4 #define IE_LLC_PDU 14 -- cgit v1.2.3 From cd8a83a42c44a749a801cb53ec8e9888fcd153d0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 23 Sep 2012 06:41:21 +0200 Subject: Statefull reset and unblock BVCs and sending flow control messages The flow control interval can be set via VTY. --- src/gprs_bssgp_pcu.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++--- src/gprs_rlcmac.h | 1 + src/pcu_main.cpp | 1 + src/pcu_vty.c | 18 ++++++++++- 4 files changed, 97 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 374baf63..020df616 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -25,8 +25,13 @@ struct sgsn_instance *sgsn; void *tall_bsc_ctx; struct bssgp_bvc_ctx *bctx = NULL; struct gprs_nsvc *nsvc = NULL; +static int bvc_sig_reset = 0, bvc_reset = 0, bvc_unblocked = 0; extern uint16_t spoof_mcc, spoof_mnc; +struct osmo_timer_list bvc_timer; + +static void bvc_timeout(void *_priv); + int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) { struct bssgp_ud_hdr *budh; @@ -295,6 +300,11 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp break; case BSSGP_PDUT_BVC_RESET_ACK: LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_RESET_ACK\n"); + if (!bvc_sig_reset) + bvc_sig_reset = 1; + else + bvc_reset = 1; + bvc_timeout(NULL); break; case BSSGP_PDUT_PAGING_PS: LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_PS\n"); @@ -316,6 +326,8 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp break; case BSSGP_PDUT_BVC_UNBLOCK_ACK: LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n"); + bvc_unblocked = 1; + bvc_timeout(NULL); break; case BSSGP_PDUT_SGSN_INVOKE_TRACE: LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n"); @@ -362,7 +374,9 @@ int gprs_bssgp_pcu_rcvmsg(struct msgb *msg) /* look-up or create the BTS context for this BVC */ bctx = btsctx_by_bvci_nsei(ns_bvci, msgb_nsei(msg)); - if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET_ACK) + if (!bctx + && pdu_type != BSSGP_PDUT_BVC_RESET_ACK + && pdu_type != BSSGP_PDUT_BVC_UNBLOCK_ACK) { LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU " "type %u for unknown BVCI\n", msgb_nsei(msg), ns_bvci, @@ -438,14 +452,22 @@ static int nsvc_signal_cb(unsigned int subsys, unsigned int signal, case S_NS_UNBLOCK: if (!nsvc_unblocked) { nsvc_unblocked = 1; - LOGP(DPCU, LOGL_NOTICE, "NS-VC is unblocked.\n"); - bssgp_tx_bvc_reset(bctx, bctx->bvci, - BSSGP_CAUSE_PROTO_ERR_UNSPEC); + LOGP(DPCU, LOGL_NOTICE, "NS-VC %d is unblocked.\n", + nsvc); + bvc_sig_reset = 0; + bvc_reset = 0; + bvc_unblocked = 0; + bvc_timeout(NULL); } break; case S_NS_BLOCK: if (nsvc_unblocked) { nsvc_unblocked = 0; + if (osmo_timer_pending(&bvc_timer)) + osmo_timer_del(&bvc_timer); + bvc_sig_reset = 0; + bvc_reset = 0; + bvc_unblocked = 0; LOGP(DPCU, LOGL_NOTICE, "NS-VC is blocked.\n"); } break; @@ -454,6 +476,52 @@ static int nsvc_signal_cb(unsigned int subsys, unsigned int signal, return 0; } +int gprs_bssgp_tx_fc_bvc(void) +{ + if (!bctx) { + LOGP(DBSSGP, LOGL_ERROR, "No bctx\n"); + return -EIO; + } + /* FIXME: use real values */ + return bssgp_tx_fc_bvc(bctx, 1, 6553500, 819100, 50000, 50000, + NULL, NULL); +// return bssgp_tx_fc_bvc(bctx, 1, 84000, 25000, 48000, 45000, +// NULL, NULL); +} + +static void bvc_timeout(void *_priv) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + if (!bvc_sig_reset) { + LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI 0\n"); + bssgp_tx_bvc_reset(bctx, 0, BSSGP_CAUSE_OML_INTERV); + osmo_timer_schedule(&bvc_timer, 1, 0); + return; + } + + if (!bvc_reset) { + LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI %d\n", + bctx->bvci); + bssgp_tx_bvc_reset(bctx, bctx->bvci, BSSGP_CAUSE_OML_INTERV); + osmo_timer_schedule(&bvc_timer, 1, 0); + return; + } + + if (!bvc_unblocked) { + LOGP(DBSSGP, LOGL_INFO, "Sending unblock on BVCI %d\n", + bctx->bvci); + bssgp_tx_bvc_unblock(bctx); + osmo_timer_schedule(&bvc_timer, 1, 0); + return; + } + + LOGP(DBSSGP, LOGL_DEBUG, "Sending flow control info on BVCI %d\n", + bctx->bvci); + gprs_bssgp_tx_fc_bvc(); + osmo_timer_schedule(&bvc_timer, bts->fc_interval, 0); +} + /* create BSSGP/NS layer instances */ int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac, @@ -501,6 +569,9 @@ int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, // bssgp_tx_bvc_reset(bctx, bctx->bvci, BSSGP_CAUSE_PROTO_ERR_UNSPEC); + bvc_timer.cb = bvc_timeout; + + return 0; } @@ -509,6 +580,9 @@ void gprs_bssgp_destroy(void) if (!bssgp_nsi) return; + if (osmo_timer_pending(&bvc_timer)) + osmo_timer_del(&bvc_timer); + osmo_signal_unregister_handler(SS_L_NS, nsvc_signal_cb, NULL); nsvc = NULL; diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index a5ac7750..e7a68a4f 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -62,6 +62,7 @@ struct gprs_rlcmac_trx { }; struct gprs_rlcmac_bts { + uint8_t fc_interval; uint8_t cs1; uint8_t cs2; uint8_t cs3; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d7e8ffc..2392152a 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -142,6 +142,7 @@ int main(int argc, char *argv[]) if (!gprs_rlcmac_bts) return -ENOMEM; gprs_rlcmac_bts->initial_cs = 1; + bts->fc_interval = 1; bts->initial_cs = 1; bts->cs1 = 1; bts->t3142 = 20; diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 39a1b722..8d5b47b1 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -79,6 +79,8 @@ static int config_write_pcu(struct vty *vty) struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; vty_out(vty, "pcu%s", VTY_NEWLINE); + vty_out(vty, " flow-control-interval %d%s", bts->fc_interval, + VTY_NEWLINE); if (bts->force_cs) vty_out(vty, " cs %d%s", bts->initial_cs, VTY_NEWLINE); if (bts->force_llc_lifetime == 0xffff) @@ -106,6 +108,19 @@ DEFUN(cfg_pcu, return CMD_SUCCESS; } +DEFUN(cfg_pcu_fc_interval, + cfg_pcu_fc_interval_cmd, + "flow-control-interval <1..10>", + "Interval between sending subsequent Flow Control PDUs\n" + "Tiem in seconds\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->fc_interval = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_pcu_cs, cfg_pcu_cs_cmd, "cs <1-4>", @@ -242,6 +257,7 @@ int pcu_vty_init(const struct log_info *cat) install_node(&pcu_node, config_write_pcu); install_element(CONFIG_NODE, &cfg_pcu_cmd); install_default(PCU_NODE); + install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd); install_element(PCU_NODE, &cfg_pcu_cs_cmd); install_element(PCU_NODE, &cfg_pcu_no_cs_cmd); install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd); @@ -249,7 +265,7 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd); install_element(PCU_NODE, &cfg_pcu_alloc_cmd); install_element(PCU_NODE, &cfg_pcu_two_phase_cmd); - install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd); + install_element(PCU_NODE, &cfg_pcu_fc_interval_cmd); install_element(PCU_NODE, &ournode_end_cmd); return 0; -- cgit v1.2.3 From 514491d726008b45d3caaa8fb36e55bc2ff8311b Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 23 Sep 2012 06:42:07 +0200 Subject: Fix: Correctly interpret MCC, MNC, CELL ID from BTS --- src/gprs_bssgp_pcu.cpp | 4 ++++ src/pcu_l1_if.cpp | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 020df616..12d45825 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -529,6 +529,10 @@ int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, { struct sockaddr_in dest; + mcc = ((mcc & 0xf00) >> 8) * 100 + ((mcc & 0x0f0) >> 4) * 10 + (mcc & 0x00f); + mnc = ((mnc & 0xf00) >> 8) * 100 + ((mnc & 0x0f0) >> 4) * 10 + (mnc & 0x00f); + cell_id = ntohs(cell_id); + if (bctx) return 0; /* if already created, must return 0: no error */ diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 2ed023a3..1eeacfaf 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -310,11 +310,11 @@ bssgp_failed: return 0; } LOGP(DL1IF, LOGL_INFO, "BTS available\n"); - LOGP(DL1IF, LOGL_DEBUG, " mcc=%d\n", info_ind->mcc); - LOGP(DL1IF, LOGL_DEBUG, " mnc=%d\n", info_ind->mnc); + LOGP(DL1IF, LOGL_DEBUG, " mcc=%x\n", info_ind->mcc); + LOGP(DL1IF, LOGL_DEBUG, " mnc=%x\n", info_ind->mnc); LOGP(DL1IF, LOGL_DEBUG, " lac=%d\n", info_ind->lac); LOGP(DL1IF, LOGL_DEBUG, " rac=%d\n", info_ind->rac); - LOGP(DL1IF, LOGL_DEBUG, " cell_id=%d\n", info_ind->cell_id); + LOGP(DL1IF, LOGL_DEBUG, " cell_id=%d\n", ntohs(info_ind->cell_id)); LOGP(DL1IF, LOGL_DEBUG, " nsei=%d\n", info_ind->nsei); LOGP(DL1IF, LOGL_DEBUG, " nse_timer=%d %d %d %d %d %d %d\n", info_ind->nse_timer[0], info_ind->nse_timer[1], -- cgit v1.2.3 From 9a91346fa12b93e1dbfc0c5d07c28061bd71545f Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 23 Sep 2012 06:42:38 +0200 Subject: Fix: Send correct QOS profile and DL-UNITDATA IE to SGSN Be sure to use always two bytes of length information for DL-UNITDATA, even if the length of LLC data is less than 128 bytes. This way the data has always the same offset from a 32 bit boundary. --- src/gprs_rlcmac.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index cfd3ad9f..f7ec8477 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -1512,7 +1512,7 @@ unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len, /* Send Uplink unit-data to SGSN. */ int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf) { - const uint8_t qos_profile = QOS_PROFILE; + uint8_t qos_profile[3]; struct msgb *llc_pdu; unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + tbf->llc_index; @@ -1523,8 +1523,12 @@ int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf) } llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu"); - msgb_tvlv_push(llc_pdu, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*tbf->llc_index, tbf->llc_frame); - bssgp_tx_ul_ud(bctx, tbf->tlli, &qos_profile, llc_pdu); + uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*tbf->llc_index)); + tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*tbf->llc_index, tbf->llc_frame); + qos_profile[0] = QOS_PROFILE >> 16; + qos_profile[1] = QOS_PROFILE >> 8; + qos_profile[2] = QOS_PROFILE; + bssgp_tx_ul_ud(bctx, tbf->tlli, qos_profile, llc_pdu); return 0; } -- cgit v1.2.3 From df4d20e95bd7a065aa9d27b97ed9743e618496f1 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 24 Sep 2012 13:49:38 +0200 Subject: Fix: T3193 is now started with the correct value --- src/gprs_rlcmac_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 265aed6a..8bb1df65 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -1585,7 +1585,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, "release.\n"); /* start T3193 */ tbf_timer_start(tbf, 3193, bts->t3193_msec / 1000, - bts->t3193_msec & 1000); + (bts->t3193_msec % 1000) * 1000); tbf_new_state(tbf, GPRS_RLCMAC_WAIT_RELEASE); return 0; -- cgit v1.2.3 From aafcbbb252dfff7a627ed45706c3b2f99f0729a5 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 27 Sep 2012 09:20:45 +0200 Subject: Set Alpha and Gamma at assingment messages for power control The initial power control value Alpha must be set in SI13. --- src/gprs_rlcmac.cpp | 48 ++++++++++++++++++++++++++++++++++-------------- src/gprs_rlcmac.h | 9 ++++++--- src/gprs_rlcmac_data.cpp | 21 ++++++++++++++++----- src/pcu_main.cpp | 1 + src/pcu_vty.c | 35 +++++++++++++++++++++++++++++++++-- 5 files changed, 90 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index f7ec8477..64bbe75f 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -1161,7 +1161,8 @@ struct msgb *gprs_rlcmac_send_packet_paging_request( int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t tfi, uint8_t usf, uint32_t tlli, - uint8_t polling, uint32_t fn, uint8_t single_block) + uint8_t polling, uint32_t fn, uint8_t single_block, uint8_t alpha, + uint8_t gamma) { unsigned wp = 0; uint8_t plen; @@ -1215,8 +1216,13 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, bitvec_write_field(dest, wp,0x1,1); // switch TFI : on bitvec_write_field(dest, wp,tfi,5); // TFI bitvec_write_field(dest, wp,0x0,1); // RLC acknowledged mode - bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present - bitvec_write_field(dest, wp,0x0,5); // GAMMA power control parameter + if (alpha) { + bitvec_write_field(dest, wp,0x1,1); // ALPHA = present + bitvec_write_field(dest, wp,alpha,4); // ALPHA + } else { + bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present + } + bitvec_write_field(dest, wp,gamma,5); // GAMMA power control parameter bitvec_write_field(dest, wp,polling,1); // Polling Bit bitvec_write_field(dest, wp,!polling,1); // TA_VALID ??? bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on @@ -1241,9 +1247,12 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment if (single_block) { bitvec_write_field(dest, wp, 0, 1); // Block Allocation : Single Block Allocation - bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present - bitvec_write_field(dest, wp, 0, 4); // Alpha - bitvec_write_field(dest, wp, 0, 5); // Gamma + if (alpha) { + bitvec_write_field(dest, wp,0x1,1); // ALPHA = present + bitvec_write_field(dest, wp,alpha,4); // ALPHA = present + } else + bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present + bitvec_write_field(dest, wp,gamma,5); // GAMMA power control parameter bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG bitvec_write_field(dest, wp, 1, 1); // TBF_STARTING_TIME_FLAG bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1' @@ -1259,9 +1268,12 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, bitvec_write_field(dest, wp, 0, 1); // "0" power control: Not Present bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING - bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present - bitvec_write_field(dest, wp, 0, 4); // Alpha - bitvec_write_field(dest, wp, 0, 5); // Gamma + if (alpha) { + bitvec_write_field(dest, wp,0x1,1); // ALPHA = present + bitvec_write_field(dest, wp,alpha,4); // ALPHA + } else + bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present + bitvec_write_field(dest, wp,gamma,5); // GAMMA power control parameter bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG } @@ -1273,7 +1285,8 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, /* generate uplink assignment */ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, - struct gprs_rlcmac_tbf *tbf, uint8_t poll) + struct gprs_rlcmac_tbf *tbf, uint8_t poll, uint8_t alpha, + uint8_t gamma) { // TODO We should use our implementation of encode RLC/MAC Control messages. struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; @@ -1326,12 +1339,18 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, bitvec_write_field(dest, wp,0x0,1); // bitvec_write_field(dest, wp,0x0,1); // TBF Starting Time = off - bitvec_write_field(dest, wp,0x0,1); // Timeslot Allocation + if (alpha || gamma) { + bitvec_write_field(dest, wp,0x1,1); // Timeslot Allocation with Power Control + bitvec_write_field(dest, wp,alpha,4); // ALPHA + } else + bitvec_write_field(dest, wp,0x0,1); // Timeslot Allocation for (ts = 0; ts < 8; ts++) { if (tbf->pdch[ts]) { bitvec_write_field(dest, wp,0x1,1); // USF_TN(i): on bitvec_write_field(dest, wp,tbf->dir.ul.usf[ts],3); // USF_TN(i) + if (alpha || gamma) + bitvec_write_field(dest, wp,gamma,5); // GAMMA power control parameter } else bitvec_write_field(dest, wp,0x0,1); // USF_TN(i): off } @@ -1341,7 +1360,8 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, /* generate downlink assignment */ void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi, - uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll) + uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll, + uint8_t alpha, uint8_t gamma) { // Packet downlink assignment TS 44.060 11.2.7 @@ -1385,14 +1405,14 @@ void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi, block->u.Packet_Downlink_Assignment.DOWNLINK_TFI_ASSIGNMENT = tbf->tfi; // TFI block->u.Packet_Downlink_Assignment.Exist_Power_Control_Parameters = 0x1; // Power Control Parameters = on - block->u.Packet_Downlink_Assignment.Power_Control_Parameters.ALPHA = 0x0; // ALPHA + block->u.Packet_Downlink_Assignment.Power_Control_Parameters.ALPHA = alpha; // ALPHA for (tn = 0; tn < 8; tn++) { if (tbf->pdch[tn]) { block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x1; // Slot[i] = on - block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].GAMMA_TN = 0x0; // GAMMA_TN + block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].GAMMA_TN = gamma; // GAMMA_TN } else { diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index e7a68a4f..46439911 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -83,6 +83,7 @@ struct gprs_rlcmac_bts { struct gprs_rlcmac_tbf *tbf, uint32_t cust); uint32_t alloc_algorithm_curst; /* options to customize algorithm */ uint8_t force_two_phase; + uint8_t alpha, gamma; }; extern struct gprs_rlcmac_bts *gprs_rlcmac_bts; @@ -292,14 +293,16 @@ int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len, int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling, - uint32_t fn, uint8_t single_block); + uint32_t fn, uint8_t single_block, uint8_t alpha, uint8_t gamma); void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, - struct gprs_rlcmac_tbf *tbf, uint8_t poll); + struct gprs_rlcmac_tbf *tbf, uint8_t poll, uint8_t alpha, + uint8_t gamma); void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi, - uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll); + uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll, + uint8_t alpha, uint8_t gamma); diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 8bb1df65..b6d50622 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -946,6 +946,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, struct msgb *gprs_rlcmac_send_packet_uplink_assignment( struct gprs_rlcmac_tbf *tbf, uint32_t fn) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct msgb *msg; struct gprs_rlcmac_tbf *new_tbf; @@ -990,7 +991,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment( "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); write_packet_uplink_assignment(ass_vec, tbf->tfi, (tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli, - tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL); + tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL, bts->alpha, + bts->gamma); bitvec_pack(ass_vec, msgb_put(msg, 23)); RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); @@ -1081,11 +1083,13 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) if (sb) plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, qta >> 2, bts->trx[trx].arfcn, ts, - bts->trx[trx].pdch[ts].tsc, 0, 0, 0, 0, sb_fn, 1); + bts->trx[trx].pdch[ts].tsc, 0, 0, 0, 0, sb_fn, 1, + bts->alpha, bts->gamma); else plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, - tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0, 0); + tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0, 0, + bts->alpha, bts->gamma); pcu_l1if_tx_agch(immediate_assignment, plen); bitvec_free(immediate_assignment); @@ -1611,6 +1615,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, struct msgb *gprs_rlcmac_send_packet_downlink_assignment( struct gprs_rlcmac_tbf *tbf, uint32_t fn) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct msgb *msg; struct gprs_rlcmac_tbf *new_tbf; int poll_ass_dl = POLLING_ASSIGNMENT_DL; @@ -1670,7 +1675,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); write_packet_downlink_assignment(mac_control_block, tbf->tfi, (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf, - poll_ass_dl); + poll_ass_dl, bts->alpha, bts->gamma); LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n"); encode_gsm_rlcmac_downlink(ass_vec, mac_control_block); LOGPC(DCSN1, LOGL_NOTICE, "\n"); @@ -1698,12 +1703,18 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment( static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll, char *imsi) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + int plen; + LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u TLLI: 0x%08x Immediate Assignment Downlink (PCH)\n", tbf->tfi, tbf->tlli); bitvec *immediate_assignment = bitvec_alloc(22); /* without plen */ bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); /* use request reference that has maximum distance to current time, * so the assignment will not conflict with possible RACH requests. */ - int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn, 0); + plen = write_immediate_assignment(immediate_assignment, 1, 125, + (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, + tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, + tbf->poll_fn, 0, bts->alpha, bts->gamma); pcu_l1if_tx_pch(immediate_assignment, plen, imsi); bitvec_free(immediate_assignment); } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2392152a..ba31ca7e 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -153,6 +153,7 @@ int main(int argc, char *argv[]) bts->n3101 = 10; bts->n3103 = 4; bts->n3105 = 8; + bts->alpha = 10; /* a = 1.0 */ msgb_set_talloc_ctx(tall_pcu_ctx); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 8d5b47b1..d7c2c2cd 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -94,6 +94,8 @@ static int config_write_pcu(struct vty *vty) vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE); if (bts->force_two_phase) vty_out(vty, " two-phase-access%s", VTY_NEWLINE); + vty_out(vty, " alpha %d%s", bts->alpha, VTY_NEWLINE); + vty_out(vty, " gamma %d%s", bts->gamma * 2, VTY_NEWLINE); } @@ -110,9 +112,9 @@ DEFUN(cfg_pcu, DEFUN(cfg_pcu_fc_interval, cfg_pcu_fc_interval_cmd, - "flow-control-interval <1..10>", + "flow-control-interval <1-10>", "Interval between sending subsequent Flow Control PDUs\n" - "Tiem in seconds\n") + "Interval time in seconds\n") { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; @@ -234,6 +236,33 @@ DEFUN(cfg_pcu_no_two_phase, return CMD_SUCCESS; } +DEFUN(cfg_pcu_alpha, + cfg_pcu_alpha_cmd, + "alpha <0-10>", + "Alpha parameter for MS power control in units of 0.1 (see TS 05.08) " + "NOTE: Be sure to set Alpha value at System information 13 too.\n" + "Alpha in units of 0.1\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->alpha = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_gamma, + cfg_pcu_gamma_cmd, + "gamma <0-62>", + "Gamma parameter for MS power control in units of dB (see TS 05.08)\n" + "Gamma in even unit of dBs\n") +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + bts->gamma = atoi(argv[0]) / 2; + + return CMD_SUCCESS; +} + static const char pcu_copyright[] = "Copyright (C) 2012 by ...\r\n" "License GNU GPL version 2 or later\r\n" @@ -266,6 +295,8 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_alloc_cmd); install_element(PCU_NODE, &cfg_pcu_two_phase_cmd); install_element(PCU_NODE, &cfg_pcu_fc_interval_cmd); + install_element(PCU_NODE, &cfg_pcu_alpha_cmd); + install_element(PCU_NODE, &cfg_pcu_gamma_cmd); install_element(PCU_NODE, &ournode_end_cmd); return 0; -- cgit v1.2.3 From 80be275710844e6791bee32f7d348f5e0aaa082f Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 27 Sep 2012 09:21:17 +0200 Subject: Fix: Dump correct NSVCI value at debug line --- src/gprs_bssgp_pcu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 12d45825..df7d37af 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -453,7 +453,7 @@ static int nsvc_signal_cb(unsigned int subsys, unsigned int signal, if (!nsvc_unblocked) { nsvc_unblocked = 1; LOGP(DPCU, LOGL_NOTICE, "NS-VC %d is unblocked.\n", - nsvc); + nsvc->nsvci); bvc_sig_reset = 0; bvc_reset = 0; bvc_unblocked = 0; -- cgit v1.2.3 From 99a107dbeef03b2e80aff82023cdfc5c10109b5b Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 27 Sep 2012 09:21:52 +0200 Subject: Free existing UL/DL TBF, if RACH has been received from MS In this case the mobile has lost existing flows, so it make sense to free them. The TFI(s) can be re-used immidiately, because they are not associated by MS anymore. --- src/gprs_rlcmac_data.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index b6d50622..dedf98a8 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -380,8 +380,25 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, if (ul_control_block->u.Packet_Resource_Request.ID.UnionType) { tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI; tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); + if (tbf) { + LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from " + "TLLI=0x%08x while UL TBF=%d still " + "exists. Killing pending DL TBF\n", + tlli, tbf->tfi); + tbf_free(tbf); + tbf = NULL; + } if (!tbf) { uint8_t ms_class = 0; + struct gprs_rlcmac_tbf *dl_tbf; + + if ((dl_tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) { + LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from " + "TLLI=0x%08x while DL TBF=%d still exists. " + "Killing pending DL TBF\n", tlli, + dl_tbf->tfi); + tbf_free(dl_tbf); + } LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF " "in packet ressource request of single " "block, so we provide one:\n"); -- cgit v1.2.3 From a9be1547b1b4459d64d92207da2a29e41fcb3ba2 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 27 Sep 2012 09:23:24 +0200 Subject: 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. --- src/gprs_bssgp_pcu.cpp | 4 ++- src/gprs_rlcmac.h | 7 ++++- src/gprs_rlcmac_data.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++----- src/gprs_rlcmac_sched.cpp | 4 +++ src/pcu_l1_if.cpp | 23 ++++++++++++++++ src/pcuif_proto.h | 4 ++- 6 files changed, 99 insertions(+), 10 deletions(-) (limited to 'src') 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; -- cgit v1.2.3 From a3c12fb6c5b1cdd4fb84e0ac18fc8820f79cf7fd Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 28 Sep 2012 22:46:33 +0200 Subject: Fix: Cleanly open and close NS instance --- src/gprs_bssgp_pcu.cpp | 9 ++++++++- src/sysmo_sock.cpp | 18 +++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 4b0255e3..7ec4ee89 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -530,6 +530,7 @@ int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, uint16_t rac, uint16_t cell_id) { struct sockaddr_in dest; + int rc; mcc = ((mcc & 0xf00) >> 8) * 100 + ((mcc & 0x0f0) >> 4) * 10 + (mcc & 0x00f); mnc = ((mnc & 0xf00) >> 8) * 100 + ((mnc & 0x0f0) >> 4) * 10 + (mnc & 0x00f); @@ -543,7 +544,13 @@ int gprs_bssgp_create(uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n"); return -EINVAL; } - gprs_ns_nsip_listen(bssgp_nsi); + rc = gprs_ns_nsip_listen(bssgp_nsi); + if (rc < 0) { + LOGP(DBSSGP, LOGL_ERROR, "Failed to create socket\n"); + gprs_ns_destroy(bssgp_nsi); + bssgp_nsi = NULL; + return -EINVAL; + } dest.sin_family = AF_INET; dest.sin_port = htons(sgsn_port); diff --git a/src/sysmo_sock.cpp b/src/sysmo_sock.cpp index e3b95168..c4565952 100644 --- a/src/sysmo_sock.cpp +++ b/src/sysmo_sock.cpp @@ -73,14 +73,15 @@ int pcu_sock_send(struct msgb *msg) return 0; } -static void pcu_sock_close(struct pcu_sock_state *state) +static void pcu_sock_close(struct pcu_sock_state *state, int lost) { struct osmo_fd *bfd = &state->conn_bfd; struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; uint8_t trx, ts, tfi; - LOGP(DL1IF, LOGL_NOTICE, "PCU socket has LOST connection\n"); + LOGP(DL1IF, LOGL_NOTICE, "PCU socket has %s connection\n", + (lost) ? "LOST" : "closed"); close(bfd->fd); bfd->fd = -1; @@ -108,8 +109,10 @@ static void pcu_sock_close(struct pcu_sock_state *state) gprs_bssgp_destroy(); - state->timer.cb = pcu_sock_timeout; - osmo_timer_schedule(&state->timer, 5, 0); + if (lost) { + state->timer.cb = pcu_sock_timeout; + osmo_timer_schedule(&state->timer, 5, 0); + } } static int pcu_sock_read(struct osmo_fd *bfd) @@ -145,7 +148,7 @@ static int pcu_sock_read(struct osmo_fd *bfd) close: msgb_free(msg); - pcu_sock_close(state); + pcu_sock_close(state, 1); return -1; } @@ -192,7 +195,7 @@ dontsend: return 0; close: - pcu_sock_close(state); + pcu_sock_close(state, 1); return -1; } @@ -256,6 +259,7 @@ int pcu_l1if_open(void) if (rc != 0) { LOGP(DL1IF, LOGL_ERROR, "Failed to Connect the PCU-SYSMO " "socket, delaying... '%s'\n", local.sun_path); + pcu_sock_state = state; close(bfd->fd); bfd->fd = -1; state->timer.cb = pcu_sock_timeout; @@ -295,7 +299,7 @@ void pcu_l1if_close(void) bfd = &state->conn_bfd; if (bfd->fd > 0) - pcu_sock_close(state); + pcu_sock_close(state, 0); talloc_free(state); pcu_sock_state = NULL; } -- cgit v1.2.3 From 5f14bd941074b978ff92594544a9b62f9c366984 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 3 Oct 2012 14:20:26 +0200 Subject: Fix: Poll correctly for downlink acknowlege, to prevent window stalling --- src/gprs_rlcmac_data.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 66d29c6d..147054e0 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -33,7 +33,7 @@ int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli, #define SEND_ACK_AFTER_FRAMES 20 /* After sending these frames, we poll for ack/nack. */ -#define POLL_ACK_AFTER_FRAMES 10 +#define POLL_ACK_AFTER_FRAMES 20 /* If acknowledgement to uplink/downlink assignmentshould be polled */ #define POLLING_ASSIGNMENT_DL 1 @@ -1212,6 +1212,7 @@ struct msgb *gprs_rlcmac_send_data_block_acknowledged( uint8_t *delimiter, *data, *e_pointer; uint8_t len; uint16_t space, chunk; + int first_fin_ack; LOGP(DRLCMACDL, LOGL_DEBUG, "DL DATA TBF=%d downlink (V(A)==%d .. " "V(S)==%d)\n", tbf->tfi, tbf->dir.dl.v_a, tbf->dir.dl.v_s); @@ -1428,7 +1429,7 @@ do_resend: "done.\n"); li->e = 1; /* we cannot extend */ rh->fbi = 1; /* we indicate final block */ - tbf->dir.dl.tx_counter = POLL_ACK_AFTER_FRAMES + 1; + first_fin_ack = 1; /* + 1 indicates: first final ack */ tbf_new_state(tbf, GPRS_RLCMAC_FINISHED); break; @@ -1459,18 +1460,15 @@ tx_block: /* poll after POLL_ACK_AFTER_FRAMES frames, or when final block is tx. */ - if (tbf->dir.dl.tx_counter >= POLL_ACK_AFTER_FRAMES) { - if (tbf->dir.dl.tx_counter > POLL_ACK_AFTER_FRAMES) { - /* if rx_counter is POLL_ACK_AFTER_FRAMES + 1, this - * indicates: poll caused by final ack. */ + if (tbf->dir.dl.tx_counter >= POLL_ACK_AFTER_FRAMES || first_fin_ack) { + if (first_fin_ack) { LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " - "polling, because final block sent.\n"); + "polling, because first final block sent.\n"); } else { LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " "polling, because %d blocks sent.\n", POLL_ACK_AFTER_FRAMES); } - tbf->dir.dl.tx_counter = 0; /* scheduling not possible, because: */ if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already " @@ -1487,6 +1485,7 @@ tx_block: else { LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this " "TS %d\n", ts); + tbf->dir.dl.tx_counter = 0; /* start timer whenever we send the final block */ if (rh->fbi == 1) tbf_timer_start(tbf, 3191, bts->t3191, 0); -- cgit v1.2.3 From 3b1332cdb4a2b9e61ca71386072e915e6f5d30ba Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 3 Oct 2012 14:20:53 +0200 Subject: Replace switch/case construct by a structure, to define coding schemes A new attribute at TBF instance indicates the current scheme used. --- src/gprs_rlcmac.cpp | 9 +++++++++ src/gprs_rlcmac.h | 13 +++++++++++++ src/gprs_rlcmac_data.cpp | 22 ++++++---------------- 3 files changed, 28 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 64bbe75f..e434c4be 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -71,6 +71,15 @@ struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = { /* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA }, }; +struct gprs_rlcmac_cs gprs_rlcmac_cs[] = { +/* frame length data block max payload */ + { 0, 0, 0 }, + { 23, 23, 20 }, /* CS-1 */ + { 34, 33, 30 }, /* CS-2 */ + { 40, 39, 36 }, /* CS-3 */ + { 54, 53, 50 }, /* CS-4 */ +}; + LLIST_HEAD(gprs_rlcmac_ul_tbfs); LLIST_HEAD(gprs_rlcmac_dl_tbfs); llist_head *gprs_rlcmac_tbfs_lists[] = { diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 27cf825d..64797542 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -223,6 +223,8 @@ struct gprs_rlcmac_tbf { struct timeval bw_tv; /* timestamp for bandwidth calculation */ uint32_t bw_octets; /* number of octets transmitted since bw_tv */ + + uint8_t cs; /* current coding scheme */ }; extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */ @@ -249,6 +251,17 @@ struct gprs_rlcmac_sba { uint8_t ta; }; +/* + * coding scheme info + */ +struct gprs_rlcmac_cs { + uint8_t block_length; + uint8_t block_data; + uint8_t block_payload; +}; + +extern struct gprs_rlcmac_cs gprs_rlcmac_cs[]; + int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta); struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn); diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 147054e0..2d03ac59 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -1289,23 +1289,13 @@ do_resend: /* now we still have untransmitted LLC data, so we fill mac block */ index = tbf->dir.dl.v_s & mod_sns_half; data = tbf->rlc_block[index]; - switch (bts->initial_cs) { - case 2: /* CS-2 */ - block_length = 34; - block_data = 33; - break; - case 3: /* CS-3 */ - block_length = 40; - block_data = 39; - break; - case 4: /* CS-4 */ - block_length = 54; - block_data = 53; - break; - default: /* CS-1 */ - block_length = 23; - block_data = 23; + if (tbf->cs == 0) { + tbf->cs = bts->initial_cs; + if (tbf->cs < 1 || tbf->cs > 4) + tbf->cs = 1; } + block_length = gprs_rlcmac_cs[tbf->cs].block_length; + block_data = gprs_rlcmac_cs[tbf->cs].block_data; memset(data, 0x2b, block_data); /* spare bits will be left 0 */ rh = (struct rlc_dl_header *)data; rh->pt = 0; /* Data Block */ -- cgit v1.2.3 From 499ff415a92909d125499d70ba8288bbc6ed8f60 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 3 Oct 2012 14:21:36 +0200 Subject: Allow setting of seperate coding schemes for uplink and downlink --- src/gprs_rlcmac.cpp | 6 +++--- src/gprs_rlcmac.h | 2 +- src/gprs_rlcmac_data.cpp | 2 +- src/pcu_l1_if.cpp | 5 +++-- src/pcu_main.cpp | 3 +-- src/pcu_vty.c | 18 ++++++++++++++---- 6 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index e434c4be..b38722d7 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -1275,7 +1275,7 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, bitvec_write_field(dest, wp, usf, 3); // USF bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY bitvec_write_field(dest, wp, 0, 1); // "0" power control: Not Present - bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND + bitvec_write_field(dest, wp, bts->initial_cs_ul-1, 2); // CHANNEL_CODING_COMMAND bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING if (alpha) { bitvec_write_field(dest, wp,0x1,1); // ALPHA = present @@ -1321,7 +1321,7 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi, } bitvec_write_field(dest, wp,0x0,1); // Message escape - bitvec_write_field(dest, wp,bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND + bitvec_write_field(dest, wp,bts->initial_cs_ul-1, 2); // CHANNEL_CODING_COMMAND bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on @@ -1461,7 +1461,7 @@ void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *t block->u.Packet_Uplink_Ack_Nack.UPLINK_TFI = tbf->tfi; // Uplink TFI block->u.Packet_Uplink_Ack_Nack.UnionType = 0x0; // PU_AckNack_GPRS = on - block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.CHANNEL_CODING_COMMAND = bts->initial_cs - 1; // CS1 + block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.CHANNEL_CODING_COMMAND = bts->initial_cs_ul - 1; // CS1 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.FINAL_ACK_INDICATION = final; // FINAL ACK INDICATION block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.STARTING_SEQUENCE_NUMBER = tbf->dir.ul.v_r; // STARTING_SEQUENCE_NUMBER // RECEIVE_BLOCK_BITMAP diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index 64797542..16996279 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -67,7 +67,7 @@ struct gprs_rlcmac_bts { uint8_t cs2; uint8_t cs3; uint8_t cs4; - uint8_t initial_cs; + uint8_t initial_cs_dl, initial_cs_ul; uint8_t force_cs; /* 0=use from BTS 1=use from VTY */ uint16_t force_llc_lifetime; /* overrides lifetime from SGSN */ uint8_t t3142; diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 2d03ac59..7b0d83f7 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -1290,7 +1290,7 @@ do_resend: index = tbf->dir.dl.v_s & mod_sns_half; data = tbf->rlc_block[index]; if (tbf->cs == 0) { - tbf->cs = bts->initial_cs; + tbf->cs = bts->initial_cs_dl; if (tbf->cs < 1 || tbf->cs > 4) tbf->cs = 1; } diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 9e5e2f20..14981820 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -405,9 +405,10 @@ bssgp_failed: } if (!bts->force_cs) { if (info_ind->initial_cs < 1 || info_ind->initial_cs > 4) - bts->initial_cs = 1; + bts->initial_cs_dl = 1; else - bts->initial_cs = info_ind->initial_cs; + bts->initial_cs_dl = info_ind->initial_cs; + bts->initial_cs_ul = bts->initial_cs_dl; } for (trx = 0; trx < 8; trx++) { diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index ba31ca7e..ee6f70c4 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -141,9 +141,8 @@ int main(int argc, char *argv[]) struct gprs_rlcmac_bts); if (!gprs_rlcmac_bts) return -ENOMEM; - gprs_rlcmac_bts->initial_cs = 1; bts->fc_interval = 1; - bts->initial_cs = 1; + bts->initial_cs_dl = bts->initial_cs_ul = 1; bts->cs1 = 1; bts->t3142 = 20; bts->t3169 = 5; diff --git a/src/pcu_vty.c b/src/pcu_vty.c index d7c2c2cd..c55a9ee6 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -82,7 +82,12 @@ static int config_write_pcu(struct vty *vty) vty_out(vty, " flow-control-interval %d%s", bts->fc_interval, VTY_NEWLINE); if (bts->force_cs) - vty_out(vty, " cs %d%s", bts->initial_cs, VTY_NEWLINE); + if (bts->initial_cs_ul == bts->initial_cs_dl) + vty_out(vty, " cs %d%s", bts->initial_cs_dl, + VTY_NEWLINE); + else + vty_out(vty, " cs %d %d%s", bts->initial_cs_dl, + bts->initial_cs_ul, VTY_NEWLINE); if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -125,14 +130,19 @@ DEFUN(cfg_pcu_fc_interval, DEFUN(cfg_pcu_cs, cfg_pcu_cs_cmd, - "cs <1-4>", - "Set the Coding Scheme to be used, (overrides BTS config)\n") + "cs <1-4> [<1-4>]", + "Set the Coding Scheme to be used, (overrides BTS config)\n" + "Initial CS used\nAlternative uplink CS") { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; uint8_t cs = atoi(argv[0]); bts->force_cs = 1; - bts->initial_cs = cs; + bts->initial_cs_dl = cs; + if (argc > 1) + bts->initial_cs_ul = atoi(argv[1]); + else + bts->initial_cs_ul = cs; return CMD_SUCCESS; } -- cgit v1.2.3