laforge submitted this change.
ASCI: Add Notification CHannel (NCH) support
The location of the NCH is defined by the rest octet of System
Information 1. If NCH is defined, the given CCCH blocks are used for NCH
instead of AGCH/PCH.
The current list of VGCS/VBS call notifications is transmitted on the
NCH. If there is no notification, an empty notification is transmitted
on the NCH.
The Notification List Number (NLN) is used to indicated new
notificaitons. Only the last notification (or empty notification)
indicates NLN. This way the MS can determine after two equal NLN that
the complete list has been recevied.
Change-Id: I82fdaba3faaced76267a99ae14a5458a1b41fdaa
Related: OS#5781
---
M include/osmo-bts/bts.h
M include/osmo-bts/l1sap.h
M include/osmo-bts/notification.h
M src/common/bts.c
M src/common/l1sap.c
M src/common/notification.c
M tests/agch/agch_test.c
M tests/paging/paging_test.c
8 files changed, 153 insertions(+), 26 deletions(-)
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index eb0c663..677ff9c 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -296,7 +296,10 @@
/* Advanced Speech Call Items (VBS/VGCS) + NCH related bits */
struct {
int pos_nch; /* position of the NCH or < 0, if not available */
+ uint8_t nln, nln_status; /* current notification list number and status */
struct llist_head notifications;
+ int notification_entries; /* current number of entries in the list */
+ int notification_count; /* counter to count all entries */
} asci;
struct paging_state *paging_state;
@@ -407,8 +410,14 @@
int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg);
struct msgb *bts_agch_dequeue(struct gsm_bts *bts);
int bts_agch_max_queue_length(int T, int bcch_conf);
-int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
- int is_ag_res);
+
+enum ccch_msgt {
+ CCCH_MSGT_AGCH,
+ CCCH_MSGT_PCH,
+ CCCH_MSGT_NCH,
+};
+
+int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, enum ccch_msgt ccch);
int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher);
uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time);
void regenerate_si3_restoctets(struct gsm_bts *bts);
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h
index 87e1a99..353fc90 100644
--- a/include/osmo-bts/l1sap.h
+++ b/include/osmo-bts/l1sap.h
@@ -146,6 +146,6 @@
int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
uint8_t *data, int len);
-int is_ccch_for_agch(struct gsm_bts_trx *trx, uint32_t fn);
+enum ccch_msgt get_ccch_msgt(struct gsm_bts_trx *trx, uint32_t fn);
#endif /* L1SAP_H */
diff --git a/include/osmo-bts/notification.h b/include/osmo-bts/notification.h
index 3d05acc..f8a7b48 100644
--- a/include/osmo-bts/notification.h
+++ b/include/osmo-bts/notification.h
@@ -55,3 +55,5 @@
const struct asci_notification *bts_asci_notification_get_next(struct gsm_bts *bts);
void append_group_call_information(struct bitvec *bv, const uint8_t *gcr, const uint8_t *ch_desc, uint8_t ch_desc_len);
+
+int bts_asci_notify_nch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf);
diff --git a/src/common/bts.c b/src/common/bts.c
index b4a5f80..7257f37 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -56,6 +56,7 @@
#include <osmo-bts/nm_common_fsm.h>
#include <osmo-bts/power_control.h>
#include <osmo-bts/osmux.h>
+#include <osmo-bts/notification.h>
#define MIN_QUAL_RACH 50 /* minimum link quality (in centiBels) for Access Bursts */
#define MIN_QUAL_NORM -5 /* minimum link quality (in centiBels) for Normal Bursts */
@@ -723,8 +724,7 @@
return;
}
-int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
- int is_ag_res)
+int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, enum ccch_msgt ccch)
{
struct msgb *msg = NULL;
int rc = 0;
@@ -737,17 +737,25 @@
*/
compact_agch_queue(bts);
- /* Check for paging messages first if this is PCH */
- if (!is_ag_res)
+ switch (ccch) {
+ case CCCH_MSGT_NCH:
+ /* Send NCH message, it has priority over AGCH and does not overlap with PCH. */
+ rc = bts_asci_notify_nch_gen_msg(bts, out_buf);
+ return rc;
+ case CCCH_MSGT_PCH:
+ /* Check whether the block may be overwritten by AGCH. */
rc = paging_gen_msg(bts->paging_state, out_buf, gt, &is_empty);
-
- /* Check whether the block may be overwritten */
- if (!is_empty)
- return rc;
-
- msg = bts_agch_dequeue(bts);
- if (!msg)
- return rc;
+ if (!is_empty)
+ return rc;
+ /* fall-through */
+ case CCCH_MSGT_AGCH:
+ /* If fallen here and the AGCH queue is empty, return empty PCH message. */
+ msg = bts_agch_dequeue(bts);
+ if (!msg)
+ return rc;
+ /* Continue to return AGCH message. */
+ break;
+ }
rate_ctr_inc2(bts->ctrs, BTS_CTR_AGCH_SENT);
@@ -756,7 +764,7 @@
rc = msgb_l3len(msg);
msgb_free(msg);
- if (is_ag_res)
+ if (ccch == CCCH_MSGT_AGCH)
bts->agch_queue.agch_msgs++;
else
bts->agch_queue.pch_msgs++;
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index 1c43f8f..268486e 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -902,15 +902,32 @@
return 0;
}
-/* Check if given CCCH frame number is for a PCH or for an AGCH (this function is
+/* Check if given CCCH frame number is for a NCH, PCH or for an AGCH (this function is
* only used internally, it is public to call it from unit-tests) */
-int is_ccch_for_agch(struct gsm_bts_trx *trx, uint32_t fn) {
+enum ccch_msgt get_ccch_msgt(struct gsm_bts_trx *trx, uint32_t fn)
+{
+ uint8_t block, first_block, num_blocks;
+ int rc;
+
+ block = l1sap_fn2ccch_block(fn);
+
+ /* If there is an NCH, check if the block number matches. It has priority over PCH/AGCH. */
+ if (trx->bts->asci.pos_nch >= 0) {
+ rc = osmo_gsm48_si1ro_nch_pos_decode(trx->bts->asci.pos_nch, &num_blocks, &first_block);
+ if (rc >= 0 && block >= first_block && block < first_block + num_blocks)
+ return CCCH_MSGT_NCH;
+ }
+
/* Note: The number of available access grant channels is set by the
* parameter BS_AG_BLKS_RES via system information type 3. This SI is
* transferred to osmo-bts via RSL */
- return l1sap_fn2ccch_block(fn) < num_agch(trx, "PH-RTS-IND");
+ if (l1sap_fn2ccch_block(fn) < num_agch(trx, "PH-RTS-IND"))
+ return CCCH_MSGT_AGCH;
+
+ return CCCH_MSGT_PCH;
}
+
/* return the measured average of frame numbers that the RTS clock is running in advance */
int32_t bts_get_avg_fn_advance(const struct gsm_bts *bts)
{
@@ -1048,7 +1065,6 @@
struct msgb *pp_msg;
bool dtxd_facch = false;
int rc;
- int is_ag_res;
chan_nr = rts_ind->chan_nr;
link_id = rts_ind->link_id;
@@ -1183,8 +1199,7 @@
}
} else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) {
p = msgb_put(msg, GSM_MACBLOCK_LEN);
- is_ag_res = is_ccch_for_agch(trx, fn);
- rc = bts_ccch_copy_msg(trx->bts, p, &g_time, is_ag_res);
+ rc = bts_ccch_copy_msg(trx->bts, p, &g_time, get_ccch_msgt(trx, fn));
if (rc <= 0)
memcpy(p, fill_frame, GSM_MACBLOCK_LEN);
}
diff --git a/src/common/notification.c b/src/common/notification.c
index 1fda519..35dc65f 100644
--- a/src/common/notification.c
+++ b/src/common/notification.c
@@ -71,6 +71,10 @@
/* add at beginning of "queue" to make sure a new call is notified first */
llist_add(&n->list, &bts->asci.notifications);
+ bts->asci.notification_entries++;
+ bts->asci.notification_count = 0;
+ bts->asci.nln = (bts->asci.nln + 1) % 4;
+
return 0;
}
@@ -86,6 +90,10 @@
llist_del(&n->list);
talloc_free(n);
+ bts->asci.notification_entries--;
+ bts->asci.notification_count = 0;
+ bts->asci.nln_status = (bts->asci.nln_status + 1) % 2;
+
return 0;
}
@@ -100,6 +108,11 @@
llist_del(&n->list);
talloc_free(n);
}
+
+ bts->asci.notification_entries = 0;
+ bts->asci.notification_count = 0;
+ bts->asci.nln_status = (bts->asci.nln_status + 1) % 2;
+
return 0;
}
@@ -153,3 +166,60 @@
bitvec_free(gcr_bv);
}
+
+#define L2_PLEN(len) (((len - 1) << 2) | 0x01)
+
+int bts_asci_notify_nch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf)
+{
+ struct gsm48_notification_nch *nn = (struct gsm48_notification_nch *) out_buf;
+ const struct asci_notification *notif;
+ unsigned int ro_len;
+
+ notif = bts_asci_notification_get_next(bts);
+
+ *nn = (struct gsm48_notification_nch) {
+ .proto_discr = GSM48_PDISC_RR,
+ .msg_type = GSM48_MT_RR_NOTIF_NCH,
+ };
+
+ nn->l2_plen = L2_PLEN(nn->data - out_buf);
+
+ /* Pad remaining octets with constant '2B'O */
+ ro_len = GSM_MACBLOCK_LEN - (nn->data - out_buf);
+ memset(nn->data, GSM_MACBLOCK_PADDING, ro_len);
+
+ struct bitvec bv = {
+ .data_len = ro_len,
+ .data = nn->data,
+ };
+
+ /* {0 | 1 < NLN(NCH) : bit (2) >}
+ * Only send NLN, at the last notifications.
+ * When the phone receives two NLN with the same value, it knows that all notifications has been received.
+ * Also send NLN if no notification is available. */
+ if (bts->asci.notification_count >= bts->asci.notification_entries - 1) {
+ bitvec_set_bit(&bv, 1);
+ bitvec_set_uint(&bv, bts->asci.nln, 2);
+ } else {
+ bitvec_set_bit(&bv, 0);
+ }
+
+ /* Count NLN. */
+ if (++bts->asci.notification_count >= bts->asci.notification_entries)
+ bts->asci.notification_count = 0;
+
+ /* < List of Group Call NCH information > ::=
+ * { 0 | 1 < Group Call information > < List of Group Call NCH information > } ; */
+ if (notif) {
+ bitvec_set_bit(&bv, 1);
+ append_group_call_information(&bv, notif->group_call_ref,
+ notif->chan_desc.present ? notif->chan_desc.value : NULL,
+ notif->chan_desc.len);
+ }
+ bitvec_set_bit(&bv, 0); /* End of list */
+
+ /* TODO: Additions in Release 6 */
+ /* TODO: Additions in Release 7 */
+
+ return GSM_MACBLOCK_LEN;
+}
diff --git a/tests/agch/agch_test.c b/tests/agch/agch_test.c
index 8ddc0f7..86c5c20 100644
--- a/tests/agch/agch_test.c
+++ b/tests/agch/agch_test.c
@@ -159,7 +159,7 @@
if (is_agch)
multiframes++;
- rc = bts_ccch_copy_msg(bts, out_buf, &g_time, is_agch);
+ rc = bts_ccch_copy_msg(bts, out_buf, &g_time, (is_agch) ? CCCH_MSGT_AGCH : CCCH_MSGT_PCH);
ima = (struct gsm48_imm_ass *)out_buf;
switch (ima->msg_type) {
case GSM48_MT_RR_IMM_ASS:
diff --git a/tests/paging/paging_test.c b/tests/paging/paging_test.c
index 26f5728..d48932b 100644
--- a/tests/paging/paging_test.c
+++ b/tests/paging/paging_test.c
@@ -144,7 +144,7 @@
* Table 5 of 9 must occur. */
static void test_is_ccch_for_agch(void)
{
- int is_ag_res;
+ enum ccch_msgt ccch;
int fn;
uint8_t bs_ag_blks_res;
struct gsm_bts_trx *trx;
@@ -172,8 +172,8 @@
/* Try allo possible settings for bs_ag_blks_res */
for (bs_ag_blks_res = 0; bs_ag_blks_res <= 7; bs_ag_blks_res++) {
trx = test_is_ccch_for_agch_setup(bs_ag_blks_res);
- is_ag_res = is_ccch_for_agch(trx, fn);
- printf(" %u", is_ag_res);
+ ccch = get_ccch_msgt(trx, fn);
+ printf(" %u", (ccch == CCCH_MSGT_AGCH));
}
printf("\n");
}
To view, visit change 33297. To unsubscribe, or for help writing mail filters, visit settings.