This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
laforge gerrit-no-reply at lists.osmocom.orglaforge has submitted this change and it was merged. ( https://gerrit.osmocom.org/c/osmo-bts/+/15417 )
Change subject: ETWS Primary Notification via P1 Rest Octets
......................................................................
ETWS Primary Notification via P1 Rest Octets
The ETWS (Earthquake and Tsunami Warning System) uses a so-called
ETWS Primary Notification which is sent
* to phones in dedicated mode (via DCCH from the BSC)
* to phones in idle mode (via P1 Rest Octets on PCH/CCCH)
This patch implements the second part of the functionality, i.e.
transmitting the related ETWS Primary Notification via PCH. As
3GPP doesn't specify how this is communicated over Abis, we use
a new, vendor-specific RSL message type.
Closes: OS#4047
Depends: libosmocore I89c24a81ada6627694a9632e87485a61cbd3e680
Depends: libosmocore I36fc2ffc22728887d1cb8768c7fcd9739a8ec0fc
Change-Id: I18c60cdb86b9c19e09f5ec06d66e9b91608880e6
---
M include/osmo-bts/gsm_data_shared.h
M src/common/bts.c
M src/common/gsm_data_shared.c
M src/common/paging.c
M src/common/rsl.c
M tests/paging/paging_test.c
6 files changed, 202 insertions(+), 14 deletions(-)
Approvals:
Jenkins Builder: Verified
fixeria: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
diff --git a/include/osmo-bts/gsm_data_shared.h b/include/osmo-bts/gsm_data_shared.h
index dd2a14c..65e984d 100644
--- a/include/osmo-bts/gsm_data_shared.h
+++ b/include/osmo-bts/gsm_data_shared.h
@@ -479,6 +479,7 @@
BTS_FEAT_SPEECH_F_EFR,
BTS_FEAT_SPEECH_F_AMR,
BTS_FEAT_SPEECH_H_AMR,
+ BTS_FEAT_ETWS_PN,
_NUM_BTS_FEAT
};
@@ -718,6 +719,15 @@
uint64_t pch_msgs;
} agch_queue;
+ struct {
+ uint8_t *prim_notif; /* ETWS primary notification (NULL if none) */
+ ssize_t prim_notif_len; /* Length of prim_notif; expected 56 bytes */
+ uint8_t page_size;
+ uint8_t num_pages; /* total number of pages */
+ uint8_t next_page; /* next page number to be sent */
+ bool pni; /* Primary Notification Identifier */
+ } etws;
+
struct paging_state *paging_state;
char *bsc_oml_host;
struct llist_head oml_queue;
diff --git a/src/common/bts.c b/src/common/bts.c
index 5c415e8..73631ae 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -192,6 +192,9 @@
tall_rtp_ctx = talloc_pool(tall_bts_ctx, 262144);
osmo_rtp_init(tall_rtp_ctx);
+ /* features implemented in 'common', available for all models */
+ gsm_bts_set_feature(bts, BTS_FEAT_ETWS_PN);
+
rc = bts_model_init(bts);
if (rc < 0) {
llist_del(&bts->list);
diff --git a/src/common/gsm_data_shared.c b/src/common/gsm_data_shared.c
index b1785b8..1ba43aa 100644
--- a/src/common/gsm_data_shared.c
+++ b/src/common/gsm_data_shared.c
@@ -106,6 +106,7 @@
{ BTS_FEAT_SPEECH_F_EFR, "Fullrate speech EFR" },
{ BTS_FEAT_SPEECH_F_AMR, "Fullrate speech AMR" },
{ BTS_FEAT_SPEECH_H_AMR, "Halfrate speech AMR" },
+ { BTS_FEAT_ETWS_PN, "ETWS Primary Notification on PCH" },
{ 0, NULL }
};
diff --git a/src/common/paging.c b/src/common/paging.c
index 111f947..fca58b5 100644
--- a/src/common/paging.c
+++ b/src/common/paging.c
@@ -21,7 +21,7 @@
/* TODO:
* eMLPP priprity
- * add P1/P2/P3 rest octets
+ * add P2/P3 rest octets
*/
#include <stdlib.h>
@@ -274,11 +274,86 @@
#define L2_PLEN(len) (((len - 1) << 2) | 0x01)
+/* abstract representation of P1 rest octets; we only implement those parts we need for now */
+struct p1_rest_octets {
+ bool packet_page_ind[2];
+ bool r8_present;
+ struct {
+ bool prio_ul_access;
+ bool etws_present;
+ struct {
+ bool is_first;
+ uint8_t page_nr;
+ const uint8_t *page;
+ size_t page_bytes;
+ } etws;
+ } r8;
+};
+
+/* 3GPP TS 44.018 10.5.2.23 append a segment/page of an ETWS primary notification to given bitvec */
+static void append_etws_prim_notif(struct bitvec *bv, bool is_first, uint8_t page_nr,
+ const uint8_t *etws, ssize_t etws_len)
+{
+ OSMO_ASSERT(etws_len < 128/8);
+
+ /* ETWS primary Notification struct
+ * 0 NNNN / 1 NNNN
+ * PNI n
+ * LEN nnnnnnn (at least 13 bits before paylod)
+ * number of bits (LEN; up to 128) */
+
+ if (is_first)
+ bitvec_set_bit(bv, 0);
+ else
+ bitvec_set_bit(bv, 1);
+ bitvec_set_uint(bv, page_nr, 4); /* Segment Number / Total Number */
+ bitvec_set_bit(bv, 0); /* PNI to distinguish different ETWS */
+ bitvec_set_uint(bv, etws_len*8, 7); /* length of payload in number of bits */
+ bitvec_set_bytes(bv, etws, etws_len);
+
+ /* 17 bytes = 136bit - (11+13) = 112 bits = 14 bytes per PT1
+ * => at least 4x PT1 RO for complete primary notification (56 bytes) */
+}
+
+/* 3GPP TS 44.018 10.5.2.23 append P1 Rest Octets to given bit-vector */
+static void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro)
+{
+ /* Paging 1 RO (at least 10 bits before ETWS struct) */
+ bitvec_set_bit(bv, L); /* no NLN */
+ bitvec_set_bit(bv, L); /* no Priority1 */
+ bitvec_set_bit(bv, L); /* no Priority2 */
+ bitvec_set_bit(bv, L); /* no Group Call Info */
+ if (p1ro->packet_page_ind[0])
+ bitvec_set_bit(bv, H); /* Packet Page Indication 1 */
+ else
+ bitvec_set_bit(bv, L); /* Packet Page Indication 1 */
+ if (p1ro->packet_page_ind[1])
+ bitvec_set_bit(bv, H); /* Packet Page Indication 2 */
+ else
+ bitvec_set_bit(bv, L); /* Packet Page Indication 2 */
+
+ bitvec_set_bit(bv, L); /* No Release 6 additions */
+ bitvec_set_bit(bv, L); /* No Release 7 additions */
+
+ if (p1ro->r8_present) {
+ bitvec_set_bit(bv, H); /* Release 8 */
+ bitvec_set_bit(bv, p1ro->r8.prio_ul_access); /* Priority Uplink Access */
+ if (p1ro->r8.etws_present) {
+ bitvec_set_bit(bv, 1); /* ETWS present */
+ append_etws_prim_notif(bv, p1ro->r8.etws.is_first, p1ro->r8.etws.page_nr,
+ p1ro->r8.etws.page, p1ro->r8.etws.page_bytes);
+ } else
+ bitvec_set_bit(bv, 0);
+ }
+}
+
static int fill_paging_type_1(uint8_t *out_buf, const uint8_t *identity1_lv,
uint8_t chan1, const uint8_t *identity2_lv,
- uint8_t chan2)
+ uint8_t chan2, const struct p1_rest_octets *p1ro)
{
struct gsm48_paging1 *pt1 = (struct gsm48_paging1 *) out_buf;
+ struct bitvec bv;
+ unsigned int paging_len;
uint8_t *cur;
memset(out_buf, 0, sizeof(*pt1));
@@ -294,7 +369,19 @@
pt1->l2_plen = L2_PLEN(cur - out_buf);
- return cur - out_buf;
+ paging_len = cur - out_buf;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data = cur;
+ bv.data_len = GSM_MACBLOCK_LEN - paging_len;
+
+ if (p1ro)
+ append_p1_rest_octets(&bv, p1ro);
+
+ /* pad to the end of the MAC block */
+ bitvec_spare_padding(&bv, bv.data_len *8);
+
+ return GSM_MACBLOCK_LEN;
}
static int fill_paging_type_2(uint8_t *out_buf, const uint8_t *tmsi1_lv,
@@ -406,16 +493,43 @@
}
}
+static void build_p1_rest_octets(struct p1_rest_octets *p1ro, struct gsm_bts *bts)
+{
+ memset(p1ro, 0, sizeof(*p1ro));
+ p1ro->packet_page_ind[0] = false;
+ p1ro->packet_page_ind[1] = false;
+ p1ro->r8_present = true;
+ p1ro->r8.prio_ul_access = false;
+ p1ro->r8.etws_present = true;
+ unsigned int offset = bts->etws.page_size * bts->etws.next_page;
+
+ if (bts->etws.next_page == 0) {
+ p1ro->r8.etws.is_first = true;
+ p1ro->r8.etws.page_nr = bts->etws.num_pages;
+ } else {
+ p1ro->r8.etws.is_first = false;
+ p1ro->r8.etws.page_nr = bts->etws.next_page + 1;
+ }
+ p1ro->r8.etws.page = bts->etws.prim_notif + offset;
+ /* last page may be smaller than first pages */
+ if (bts->etws.next_page < bts->etws.num_pages-1)
+ p1ro->r8.etws.page_bytes = bts->etws.page_size;
+ else
+ p1ro->r8.etws.page_bytes = bts->etws.prim_notif_len - offset;
+ bts->etws.next_page = (bts->etws.next_page + 1) % bts->etws.num_pages;
+}
+
/* generate paging message for given gsm time */
int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt,
int *is_empty)
{
struct llist_head *group_q;
+ struct gsm_bts *bts = ps->bts;
int group;
int len;
*is_empty = 0;
- ps->bts->load.ccch.pch_total += 1;
+ bts->load.ccch.pch_total += 1;
group = get_pag_subch_nr(ps, gt);
if (group < 0) {
@@ -427,11 +541,15 @@
group_q = &ps->paging_queue[group];
- /* There is nobody to be paged, send Type1 with two empty ID */
- if (llist_empty(group_q)) {
+ if (ps->bts->etws.prim_notif) {
+ struct p1_rest_octets p1ro;
+ build_p1_rest_octets(&p1ro, bts);
+ len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro);
+ } else if (llist_empty(group_q)) {
+ /* There is nobody to be paged, send Type1 with two empty ID */
//DEBUGP(DPAG, "Tx PAGING TYPE 1 (empty)\n");
len = fill_paging_type_1(out_buf, empty_id_lv, 0,
- NULL, 0);
+ NULL, 0, NULL);
*is_empty = 1;
} else {
struct paging_record *pr[4];
@@ -439,7 +557,7 @@
time_t now = time(NULL);
unsigned int i, num_imsi = 0;
- ps->bts->load.ccch.pch_used += 1;
+ bts->load.ccch.pch_used += 1;
/* get (if we have) up to four paging records */
for (i = 0; i < ARRAY_SIZE(pr); i++) {
@@ -509,7 +627,7 @@
len = fill_paging_type_1(out_buf,
pr[0]->u.paging.identity_lv,
pr[0]->u.paging.chan_needed,
- NULL, 0);
+ NULL, 0, NULL);
} else {
/* 2 (any type) or
* 3 or 4, of which only 2 will be sent */
@@ -518,7 +636,7 @@
pr[0]->u.paging.identity_lv,
pr[0]->u.paging.chan_needed,
pr[1]->u.paging.identity_lv,
- pr[1]->u.paging.chan_needed);
+ pr[1]->u.paging.chan_needed, NULL);
if (num_pr >= 3) {
/* re-add #4 for next time */
llist_add(&pr[2]->list, group_q);
@@ -535,7 +653,7 @@
/* skip those that we might have re-added above */
if (pr[i] == NULL)
continue;
- rate_ctr_inc2(ps->bts->ctrs, BTS_CTR_PAGING_SENT);
+ rate_ctr_inc2(bts->ctrs, BTS_CTR_PAGING_SENT);
/* check if we can expire the paging record,
* or if we need to re-queue it */
if (pr[i]->u.paging.expiration_time <= now) {
diff --git a/src/common/rsl.c b/src/common/rsl.c
index d09dc4a..0bcad4c 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -522,6 +522,46 @@
return 0;
}
+/* OSMO_ETWS_CMD - proprietary extension as TS 48.058 has no standardized way to do this :( */
+static int rsl_rx_osmo_etws_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
+{
+ struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
+ struct gsm_bts *bts = trx->bts;
+ struct tlv_parsed tp;
+
+ rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+
+ if (!TLVP_PRESENT(&tp, RSL_IE_SMSCB_MSG))
+ return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR, &cch->chan_nr, NULL, msg);
+
+ bts->etws.prim_notif_len = TLVP_LEN(&tp, RSL_IE_SMSCB_MSG);
+ if (bts->etws.prim_notif_len == 0) {
+ LOGP(DRSL, LOGL_NOTICE, "ETWS Primary Notification OFF\n");
+ talloc_free(bts->etws.prim_notif);
+ bts->etws.prim_notif = NULL;
+ bts->etws.prim_notif_len = 0;
+ bts->etws.page_size = 0;
+ bts->etws.num_pages = 0;
+ bts->etws.next_page = 0;
+ } else {
+ LOGP(DRSL, LOGL_NOTICE, "ETWS Primary Notification: %s\n",
+ osmo_hexdump(TLVP_VAL(&tp, RSL_IE_SMSCB_MSG),
+ TLVP_LEN(&tp, RSL_IE_SMSCB_MSG)));
+ talloc_free(bts->etws.prim_notif);
+ bts->etws.prim_notif = talloc_memdup(bts, TLVP_VAL(&tp, RSL_IE_SMSCB_MSG),
+ bts->etws.prim_notif_len);
+
+ bts->etws.page_size = 14; /* maximum possible in SI1 Rest Octets */
+ bts->etws.num_pages = bts->etws.prim_notif_len / bts->etws.page_size;
+ if (bts->etws.prim_notif_len % bts->etws.page_size)
+ bts->etws.num_pages++;
+
+ /* toggle the PNI to allow phones to distinguish new from old primary notification */
+ bts->etws.pni = !bts->etws.pni;
+ }
+ return 0;
+}
+
/*! Prefix a given SACCH frame with a L2/LAPDm UI header and store it in given output buffer.
* \param[out] buf Output buffer, must be caller-allocated and hold at least len + 2 or sizeof(sysinfo_buf_t) bytes
* \param[out] valid pointer to bit-mask of 'valid' System information types
@@ -2951,6 +2991,9 @@
rsl_msg_name(cch->c.msg_type));
rsl_tx_error_report(trx, RSL_ERR_MSG_TYPE, &cch->chan_nr, NULL, msg);
break;
+ case RSL_MT_OSMO_ETWS_CMD:
+ ret = rsl_rx_osmo_etws_cmd(trx, msg);
+ break;
default:
LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "undefined RSL cchan msg_type 0x%02x\n",
cch->c.msg_type);
diff --git a/tests/paging/paging_test.c b/tests/paging/paging_test.c
index f112404..af8accc 100644
--- a/tests/paging/paging_test.c
+++ b/tests/paging/paging_test.c
@@ -42,6 +42,16 @@
abort(); \
}
+static bool is_padding(const uint8_t *in, size_t len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (in[i] != 0x2b)
+ return false;
+ }
+ return true;
+}
+
static void test_paging_smoke(void)
{
int rc;
@@ -61,7 +71,8 @@
g_time.t2 = 0;
g_time.t3 = 6;
rc = paging_gen_msg(bts->paging_state, out_buf, &g_time, &is_empty);
- ASSERT_TRUE(rc == 13);
+ ASSERT_TRUE(rc == 23);
+ ASSERT_TRUE(is_padding(out_buf+13, 23-13));
ASSERT_TRUE(is_empty == 0);
ASSERT_TRUE(paging_group_queue_empty(bts->paging_state, 0));
@@ -73,7 +84,8 @@
g_time.t2 = 0;
g_time.t3 = 6;
rc = paging_gen_msg(bts->paging_state, out_buf, &g_time, &is_empty);
- ASSERT_TRUE(rc == 6);
+ ASSERT_TRUE(rc == 23);
+ ASSERT_TRUE(is_padding(out_buf+6, 23-6));
ASSERT_TRUE(is_empty == 1);
/*
@@ -104,7 +116,8 @@
g_time.t2 = 0;
g_time.t3 = 6;
rc = paging_gen_msg(bts->paging_state, out_buf, &g_time, &is_empty);
- ASSERT_TRUE(rc == 13);
+ ASSERT_TRUE(rc == 23);
+ ASSERT_TRUE(is_padding(out_buf+13, 23-13));
ASSERT_TRUE(is_empty == 0);
ASSERT_TRUE(paging_group_queue_empty(bts->paging_state, 0));
--
To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/15417
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: I18c60cdb86b9c19e09f5ec06d66e9b91608880e6
Gerrit-Change-Number: 15417
Gerrit-PatchSet: 2
Gerrit-Owner: laforge <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <axilirator at gmail.com>
Gerrit-Reviewer: laforge <laforge at gnumonks.org>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190906/4e517bc8/attachment.htm>