diff options
-rw-r--r-- | include/osmocom/gsm/lapdm.h | 12 | ||||
-rw-r--r-- | src/gsm/lapdm.c | 86 | ||||
-rw-r--r-- | src/gsm/libosmogsm.map | 2 |
3 files changed, 85 insertions, 15 deletions
diff --git a/include/osmocom/gsm/lapdm.h b/include/osmocom/gsm/lapdm.h index e01d065a..931de80a 100644 --- a/include/osmocom/gsm/lapdm.h +++ b/include/osmocom/gsm/lapdm.h @@ -1,6 +1,7 @@ #pragma once #include <osmocom/gsm/l1sap.h> +#include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/lapd_core.h> /*! \defgroup lapdm LAPDm implementation according to GSM TS 04.06 @@ -81,9 +82,14 @@ extern const char *lapdm_state_names[]; struct lapdm_datalink *lapdm_datalink_for_sapi(struct lapdm_entity *le, uint8_t sapi); /* initialize a LAPDm entity */ -void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode, int t200); -void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode); - +void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode, int t200) + OSMO_DEPRECATED("Use lapdm_entity_init2() instead"); +void lapdm_entity_init2(struct lapdm_entity *le, enum lapdm_mode mode, + const int *t200_ms, int n200); +void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode) + OSMO_DEPRECATED("Use lapdm_channel_init2() instead"); +int lapdm_channel_init2(struct lapdm_channel *lc, enum lapdm_mode mode, + const int *t200_ms_dcch, const int *t200_ms_acch, enum gsm_chan_t chan_t); /* deinitialize a LAPDm entity */ void lapdm_entity_exit(struct lapdm_entity *le); void lapdm_channel_exit(struct lapdm_channel *lc); diff --git a/src/gsm/lapdm.c b/src/gsm/lapdm.c index f1651d6d..80840293 100644 --- a/src/gsm/lapdm.c +++ b/src/gsm/lapdm.c @@ -1,7 +1,7 @@ /*! \file lapdm.c * GSM LAPDm (TS 04.06) implementation. */ /* - * (C) 2010-2017 by Harald Welte <laforge@gnumonks.org> + * (C) 2010-2019 by Harald Welte <laforge@gnumonks.org> * (C) 2010-2011 by Andreas Eversberg <jolly@eversberg.eu> * (C) 2014-2016 by sysmocom - s.f.m.c GmbH * @@ -132,7 +132,7 @@ static int send_rslms_dlsap(struct osmo_dlsap_prim *dp, static int update_pending_frames(struct lapd_msg_ctx *lctx); static void lapdm_dl_init(struct lapdm_datalink *dl, - struct lapdm_entity *entity, int t200) + struct lapdm_entity *entity, int t200_ms, uint32_t n200) { memset(dl, 0, sizeof(*dl)); dl->entity = entity; @@ -142,39 +142,101 @@ static void lapdm_dl_init(struct lapdm_datalink *dl, dl->dl.send_dlsap = send_rslms_dlsap; dl->dl.update_pending_frames = update_pending_frames; dl->dl.n200_est_rel = N200_EST_REL; - dl->dl.n200 = N200; + dl->dl.n200 = n200; dl->dl.t203_sec = 0; dl->dl.t203_usec = 0; - dl->dl.t200_sec = t200; dl->dl.t200_usec = 0; + dl->dl.t200_sec = t200_ms / 1000; dl->dl.t200_usec = (t200_ms % 1000) * 1000; } /*! initialize a LAPDm entity and all datalinks inside * \param[in] le LAPDm entity * \param[in] mode \ref lapdm_mode (BTS/MS) + * \param[in] t200 T200 re-transmission timer for all SAPIs in seconds + * + * Don't use this function; It doesn't support different T200 values per API + * and doesn't permit the caller to specify the N200 counter, both of which + * are required by GSM specs and supported by lapdm_entity_init2(). */ void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode, int t200) { + /* convert from single full-second value to per-SAPI milli-second value */ + int t200_ms_sapi_arr[_NR_DL_SAPI]; + int i; + + for (i = 0; i < ARRAY_SIZE(t200_ms_sapi_arr); i++) + t200_ms_sapi_arr[i] = t200 * 1000; + + return lapdm_entity_init2(le, mode, t200_ms_sapi_arr, N200); +} + +/*! initialize a LAPDm entity and all datalinks inside + * \param[in] le LAPDm entity + * \param[in] mode lapdm_mode (BTS/MS) + * \param[in] t200_ms per-SAPI array of T200 re-transmission timer in milli-seconds + * \param[in] n200 N200 re-transmisison count + */ +void lapdm_entity_init2(struct lapdm_entity *le, enum lapdm_mode mode, + const int *t200_ms, int n200) +{ unsigned int i; for (i = 0; i < ARRAY_SIZE(le->datalink); i++) - lapdm_dl_init(&le->datalink[i], le, t200); + lapdm_dl_init(&le->datalink[i], le, t200_ms[i], n200); lapdm_entity_set_mode(le, mode); } +static int get_n200_dcch(enum gsm_chan_t chan_t) +{ + switch (chan_t) { + case GSM_LCHAN_SDCCH: + return N200_TR_SDCCH; + case GSM_LCHAN_TCH_F: + return N200_TR_FACCH_FR; + case GSM_LCHAN_TCH_H: + return N200_TR_FACCH_HR; + default: + return -1; + } +} + /*! initialize a LAPDm channel and all its channels - * \param[in] lc \ref lapdm_channel to be initialized - * \param[in] mode \ref lapdm_mode (BTS/MS) + * \param[in] lc lapdm_channel to be initialized + * \param[in] mode lapdm_mode (BTS/MS) * - * This really is a convenience wrapper around calling \ref - * lapdm_entity_init twice. + * Don't use this function; It doesn't support different T200 values per API + * and doesn't set the correct N200 counter, both of which + * are required by GSM specs and supported by lapdm_channel_init2(). */ void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode) { - lapdm_entity_init(&lc->lapdm_acch, mode, 2); + /* emulate old backwards-compatible behavior with 1s/2s */ + const int t200_ms_dcch[_NR_DL_SAPI] = { 1000, 1000 }; + const int t200_ms_acch[_NR_DL_SAPI] = { 2000, 2000 }; + + lapdm_channel_init2(lc, mode, t200_ms_dcch, t200_ms_acch, GSM_LCHAN_SDCCH); +} + +/*! initialize a LAPDm channel and all its channels + * \param[in] lc \ref lapdm_channel to be initialized + * \param[in] mode \ref lapdm_mode (BTS/MS) + * \param[in] t200_ms_dcch per-SAPI array of T200 in milli-seconds for DCCH + * \param[in] t200_ms_acch per-SAPI array of T200 in milli-seconds for SACCH + * \param[in] chan_t GSM channel type (to correctly set N200) + */ +int lapdm_channel_init2(struct lapdm_channel *lc, enum lapdm_mode mode, + const int *t200_ms_dcch, const int *t200_ms_acch, enum gsm_chan_t chan_t) +{ + int n200_dcch = get_n200_dcch(chan_t); + if (n200_dcch < 0) + return -EINVAL; + + lapdm_entity_init2(&lc->lapdm_acch, mode, t200_ms_acch, N200_TR_SACCH); lc->lapdm_acch.lapdm_ch = lc; - /* FIXME: this depends on chan type */ - lapdm_entity_init(&lc->lapdm_dcch, mode, 1); + + lapdm_entity_init2(&lc->lapdm_dcch, mode, t200_ms_dcch, n200_dcch); lc->lapdm_dcch.lapdm_ch = lc; + + return 0; } /*! flush and release all resoures in LAPDm entity */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 9aa9683a..34a15432 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -457,6 +457,7 @@ lapd_state_names; lapdm_channel_exit; lapdm_channel_init; +lapdm_channel_init2; lapdm_channel_reset; lapdm_channel_set_flags; lapdm_channel_set_l1; @@ -465,6 +466,7 @@ lapdm_channel_set_mode; lapdm_datalink_for_sapi; lapdm_entity_exit; lapdm_entity_init; +lapdm_entity_init2; lapdm_entity_reset; lapdm_entity_set_flags; lapdm_entity_set_mode; |