diff options
-rw-r--r-- | include/osmocom/bsc/gsm_04_08_rr.h | 2 | ||||
-rw-r--r-- | src/osmo-bsc/gsm_04_08_rr.c | 22 | ||||
-rw-r--r-- | src/osmo-bsc/smscb.c | 63 |
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 */ |