mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn.git
synced 2025-10-23 00:11:57 +00:00
ranap: Take into account RNC availability during paging
Avoid transmitting a RANAP paging message to an RNC if we already know it's not currently available over SCCP. Take into account that information when deciding/printing whether the paging could be sent or not. Take the chance to clean up the iu paging function helpers inherited from osmo-iuh iu_client.c to better fit the data domain in osmo-sgsn (iu_rnc). Change-Id: I24e5446bcf4c958028577230b231960acea9e5b9
This commit is contained in:
@@ -30,9 +30,6 @@ int sgsn_ranap_iu_tx_rab_ps_ass_req(struct ranap_ue_conn_ctx *ue_ctx,
|
||||
int sgsn_ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec,
|
||||
int send_ck, int new_key);
|
||||
int sgsn_ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *ue_ctx, const char *imsi);
|
||||
int sgsn_ranap_iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
|
||||
const char *imsi, const uint32_t *tmsi,
|
||||
bool is_ps, uint32_t paging_cause);
|
||||
|
||||
int sgsn_ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause);
|
||||
/* Transmit a Iu Release Command and submit event RANAP_IU_EVENT_IU_RELEASE upon
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/defs.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
@@ -43,6 +44,12 @@ void iu_rnc_update_rai_seen(struct ranap_iu_rnc *rnc, const struct osmo_routing_
|
||||
|
||||
void iu_rnc_discard_all_ue_ctx(struct ranap_iu_rnc *rnc);
|
||||
|
||||
int iu_rnc_tx_paging_cmd(struct ranap_iu_rnc *rnc,
|
||||
const char *imsi,
|
||||
const uint32_t *tmsi,
|
||||
bool is_ps,
|
||||
uint32_t paging_cause);
|
||||
|
||||
#define LOG_RNC_CAT(IU_RNC, subsys, loglevel, fmt, args ...) \
|
||||
LOGPFSMSL((IU_RNC)->fi, subsys, loglevel, fmt, ## args)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ enum iu_rnc_event {
|
||||
IU_RNC_EV_MSG_UP_CO, /* struct iu_rnc_ev_msg_up_co_ctx* */
|
||||
IU_RNC_EV_RX_RESET, /* no param */
|
||||
IU_RNC_EV_RX_RESET_ACK, /* no param */
|
||||
IU_RNC_EV_MSG_DOWN_CL, /* struct msgb* */
|
||||
IU_RNC_EV_AVAILABLE,
|
||||
IU_RNC_EV_UNAVAILABLE
|
||||
};
|
||||
|
||||
@@ -287,22 +287,6 @@ int sgsn_ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *uectx, const char *imsi
|
||||
return sgsn_scu_iups_tx_data_req(uectx->rnc->scu_iups, uectx->conn_id, msg);
|
||||
}
|
||||
|
||||
/* Send a paging command down a given SCCP User. tmsi and paging_cause are
|
||||
* optional and may be passed NULL and 0, respectively, to disable their use.
|
||||
* See enum RANAP_PagingCause.
|
||||
*
|
||||
* If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
|
||||
* the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
|
||||
int sgsn_ranap_iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
|
||||
const char *imsi, const uint32_t *tmsi,
|
||||
bool is_ps, uint32_t paging_cause)
|
||||
{
|
||||
struct msgb *msg;
|
||||
msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps ? 1 : 0, paging_cause);
|
||||
msg->l2h = msg->data;
|
||||
return osmo_sccp_tx_unitdata_msg(sgsn->sccp.scu_iups->scu, &sgsn->sccp.scu_iups->local_sccp_addr, called_addr, msg);
|
||||
}
|
||||
|
||||
int sgsn_ranap_iu_tx(struct msgb *msg_nas, uint8_t sapi)
|
||||
{
|
||||
struct ranap_ue_conn_ctx *uectx = msg_nas->dst;
|
||||
|
||||
@@ -43,12 +43,6 @@
|
||||
#include <osmocom/sgsn/sccp.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
|
||||
#define LOGPIU(level, fmt, args...) \
|
||||
LOGP(DRANAP, level, fmt, ## args)
|
||||
|
||||
#define LOGPIUC(level, fmt, args...) \
|
||||
LOGPC(DRANAP, level, fmt, ## args)
|
||||
|
||||
const struct value_string iu_client_event_type_names[] = {
|
||||
OSMO_VALUE_STRING(RANAP_IU_EVENT_RAB_ASSIGN),
|
||||
OSMO_VALUE_STRING(RANAP_IU_EVENT_SECURITY_MODE_COMPLETE),
|
||||
@@ -66,7 +60,7 @@ int global_iu_event(struct ranap_ue_conn_ctx *ue_ctx,
|
||||
if (ue_ctx && !ue_ctx->notification)
|
||||
return 0;
|
||||
|
||||
LOGPIU(LOGL_DEBUG, "Submit Iu event to upper layer: %s\n", iu_client_event_type_str(type));
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Submit Iu event to upper layer: %s\n", iu_client_event_type_str(type));
|
||||
|
||||
return sgsn_ranap_iu_event(ue_ctx, type, data);
|
||||
}
|
||||
@@ -126,78 +120,74 @@ void ue_conn_ctx_link_invalidated_free(struct ranap_ue_conn_ctx *ue)
|
||||
***********************************************************************/
|
||||
|
||||
/* legacy, do a first match with ignoring PLMN */
|
||||
static bool iu_rnc_lac_rac_find_legacy(struct ranap_iu_rnc **rnc, struct iu_lac_rac_entry **lre,
|
||||
uint16_t lac, uint8_t rac)
|
||||
{
|
||||
struct ranap_iu_rnc *r;
|
||||
struct iu_lac_rac_entry *e;
|
||||
|
||||
if (rnc)
|
||||
*rnc = NULL;
|
||||
if (lre)
|
||||
*lre = NULL;
|
||||
|
||||
llist_for_each_entry(r, &sgsn->rnc_list, entry) {
|
||||
llist_for_each_entry(e, &r->lac_rac_list, entry) {
|
||||
if (e->rai.lac.lac == lac && e->rai.rac == rac) {
|
||||
if (rnc)
|
||||
*rnc = r;
|
||||
if (lre)
|
||||
*lre = e;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptmsi,
|
||||
uint16_t lac, uint8_t rac, bool is_ps)
|
||||
static struct ranap_iu_rnc *iu_rnc_lac_rac_find_legacy(uint16_t lac, uint8_t rac)
|
||||
{
|
||||
struct ranap_iu_rnc *rnc;
|
||||
const char *log_msg;
|
||||
int log_level;
|
||||
int paged = 0;
|
||||
struct iu_lac_rac_entry *e;
|
||||
|
||||
iu_rnc_lac_rac_find_legacy(&rnc, NULL, lac, rac);
|
||||
if (rnc) {
|
||||
if (sgsn_ranap_iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi_or_ptmsi, is_ps, 0) == 0) {
|
||||
log_msg = "Paging";
|
||||
log_level = LOGL_DEBUG;
|
||||
paged = 1;
|
||||
} else {
|
||||
log_msg = "Paging failed";
|
||||
log_level = LOGL_ERROR;
|
||||
llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
|
||||
llist_for_each_entry(e, &rnc->lac_rac_list, entry) {
|
||||
if (e->rai.lac.lac == lac && e->rai.rac == rac)
|
||||
return rnc;
|
||||
}
|
||||
} else {
|
||||
log_msg = "Found no RNC to Page";
|
||||
log_level = LOGL_ERROR;
|
||||
}
|
||||
|
||||
if (is_ps)
|
||||
LOGPIU(log_level, "IuPS: %s on LAC %d RAC %d", log_msg, lac, rac);
|
||||
else
|
||||
LOGPIU(log_level, "IuCS: %s on LAC %d", log_msg, lac);
|
||||
if (rnc)
|
||||
LOGPIUC(log_level, " at SCCP-addr %s", osmo_sccp_addr_dump(&rnc->sccp_addr));
|
||||
if (tmsi_or_ptmsi)
|
||||
LOGPIUC(log_level, ", for %s %08x\n", is_ps ? "PTMSI" : "TMSI", *tmsi_or_ptmsi);
|
||||
else
|
||||
LOGPIUC(log_level, ", for IMSI %s\n", imsi);
|
||||
|
||||
return paged;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Old paging() doesn't use PLMN and transmit paging command only to the first RNC */
|
||||
int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
|
||||
{
|
||||
return iu_page(imsi, tmsi, lac, 0, false);
|
||||
struct ranap_iu_rnc *rnc;
|
||||
char log_msg[32] = {};
|
||||
int rc;
|
||||
|
||||
if (tmsi)
|
||||
snprintf(log_msg, sizeof(log_msg), "TMSI %08x\n", *tmsi);
|
||||
else
|
||||
snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);
|
||||
|
||||
rnc = iu_rnc_lac_rac_find_legacy(lac, 0);
|
||||
if (!rnc) {
|
||||
LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page CS on LAC %u for %s",
|
||||
lac, log_msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = iu_rnc_tx_paging_cmd(rnc, imsi, tmsi, false, 0);
|
||||
if (rc != 0) {
|
||||
LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging CS for LAC %u for %s",
|
||||
lac, log_msg);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*! Old paging() doesn't use PLMN and transmit paging command only to the first RNC */
|
||||
int ranap_iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac)
|
||||
{
|
||||
return iu_page(imsi, ptmsi, lac, rac, true);
|
||||
struct ranap_iu_rnc *rnc;
|
||||
char log_msg[32] = {};
|
||||
int rc;
|
||||
|
||||
if (ptmsi)
|
||||
snprintf(log_msg, sizeof(log_msg), "P-TMSI %08x\n", *ptmsi);
|
||||
else
|
||||
snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);
|
||||
|
||||
rnc = iu_rnc_lac_rac_find_legacy(lac, rac);
|
||||
if (!rnc) {
|
||||
LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page PS on LAC %u RAC %u for %s",
|
||||
lac, rac, log_msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = iu_rnc_tx_paging_cmd(rnc, imsi, ptmsi, true, 0);
|
||||
if (rc != 0) {
|
||||
LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging PS for LAC %u RAC %u for %s",
|
||||
lac, rac, log_msg);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*! Transmit a single page request towards all RNCs serving the specific LAI (no page retransmission).
|
||||
@@ -212,8 +202,13 @@ int ranap_iu_page_cs2(const char *imsi, const uint32_t *tmsi, const struct osmo_
|
||||
struct ranap_iu_rnc *rnc;
|
||||
struct iu_lac_rac_entry *entry;
|
||||
char log_msg[32] = {};
|
||||
int paged = 0;
|
||||
int rc = 0;
|
||||
unsigned int paged = 0;
|
||||
int rc;
|
||||
|
||||
if (tmsi)
|
||||
snprintf(log_msg, sizeof(log_msg), "TMSI %08x\n", *tmsi);
|
||||
else
|
||||
snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);
|
||||
|
||||
/* find all RNCs which are serving this LA */
|
||||
llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
|
||||
@@ -221,27 +216,23 @@ int ranap_iu_page_cs2(const char *imsi, const uint32_t *tmsi, const struct osmo_
|
||||
if (osmo_lai_cmp(&entry->rai.lac, lai))
|
||||
continue;
|
||||
|
||||
rc = sgsn_ranap_iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi, false, 0);
|
||||
if (rc > 0) {
|
||||
LOGPIU(LOGL_ERROR, "IuCS: Failed to tx Paging RNC %s for LAC %s for IMSI %s / TMSI %08x",
|
||||
osmo_rnc_id_name(&rnc->rnc_id),
|
||||
osmo_lai_name(lai), imsi, tmsi ? *tmsi : GSM_RESERVED_TMSI);
|
||||
rc = iu_rnc_tx_paging_cmd(rnc, imsi, tmsi, false, 0);
|
||||
if (rc != 0) {
|
||||
LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging CS for LAI %s for %s",
|
||||
osmo_lai_name(lai), log_msg);
|
||||
} else {
|
||||
paged++;
|
||||
}
|
||||
paged++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmsi)
|
||||
snprintf(log_msg, sizeof(log_msg), "for TMSI %08x\n", *tmsi);
|
||||
else
|
||||
snprintf(log_msg, sizeof(log_msg) - 1, "for IMSI %s\n", imsi);
|
||||
|
||||
if (paged)
|
||||
LOGPIU(LOGL_DEBUG, "IuPS: Paged %d RNCs on LAI %s for %s", paged, osmo_lai_name(lai), log_msg);
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Paged CS %u RNCs on LAI %s for %s",
|
||||
paged, osmo_lai_name(lai), log_msg);
|
||||
else
|
||||
LOGPIU(LOGL_INFO, "IuPS: Found no RNC to Page on LAI %s for %s", osmo_lai_name(lai), log_msg);
|
||||
|
||||
LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page CS on LAI %s for %s",
|
||||
osmo_lai_name(lai), log_msg);
|
||||
|
||||
return paged;
|
||||
}
|
||||
@@ -249,7 +240,7 @@ int ranap_iu_page_cs2(const char *imsi, const uint32_t *tmsi, const struct osmo_
|
||||
/*! Transmit a single page request towards all RNCs serving the specific RAI (no page retransmission).
|
||||
*
|
||||
* \param imsi the imsi as human readable string
|
||||
* \param ptmsi NULL or pointer to the tmsi
|
||||
* \param ptmsi NULL or pointer to the ptmsi
|
||||
* \param rai full Location Area Identifier
|
||||
* \return amount of paged RNCs. 0 when no RNC found.
|
||||
*/
|
||||
@@ -258,8 +249,13 @@ int ranap_iu_page_ps2(const char *imsi, const uint32_t *ptmsi, const struct osmo
|
||||
struct ranap_iu_rnc *rnc;
|
||||
struct iu_lac_rac_entry *entry;
|
||||
char log_msg[32] = {};
|
||||
int paged = 0;
|
||||
int rc = 0;
|
||||
unsigned int paged = 0;
|
||||
int rc;
|
||||
|
||||
if (ptmsi)
|
||||
snprintf(log_msg, sizeof(log_msg), "P-TMSI %08x\n", *ptmsi);
|
||||
else
|
||||
snprintf(log_msg, sizeof(log_msg), "IMSI %s\n", imsi);
|
||||
|
||||
/* find all RNCs which are serving this RAC */
|
||||
llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
|
||||
@@ -267,26 +263,23 @@ int ranap_iu_page_ps2(const char *imsi, const uint32_t *ptmsi, const struct osmo
|
||||
if (osmo_rai_cmp(&entry->rai, rai))
|
||||
continue;
|
||||
|
||||
rc = sgsn_ranap_iu_tx_paging_cmd(&rnc->sccp_addr, imsi, ptmsi, true, 0);
|
||||
if (rc > 0) {
|
||||
LOGPIU(LOGL_ERROR, "IuPS: Failed to tx Paging RNC %s for RAC %s for IMSI %s / P-TMSI %08x",
|
||||
osmo_rnc_id_name(&rnc->rnc_id),
|
||||
osmo_rai_name2(rai), imsi, ptmsi ? *ptmsi : GSM_RESERVED_TMSI);
|
||||
rc = iu_rnc_tx_paging_cmd(rnc, imsi, ptmsi, true, 0);
|
||||
if (rc != 0) {
|
||||
LOG_RNC(rnc, LOGL_ERROR, "Failed to tx Paging PS for RAI %s for %s",
|
||||
osmo_rai_name2(rai), log_msg);
|
||||
} else {
|
||||
paged++;
|
||||
}
|
||||
paged++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptmsi)
|
||||
snprintf(log_msg, sizeof(log_msg) - 1, "for PTMSI %08x\n", *ptmsi);
|
||||
else
|
||||
snprintf(log_msg, sizeof(log_msg) - 1, "for IMSI %s\n", imsi);
|
||||
|
||||
if (paged)
|
||||
LOGPIU(LOGL_DEBUG, "IuPS: Paged %d RNCs on RAI %s for %s", paged, osmo_rai_name2(rai), log_msg);
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Paged PS %u RNCs on RAI %s for %s",
|
||||
paged, osmo_rai_name2(rai), log_msg);
|
||||
else
|
||||
LOGPIU(LOGL_INFO, "IuPS: Found no RNC to Page on RAI %s for %s", osmo_rai_name2(rai), log_msg);
|
||||
LOGP(DRANAP, LOGL_INFO, "Found no RNC to Page PS on RAI %s for %s",
|
||||
osmo_rai_name2(rai), log_msg);
|
||||
|
||||
return paged;
|
||||
}
|
||||
|
||||
@@ -213,3 +213,43 @@ void iu_rnc_discard_all_ue_ctx(struct ranap_iu_rnc *rnc)
|
||||
ue_conn_ctx_link_invalidated_free(ue_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a paging command down a given SCCP User. tmsi_or_ptmsi and paging_cause are
|
||||
* optional and may be passed NULL and 0, respectively, to disable their use.
|
||||
* See enum RANAP_PagingCause.
|
||||
*
|
||||
* If tmsi_or_ptmsi is given, the imsi is not sent over the air interface.
|
||||
* Nevertheless, the IMSI is still required for resolution in the HNB-GW
|
||||
* and/or(?) RNC.
|
||||
*
|
||||
* returns negative if paging couldn't be sent (eg. because RNC is currently
|
||||
* unreachable in lower layers).
|
||||
**/
|
||||
int iu_rnc_tx_paging_cmd(struct ranap_iu_rnc *rnc,
|
||||
const char *imsi,
|
||||
const uint32_t *tmsi_or_ptmsi,
|
||||
bool is_ps,
|
||||
uint32_t paging_cause)
|
||||
{
|
||||
struct msgb *ranap_msg;
|
||||
int rc;
|
||||
|
||||
/* rnc is not ready for paging (link not ready). */
|
||||
if (rnc->fi->state != IU_RNC_ST_READY)
|
||||
return -ENOLINK;
|
||||
|
||||
LOG_RNC(rnc, LOGL_DEBUG, "Paging %s for %s=%08x IMSI=%s\n",
|
||||
is_ps ? "PS" : "CS",
|
||||
is_ps ? "P-TMSI" : "TMSI",
|
||||
tmsi_or_ptmsi ? *tmsi_or_ptmsi : GSM_RESERVED_TMSI,
|
||||
imsi);
|
||||
|
||||
ranap_msg = ranap_new_msg_paging_cmd(imsi, tmsi_or_ptmsi, is_ps ? 1 : 0, paging_cause);
|
||||
if (!ranap_msg)
|
||||
return -EINVAL;
|
||||
|
||||
rc = osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_MSG_DOWN_CL, ranap_msg);
|
||||
if (rc != 0)
|
||||
msgb_free(ranap_msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ static const struct value_string iu_rnc_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(IU_RNC_EV_MSG_UP_CO),
|
||||
OSMO_VALUE_STRING(IU_RNC_EV_RX_RESET),
|
||||
OSMO_VALUE_STRING(IU_RNC_EV_RX_RESET_ACK),
|
||||
OSMO_VALUE_STRING(IU_RNC_EV_MSG_DOWN_CL),
|
||||
OSMO_VALUE_STRING(IU_RNC_EV_AVAILABLE),
|
||||
OSMO_VALUE_STRING(IU_RNC_EV_UNAVAILABLE),
|
||||
{}
|
||||
@@ -252,6 +253,11 @@ static void iu_rnc_st_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data
|
||||
iu_rnc_rx_reset(rnc);
|
||||
return;
|
||||
|
||||
case IU_RNC_EV_MSG_DOWN_CL:
|
||||
OSMO_ASSERT(data);
|
||||
sgsn_ranap_iu_tx_cl(rnc->scu_iups, &rnc->sccp_addr, (struct msgb *)data);
|
||||
return;
|
||||
|
||||
case IU_RNC_EV_AVAILABLE:
|
||||
/* Do nothing, we were already up. */
|
||||
return;
|
||||
@@ -336,6 +342,7 @@ static const struct osmo_fsm_state iu_rnc_fsm_states[] = {
|
||||
| S(IU_RNC_EV_RX_RESET)
|
||||
| S(IU_RNC_EV_MSG_UP_CO_INITIAL)
|
||||
| S(IU_RNC_EV_MSG_UP_CO)
|
||||
| S(IU_RNC_EV_MSG_DOWN_CL)
|
||||
| S(IU_RNC_EV_AVAILABLE)
|
||||
| S(IU_RNC_EV_UNAVAILABLE)
|
||||
,
|
||||
|
||||
Reference in New Issue
Block a user