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;  | 
