aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/bts.cpp6
-rw-r--r--src/bts.h5
-rw-r--r--src/gprs_ms.cpp1
-rw-r--r--src/gprs_ms.h2
-rw-r--r--src/gprs_rlcmac.cpp21
-rw-r--r--src/gprs_rlcmac.h3
-rw-r--r--src/gprs_rlcmac_sched.cpp89
-rw-r--r--src/pcu_l1_if.cpp39
9 files changed, 140 insertions, 29 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 233e24de..7148267b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,7 +69,8 @@ libgprs_la_SOURCES = \
gprs_codel.c \
coding_scheme.c \
gprs_coding_scheme.cpp \
- egprs_rlc_compression.cpp
+ egprs_rlc_compression.cpp \
+ gprs_rlcmac_sched.cpp
bin_PROGRAMS = \
osmo-pcu
diff --git a/src/bts.cpp b/src/bts.cpp
index 8b32e2ed..1b2ab2fb 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -231,6 +231,7 @@ BTS::BTS()
{
memset(&m_bts, 0, sizeof(m_bts));
m_bts.bts = this;
+ m_bts.app_info = NULL;
m_bts.dl_tbf_preemptive_retransmission = true;
m_bts.T_defs_bts = T_defs_bts;
m_bts.T_defs_pcu = T_defs_pcu;
@@ -279,6 +280,11 @@ void BTS::cleanup()
osmo_stat_item_group_free(m_statg);
m_statg = NULL;
}
+
+ if (m_bts.app_info) {
+ msgb_free(m_bts.app_info);
+ m_bts.app_info = NULL;
+ }
}
BTS::~BTS()
diff --git a/src/bts.h b/src/bts.h
index 6d92ae15..6af6d520 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -164,6 +164,11 @@ struct gprs_rlcmac_bts {
/* Are we talking Gb with IP-SNS (true) or classic Gb? */
bool gb_dialect_sns;
+
+ /* Packet Application Information (3GPP TS 44.060 11.2.47, usually ETWS primary message). We don't need to store
+ * more than one message, because they get sent so rarely. */
+ struct msgb *app_info;
+ uint32_t app_info_pending; /* Count of MS with active TBF, to which we did not send app_info yet */
};
#ifdef __cplusplus
diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp
index 19f2ecb2..75f75e17 100644
--- a/src/gprs_ms.cpp
+++ b/src/gprs_ms.cpp
@@ -135,6 +135,7 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
gprs_codel_set_interval(m_codel_state, codel_interval);
}
m_last_cs_not_low = now_msec();
+ app_info_pending = false;
}
GprsMs::~GprsMs()
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index ad8ca1da..781dd59f 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -136,6 +136,8 @@ public:
/* internal use */
static void timeout(void *priv_);
+ bool app_info_pending;
+
protected:
void update_status();
GprsMs *ref();
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 5a223c13..4d93f8f0 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -41,4 +41,25 @@ int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
return 0;
}
+/* Encode Application Information Request to Packet Application Information (3GPP TS 44.060 11.2.47) */
+struct msgb *gprs_rlcmac_app_info_msg(const struct gsm_pcu_if_app_info_req *req) {
+ struct msgb *msg;
+ uint16_t msgb_len = req->len + 1;
+ struct bitvec bv = {0, msgb_len, NULL};
+ const enum bit_value page_mode[] = {ZERO, ZERO}; /* Normal Paging (3GPP TS 44.060 12.20) */
+ if (!req->len) {
+ LOGP(DRLCMAC, LOGL_ERROR, "Application Information Request with zero length received!\n");
+ return NULL;
+ }
+
+ msg = msgb_alloc(msgb_len, "app_info_msg");
+ if (!msg)
+ return NULL;
+
+ bv.data = msgb_put(msg, msgb_len);
+ bitvec_set_bits(&bv, page_mode, 2);
+ bitvec_set_uint(&bv, req->application_type, 4);
+ bitvec_set_bytes(&bv, req->data, req->len);
+ return msg;
+}
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index 7a3a7af5..16cb05f2 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -31,6 +31,7 @@ extern "C" {
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/bitvec.h>
+#include <osmocom/pcu/pcuif_proto.h>
}
#endif
@@ -94,6 +95,8 @@ int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
const char *imsi);
+struct msgb *gprs_rlcmac_app_info_msg(const struct gsm_pcu_if_app_info_req *req);
+
int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts,
uint32_t fn, uint8_t block_nr);
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 57756e3b..7356523f 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -123,6 +123,34 @@ static uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
return usf;
}
+struct msgb *sched_app_info(struct gprs_rlcmac_tbf *tbf) {
+ struct gprs_rlcmac_bts *bts_data;
+ struct msgb *msg = NULL;
+
+ if (!tbf || !tbf->ms()->app_info_pending)
+ return NULL;
+
+ bts_data = BTS::main_bts()->bts_data();
+
+ if (bts_data->app_info) {
+ LOGP(DRLCMACSCHED, LOGL_DEBUG, "Sending Packet Application Information message\n");
+ msg = msgb_copy(bts_data->app_info, "app_info_msg_sched");
+ } else
+ LOGP(DRLCMACSCHED, LOGL_ERROR, "MS has app_info_pending flag set, but no Packet Application Information"
+ " message stored in BTS!\n");
+
+ tbf->ms()->app_info_pending = false;
+ bts_data->app_info_pending--;
+
+ if (!bts_data->app_info_pending) {
+ LOGP(DRLCMACSCHED, LOGL_DEBUG, "Packet Application Information successfully sent to all MS with active"
+ " TBF\n");
+ msgb_free(bts_data->app_info);
+ bts_data->app_info = NULL;
+ }
+ return msg;
+}
+
static struct msgb *sched_select_ctrl_msg(
uint8_t trx, uint8_t ts, uint32_t fn,
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch,
@@ -134,37 +162,42 @@ static struct msgb *sched_select_ctrl_msg(
struct gprs_rlcmac_tbf *tbf = NULL;
struct gprs_rlcmac_tbf *next_list[3] = { ul_ass_tbf, dl_ass_tbf, ul_ack_tbf };
- for (size_t i = 0; i < ARRAY_SIZE(next_list); ++i) {
- tbf = next_list[(pdch->next_ctrl_prio + i) % 3];
- if (!tbf)
- continue;
+ /* Send Packet Application Information first (ETWS primary notifications) */
+ msg = sched_app_info(dl_ass_tbf);
- /*
- * Assignments for the same direction have lower precedence,
- * because they may kill the TBF when the CONTROL ACK is
- * received, thus preventing the others from being processed.
- */
- if (tbf == ul_ass_tbf && tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))
- msg = ul_ass_tbf->create_packet_access_reject();
- else if (tbf == ul_ass_tbf && tbf->direction ==
- GPRS_RLCMAC_DL_TBF)
- if (tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))
+ if (!msg) {
+ for (size_t i = 0; i < ARRAY_SIZE(next_list); ++i) {
+ tbf = next_list[(pdch->next_ctrl_prio + i) % 3];
+ if (!tbf)
+ continue;
+
+ /*
+ * Assignments for the same direction have lower precedence,
+ * because they may kill the TBF when the CONTROL ACK is
+ * received, thus preventing the others from being processed.
+ */
+ if (tbf == ul_ass_tbf && tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))
msg = ul_ass_tbf->create_packet_access_reject();
- else
- msg = ul_ass_tbf->create_ul_ass(fn, ts);
- else if (tbf == dl_ass_tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
- msg = dl_ass_tbf->create_dl_ass(fn, ts);
- else if (tbf == ul_ack_tbf)
- msg = ul_ack_tbf->create_ul_ack(fn, ts);
-
- if (!msg) {
- tbf = NULL;
- continue;
+ else if (tbf == ul_ass_tbf && tbf->direction ==
+ GPRS_RLCMAC_DL_TBF)
+ if (tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))
+ msg = ul_ass_tbf->create_packet_access_reject();
+ else
+ msg = ul_ass_tbf->create_ul_ass(fn, ts);
+ else if (tbf == dl_ass_tbf && tbf->direction == GPRS_RLCMAC_UL_TBF)
+ msg = dl_ass_tbf->create_dl_ass(fn, ts);
+ else if (tbf == ul_ack_tbf)
+ msg = ul_ack_tbf->create_ul_ack(fn, ts);
+
+ if (!msg) {
+ tbf = NULL;
+ continue;
+ }
+
+ pdch->next_ctrl_prio += 1;
+ pdch->next_ctrl_prio %= 3;
+ break;
}
-
- pdch->next_ctrl_prio += 1;
- pdch->next_ctrl_prio %= 3;
- break;
}
if (!msg) {
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index 6ffebcf6..8901ce6f 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -620,6 +620,42 @@ static int pcu_rx_susp_req(struct gsm_pcu_if_susp_req *susp_req)
return bssgp_tx_suspend(bctx->nsei, susp_req->tlli, &ra_id);
}
+static int pcu_rx_app_info_req(struct gsm_pcu_if_app_info_req *app_info_req)
+{
+ LListHead<GprsMs> *ms_iter;
+ BTS *bts = BTS::main_bts();
+ struct gprs_rlcmac_bts *bts_data = bts->bts_data();
+
+ LOGP(DL1IF, LOGL_DEBUG, "Application Information Request received: type=0x%08x len=%i\n",
+ app_info_req->application_type, app_info_req->len);
+
+ bts_data->app_info_pending = 0;
+ llist_for_each(ms_iter, &bts->ms_store().ms_list()) {
+ GprsMs *ms = ms_iter->entry();
+ if (!ms->dl_tbf())
+ continue;
+ bts_data->app_info_pending++;
+ ms->app_info_pending = true;
+ }
+
+ if (!bts_data->app_info_pending) {
+ LOGP(DL1IF, LOGL_NOTICE, "Packet Application Information will not be sent, no subscribers with active"
+ " TBF\n");
+ return -1;
+ }
+
+ if (bts_data->app_info) {
+ LOGP(DL1IF, LOGL_NOTICE, "Previous Packet Application Information was not sent to all subscribers,"
+ " overwriting with new one\n");
+ msgb_free(bts_data->app_info);
+ }
+
+ LOGP(DL1IF, LOGL_INFO, "Sending Packet Application Information to %i subscribers with active TBF\n",
+ bts_data->app_info_pending);
+ bts_data->app_info = gprs_rlcmac_app_info_msg(app_info_req);
+ return 0;
+}
+
int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
{
int rc = 0;
@@ -649,6 +685,9 @@ int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
case PCU_IF_MSG_SUSP_REQ:
rc = pcu_rx_susp_req(&pcu_prim->u.susp_req);
break;
+ case PCU_IF_MSG_APP_INFO_REQ:
+ rc = pcu_rx_app_info_req(&pcu_prim->u.app_info_req);
+ break;
default:
LOGP(DL1IF, LOGL_ERROR, "Received unknown PCU msg type %d\n",
msg_type);