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

<div style="display:none"> Gerrit-Project: osmo-bts </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I18c60cdb86b9c19e09f5ec06d66e9b91608880e6 </div>
<div style="display:none"> Gerrit-Change-Number: 15417 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>