aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/bsc/gsm_04_08_rr.h2
-rw-r--r--src/osmo-bsc/gsm_04_08_rr.c22
-rw-r--r--src/osmo-bsc/smscb.c63
3 files changed, 85 insertions, 2 deletions
diff --git a/include/osmocom/bsc/gsm_04_08_rr.h b/include/osmocom/bsc/gsm_04_08_rr.h
index 8e4f78785..f0c0f4223 100644
--- a/include/osmocom/bsc/gsm_04_08_rr.h
+++ b/include/osmocom/bsc/gsm_04_08_rr.h
@@ -29,6 +29,8 @@ struct msgb *gsm48_make_ho_cmd(struct gsm_lchan *new_lchan, uint8_t power_comman
int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
uint8_t power_command, uint8_t ho_ref);
int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, uint8_t power_command);
+int gsm48_send_rr_app_info(struct gsm_lchan *lchan, uint8_t apdu_id, uint8_t apdu_flags,
+ const uint8_t *apdu_data, ssize_t apdu_data_len);
int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode);
int gsm48_rx_rr_modif_ack(struct msgb *msg);
int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg);
diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c
index 7ff94adea..1fbbb5787 100644
--- a/src/osmo-bsc/gsm_04_08_rr.c
+++ b/src/osmo-bsc/gsm_04_08_rr.c
@@ -592,6 +592,28 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan,
return gsm48_sendmsg(msg);
}
+/* TS 44.018 section 9.1.53 */
+int gsm48_send_rr_app_info(struct gsm_lchan *lchan, uint8_t apdu_id, uint8_t apdu_flags,
+ const uint8_t *apdu_data, ssize_t apdu_data_len)
+{
+ struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 APP INFO");
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+
+ if ((apdu_id & 0xF0) || (apdu_flags & 0xF0)) {
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ msg->lchan = lchan;
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_APP_INFO;
+
+ msgb_put_u8(msg, (apdu_flags << 4) | apdu_id);
+ msgb_lv_put(msg, apdu_data_len, apdu_data);
+
+ return gsm48_sendmsg(msg);
+}
+
/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode)
{
diff --git a/src/osmo-bsc/smscb.c b/src/osmo-bsc/smscb.c
index 6b9608652..319ef21a7 100644
--- a/src/osmo-bsc/smscb.c
+++ b/src/osmo-bsc/smscb.c
@@ -25,10 +25,12 @@
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/byteswap.h>
#include <osmocom/gsm/cbsp.h>
#include <osmocom/gsm/protocol/gsm_23_041.h>
#include <osmocom/gsm/protocol/gsm_48_049.h>
+#include <osmocom/gsm/protocol/gsm_03_41.h>
#include <osmocom/netif/stream.h>
@@ -36,6 +38,8 @@
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/smscb.h>
#include <osmocom/bsc/vty.h>
+#include <osmocom/bsc/gsm_04_08_rr.h>
+#include <osmocom/bsc/lchan_fsm.h>
/*********************************************************************************
* Helper Functions
@@ -52,6 +56,26 @@ static void llist_replace_head(struct llist_head *new, struct llist_head *old)
INIT_LLIST_HEAD(old);
}
+#define ETWS_PRIM_NOTIF_SIZE 56
+
+/* Build a ETWS Primary Notification message as per TS 23.041 9.4.1.3 */
+static int gen_etws_primary_notification(uint8_t *out, uint16_t serial_nr, uint16_t msg_id,
+ uint16_t warn_type, const uint8_t *sec_info)
+{
+ struct gsm341_etws_message *etws = (struct gsm341_etws_message *)out;
+
+ memset(out, 0, ETWS_PRIM_NOTIF_SIZE);
+
+ osmo_store16be(serial_nr, out);
+ etws->msg_id = osmo_htons(msg_id);
+ etws->warning_type = osmo_htons(warn_type);
+
+ if (sec_info)
+ memcpy(etws->data, sec_info, ETWS_PRIM_NOTIF_SIZE - sizeof(*etws));
+
+ return ETWS_PRIM_NOTIF_SIZE;
+}
+
/*! Obtain SMSCB Channel State for given BTS (basic or extended CBCH) */
struct bts_smscb_chan_state *bts_get_smscb_chan(struct gsm_bts *bts, bool extended)
{
@@ -437,6 +461,39 @@ static int tx_cbsp_keepalive_compl(struct bsc_cbc_link *cbc)
* Per-BTS Processing of CBSP from CBC, called via cbsp_per_bts()
*********************************************************************************/
+static void etws_primary_to_dedicated(struct gsm_bts *bts,
+ const struct osmo_cbsp_write_replace *wrepl)
+{
+ uint8_t etws_primary[ETWS_PRIM_NOTIF_SIZE];
+ struct gsm_bts_trx *trx;
+ unsigned int count = 0;
+ int i, j;
+
+ gen_etws_primary_notification(etws_primary, wrepl->new_serial_nr, wrepl->msg_id,
+ wrepl->u.emergency.warning_type,
+ wrepl->u.emergency.warning_sec_info);
+
+ /* iterate over all lchan in each TS in each TRX of this BTS */
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ for (j = 0; j < ARRAY_SIZE(ts->lchan); j++) {
+ struct gsm_lchan *lchan = &ts->lchan[j];
+ if (!lchan_may_receive_data(lchan))
+ continue;
+ gsm48_send_rr_app_info(lchan, 0x1, 0x0, etws_primary,
+ sizeof(etws_primary));
+ count++;
+ }
+ }
+ }
+
+ LOG_BTS(bts, DCBS, LOGL_NOTICE, "Sent ETWS Primary Notification via %u dedicated channels\n",
+ count);
+
+ /* FIXME: Notify BTS of primary ETWS notification via vendor-specific Abis message */
+}
+
/*! Try to execute a write-replace operation; roll-back if it fails.
* \param[in] chan_state BTS CBCH channel state
* \param[in] extended_cbch Basic (false) or Extended (true) CBCH
@@ -506,8 +563,10 @@ static int bts_rx_write_replace(struct gsm_bts *bts, const struct osmo_cbsp_deco
int rc;
if (!wrepl->is_cbs) {
- LOG_BTS(bts, DCBS, LOGL_ERROR, "(Primary) Emergency Message not supported\n");
- return -CBSP_CAUSE_CB_NOT_SUPPORTED;
+ /* send through any active dedicated channels of this BTS */
+ etws_primary_to_dedicated(bts, wrepl);
+ /* TODO: send via RSL to BTS for transmission on PCH */
+ return 0;
}
/* check if cell has a CBCH at all */