Change in ...osmo-bts[master]: ETWS Primary Notification via P1 Rest Octets

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.org
Thu Sep 5 10:51:19 UTC 2019


laforge has uploaded this change for review. ( 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
5 files changed, 186 insertions(+), 11 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/17/15417/1

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

-- 
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: 1
Gerrit-Owner: laforge <laforge at gnumonks.org>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190905/8b9326bf/attachment.htm>


More information about the gerrit-log mailing list