aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-07-10 22:39:15 +0200
committerHarald Welte <laforge@gnumonks.org>2019-03-27 11:19:11 +0000
commit41723e1508d242e774c18dc9b7b0efff70548592 (patch)
treecde76476cfb7f369a6b9d8c0bebe46f78fa2df2d /src
parent945c09381d033d142d8e851cd7a4de2e407b61ca (diff)
Forward GPRS SUSPEND REQ from DCCH to PCU socket
As specified in 3GPP TS 03.60 Section 16.2.1 and 44.018 Section 3.4.15, a Class B MS is sending a "RR GPRS SUSPEND REQ" via a DCCH to the BTS if it wants to suspend GPRS services. The BSS is now responsible to somehow forward this to the SGSN. As the Gs interface between BSC and SGSN is both optional and doesn't have any provision to forward this message, we have to send it over to the PCU so it can use regular BSSGP signaling to inform the SGSN of the SUSPEND REQUEST. This patch requires libosmocore Change-Id I90113044460a6c511ced14f588876c4280d1cac7 for the related definition of struct gsm48_gprs_susp_req. Change-Id: I3c1af662c8f0d3d22da200638480f6ef05c3ed1f Closes: OS#2249
Diffstat (limited to 'src')
-rw-r--r--src/common/pcu_sock.c17
-rw-r--r--src/common/rsl.c55
2 files changed, 63 insertions, 9 deletions
diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c
index 440f561d..d6946028 100644
--- a/src/common/pcu_sock.c
+++ b/src/common/pcu_sock.c
@@ -466,6 +466,23 @@ int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len)
return pcu_sock_send(&bts_gsmnet, msg);
}
+/* forward data from a RR GPRS SUSPEND REQ towards PCU */
+int pcu_tx_susp_req(struct gsm_lchan *lchan, uint32_t tlli, const uint8_t *ra_id, uint8_t cause)
+{
+ struct msgb *msg;
+ struct gsm_pcu_if *pcu_prim;
+
+ msg = pcu_msgb_alloc(PCU_IF_MSG_SUSP_REQ, lchan->ts->trx->bts->nr);
+ if (!msg)
+ return -ENOMEM;
+ pcu_prim = (struct gsm_pcu_if *) msg->data;
+ pcu_prim->u.susp_req.tlli = tlli;
+ memcpy(pcu_prim->u.susp_req.ra_id, ra_id, sizeof(pcu_prim->u.susp_req.ra_id));
+ pcu_prim->u.susp_req.cause = cause;
+
+ return pcu_sock_send(&bts_gsmnet, msg);
+}
+
static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type,
const struct gsm_pcu_if_data *data_req)
{
diff --git a/src/common/rsl.c b/src/common/rsl.c
index f93ca50d..5287201e 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <arpa/inet.h>
+#include <osmocom/core/byteswap.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/rsl.h>
@@ -36,6 +37,7 @@
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/protocol/ipaccess.h>
#include <osmocom/trau/osmo_ortp.h>
@@ -2557,32 +2559,35 @@ static inline int rsl_link_id_is_sacch(uint8_t link_id)
return 0;
}
-static int rslms_is_meas_rep(struct msgb *msg)
+static int rslms_get_meas_msg_type(struct msgb *msg, bool rllh_link_id_is_sacch)
{
struct abis_rsl_common_hdr *rh = msgb_l2(msg);
struct abis_rsl_rll_hdr *rllh;
struct gsm48_hdr *gh;
if ((rh->msg_discr & 0xfe) != ABIS_RSL_MDISC_RLL)
- return 0;
+ return -1;
if (rh->msg_type != RSL_MT_UNIT_DATA_IND)
- return 0;
+ return -2;
rllh = msgb_l2(msg);
- if (rsl_link_id_is_sacch(rllh->link_id) == 0)
- return 0;
+ if (rsl_link_id_is_sacch(rllh->link_id) != rllh_link_id_is_sacch)
+ return -3;
gh = msgb_l3(msg);
if (gh->proto_discr != GSM48_PDISC_RR)
- return 0;
+ return -4;
+
+ return gh->msg_type;
+}
- switch (gh->msg_type) {
+static int rslms_is_meas_rep(struct msgb *msg)
+{
+ switch (rslms_get_meas_msg_type(msg, 1)) {
case GSM48_MT_RR_MEAS_REP:
case GSM48_MT_RR_EXT_MEAS_REP:
return 1;
- default:
- break;
}
/* FIXME: this does not cover the Bter frame format and the associated
@@ -2591,6 +2596,36 @@ static int rslms_is_meas_rep(struct msgb *msg)
return 0;
}
+static int rslms_is_gprs_susp_req(struct msgb *msg)
+{
+ return rslms_get_meas_msg_type(msg, 0) == GSM48_MT_RR_GPRS_SUSP_REQ;
+}
+
+/* TS 44.018 9.1.13b GPRS suspension request */
+static int handle_gprs_susp_req(struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm48_gprs_susp_req *gsr;
+ uint32_t tlli;
+ int rc;
+
+ if (!gh || msgb_l3len(msg) < sizeof(*gh)+sizeof(*gsr)) {
+ LOGP(DRSL, LOGL_NOTICE, "%s Short GPRS SUSPEND REQ received, ignoring\n", gsm_lchan_name(msg->lchan));
+ return -EINVAL;
+ }
+
+ gsr = (struct gsm48_gprs_susp_req *) gh->data;
+ tlli = osmo_ntohl(gsr->tlli);
+
+ LOGP(DRSL, LOGL_INFO, "%s Fwd GPRS SUSPEND REQ for TLLI=0x%08x to PCU\n",
+ gsm_lchan_name(msg->lchan), tlli);
+ rc = pcu_tx_susp_req(msg->lchan, tlli, gsr->ra_id, gsr->cause);
+
+ msgb_free(msg);
+
+ return rc;
+}
+
static inline uint8_t ms_to2rsl(const struct gsm_lchan *lchan, const struct lapdm_entity *le)
{
return (lchan->ms_t_offs >= 0) ? lchan->ms_t_offs : (lchan->p_offs - le->ta);
@@ -2731,6 +2766,8 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
rc = rsl_tx_meas_res(lchan, msgb_l3(msg), msgb_l3len(msg), le);
msgb_free(msg);
return rc;
+ } else if (rslms_is_gprs_susp_req(msg)) {
+ return handle_gprs_susp_req(msg);
} else {
LOGP(DRSL, LOGL_INFO, "%s Fwd RLL msg %s from LAPDm to A-bis\n",
gsm_lchan_name(lchan), rsl_msg_name(rh->msg_type));