mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-smlc.git
synced 2025-11-03 13:43:35 +00:00
smlc: Initial implementation of N-PCSTATE.ind
Related: OS#5917 Change-Id: Id034a0c4d8bff0647a64658480dfa9b4cea563de
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/gsm/gsm0808.h>
|
||||
#include <osmocom/sigtran/sccp_sap.h>
|
||||
@@ -49,6 +51,8 @@ enum lb_peer_event {
|
||||
LB_PEER_EV_MSG_DOWN_CO,
|
||||
LB_PEER_EV_RX_RESET,
|
||||
LB_PEER_EV_RX_RESET_ACK,
|
||||
LB_PEER_EV_AVAILABLE,
|
||||
LB_PEER_EV_UNAVAILABLE,
|
||||
};
|
||||
|
||||
struct lb_peer_ev_ctx {
|
||||
@@ -59,6 +63,7 @@ struct lb_peer_ev_ctx {
|
||||
|
||||
struct lb_peer *lb_peer_find_or_create(struct sccp_lb_inst *sli, const struct osmo_sccp_addr *peer_addr);
|
||||
struct lb_peer *lb_peer_find(const struct sccp_lb_inst *sli, const struct osmo_sccp_addr *peer_addr);
|
||||
struct lb_peer *lb_peer_find_by_pc(const struct sccp_lb_inst *sli, uint32_t pc);
|
||||
|
||||
int lb_peer_up_l2(struct sccp_lb_inst *sli, const struct osmo_sccp_addr *calling_addr, bool co, uint32_t conn_id,
|
||||
struct msgb *l2);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2019-2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
@@ -80,6 +80,15 @@ struct lb_peer *lb_peer_find(const struct sccp_lb_inst *sli, const struct osmo_s
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find an lb_peer by its remote SCCP address */
|
||||
struct lb_peer *lb_peer_find_by_pc(const struct sccp_lb_inst *sli, uint32_t pc)
|
||||
{
|
||||
struct osmo_sccp_addr rem_addr;
|
||||
|
||||
osmo_sccp_make_addr_pc_ssn(&rem_addr, pc, OSMO_SCCP_SSN_BSC_BSSAP_LE);
|
||||
return lb_peer_find(sli, &rem_addr);
|
||||
}
|
||||
|
||||
static const struct osmo_tdef_state_timeout lb_peer_fsm_timeouts[32] = {
|
||||
[LB_PEER_ST_WAIT_RX_RESET_ACK] = { .T = -13 },
|
||||
[LB_PEER_ST_DISCARDING] = { .T = -14 },
|
||||
@@ -235,6 +244,15 @@ static void lb_peer_st_wait_rx_reset(struct osmo_fsm_inst *fi, uint32_t event, v
|
||||
lb_peer_rx_reset(lbp, msg);
|
||||
return;
|
||||
|
||||
case LB_PEER_EV_AVAILABLE:
|
||||
/* Send a RESET to the peer. */
|
||||
lb_peer_reset(lbp);
|
||||
return;
|
||||
|
||||
case LB_PEER_EV_UNAVAILABLE:
|
||||
/* Do nothing, wait for peer to come up again. */
|
||||
return;
|
||||
|
||||
default:
|
||||
LOG_LB_PEER(lbp, LOGL_ERROR, "Unhandled event: %s\n", osmo_fsm_event_name(&lb_peer_fsm, event));
|
||||
return;
|
||||
@@ -270,6 +288,15 @@ static void lb_peer_st_wait_rx_reset_ack(struct osmo_fsm_inst *fi, uint32_t even
|
||||
lb_peer_rx_reset(lbp, msg);
|
||||
return;
|
||||
|
||||
case LB_PEER_EV_AVAILABLE:
|
||||
/* Send a RESET to the peer. */
|
||||
lb_peer_reset(lbp);
|
||||
return;
|
||||
|
||||
case LB_PEER_EV_UNAVAILABLE:
|
||||
lb_peer_state_chg(lbp, LB_PEER_ST_WAIT_RX_RESET);
|
||||
return;
|
||||
|
||||
default:
|
||||
LOG_LB_PEER(lbp, LOGL_ERROR, "Unhandled event: %s\n", osmo_fsm_event_name(&lb_peer_fsm, event));
|
||||
return;
|
||||
@@ -334,6 +361,16 @@ static void lb_peer_st_ready(struct osmo_fsm_inst *fi, uint32_t event, void *dat
|
||||
lb_peer_rx_reset(lbp, msg);
|
||||
return;
|
||||
|
||||
case LB_PEER_EV_AVAILABLE:
|
||||
/* Send a RESET to the peer. */
|
||||
lb_peer_reset(lbp);
|
||||
return;
|
||||
|
||||
case LB_PEER_EV_UNAVAILABLE:
|
||||
lb_peer_discard_all_conns(lbp);
|
||||
lb_peer_state_chg(lbp, LB_PEER_ST_WAIT_RX_RESET);
|
||||
return;
|
||||
|
||||
default:
|
||||
LOG_LB_PEER(lbp, LOGL_ERROR, "Unhandled event: %s\n", osmo_fsm_event_name(&lb_peer_fsm, event));
|
||||
return;
|
||||
@@ -363,6 +400,8 @@ static const struct value_string lb_peer_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(LB_PEER_EV_MSG_DOWN_CO),
|
||||
OSMO_VALUE_STRING(LB_PEER_EV_RX_RESET),
|
||||
OSMO_VALUE_STRING(LB_PEER_EV_RX_RESET_ACK),
|
||||
OSMO_VALUE_STRING(LB_PEER_EV_AVAILABLE),
|
||||
OSMO_VALUE_STRING(LB_PEER_EV_UNAVAILABLE),
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -376,6 +415,8 @@ static const struct osmo_fsm_state lb_peer_fsm_states[] = {
|
||||
| S(LB_PEER_EV_RX_RESET)
|
||||
| S(LB_PEER_EV_MSG_UP_CO_INITIAL)
|
||||
| S(LB_PEER_EV_MSG_UP_CO)
|
||||
| S(LB_PEER_EV_AVAILABLE)
|
||||
| S(LB_PEER_EV_UNAVAILABLE)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(LB_PEER_ST_WAIT_RX_RESET)
|
||||
@@ -392,6 +433,8 @@ static const struct osmo_fsm_state lb_peer_fsm_states[] = {
|
||||
| S(LB_PEER_EV_RX_RESET_ACK)
|
||||
| S(LB_PEER_EV_MSG_UP_CO_INITIAL)
|
||||
| S(LB_PEER_EV_MSG_UP_CO)
|
||||
| S(LB_PEER_EV_AVAILABLE)
|
||||
| S(LB_PEER_EV_UNAVAILABLE)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(LB_PEER_ST_WAIT_RX_RESET)
|
||||
@@ -410,6 +453,8 @@ static const struct osmo_fsm_state lb_peer_fsm_states[] = {
|
||||
| S(LB_PEER_EV_MSG_DOWN_CO_INITIAL)
|
||||
| S(LB_PEER_EV_MSG_DOWN_CO)
|
||||
| S(LB_PEER_EV_MSG_DOWN_CL)
|
||||
| S(LB_PEER_EV_AVAILABLE)
|
||||
| S(LB_PEER_EV_UNAVAILABLE)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(LB_PEER_ST_WAIT_RX_RESET)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2020-2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
@@ -85,6 +85,96 @@ struct sccp_lb_inst *sccp_lb_init(void *talloc_ctx, struct osmo_sccp_instance *s
|
||||
return sli;
|
||||
}
|
||||
|
||||
static void handle_pcstate_ind(struct sccp_lb_inst *sli, const struct osmo_scu_pcstate_param *pcst)
|
||||
{
|
||||
struct osmo_ss7_instance *cs7 = osmo_sccp_get_ss7(sli->sccp);
|
||||
struct lb_peer *lbp;
|
||||
bool connected;
|
||||
bool disconnected;
|
||||
|
||||
LOG_SCCP_LB(sli, LOGL_DEBUG, "N-PCSTATE ind: affected_pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
|
||||
pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
|
||||
osmo_sccp_sp_status_name(pcst->sp_status),
|
||||
osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
|
||||
|
||||
/* If we don't care about that point-code, ignore PCSTATE. */
|
||||
lbp = lb_peer_find_by_pc(sli, pcst->affected_pc);
|
||||
if (!lbp) {
|
||||
LOG_SCCP_LB(sli, LOGL_DEBUG, "No lb_peer found under pc=%u=%s\n",
|
||||
pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc));
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if this marks the point code to have become available, or to have been lost.
|
||||
*
|
||||
* I want to detect two events:
|
||||
* - connection event (both indicators say PC is reachable).
|
||||
* - disconnection event (at least one indicator says the PC is not reachable).
|
||||
*
|
||||
* There are two separate incoming indicators with various possible values -- the incoming events can be:
|
||||
*
|
||||
* - neither connection nor disconnection indicated -- just indicating congestion
|
||||
* connected == false, disconnected == false --> do nothing.
|
||||
* - both incoming values indicate that we are connected
|
||||
* --> trigger connected
|
||||
* - both indicate we are disconnected
|
||||
* --> trigger disconnected
|
||||
* - one value indicates 'connected', the other indicates 'disconnected'
|
||||
* --> trigger disconnected
|
||||
*
|
||||
* Congestion could imply that we're connected, but it does not indicate that a PC's reachability changed, so no need to
|
||||
* trigger on that.
|
||||
*/
|
||||
connected = false;
|
||||
disconnected = false;
|
||||
|
||||
switch (pcst->sp_status) {
|
||||
case OSMO_SCCP_SP_S_ACCESSIBLE:
|
||||
connected = true;
|
||||
break;
|
||||
case OSMO_SCCP_SP_S_INACCESSIBLE:
|
||||
disconnected = true;
|
||||
break;
|
||||
default:
|
||||
case OSMO_SCCP_SP_S_CONGESTED:
|
||||
/* Neither connecting nor disconnecting */
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pcst->remote_sccp_status) {
|
||||
case OSMO_SCCP_REM_SCCP_S_AVAILABLE:
|
||||
if (!disconnected)
|
||||
connected = true;
|
||||
break;
|
||||
case OSMO_SCCP_REM_SCCP_S_UNAVAILABLE_UNKNOWN:
|
||||
case OSMO_SCCP_REM_SCCP_S_UNEQUIPPED:
|
||||
case OSMO_SCCP_REM_SCCP_S_INACCESSIBLE:
|
||||
disconnected = true;
|
||||
connected = false;
|
||||
break;
|
||||
default:
|
||||
case OSMO_SCCP_REM_SCCP_S_CONGESTED:
|
||||
/* Neither connecting nor disconnecting */
|
||||
break;
|
||||
}
|
||||
|
||||
if (disconnected) {
|
||||
LOG_SCCP_LB(sli, LOGL_NOTICE,
|
||||
"now unreachable: N-PCSTATE ind: pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
|
||||
pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
|
||||
osmo_sccp_sp_status_name(pcst->sp_status),
|
||||
osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
|
||||
osmo_fsm_inst_dispatch(lbp->fi, LB_PEER_EV_UNAVAILABLE, NULL);
|
||||
} else if (connected) {
|
||||
LOG_SCCP_LB(sli, LOGL_NOTICE,
|
||||
"now available: N-PCSTATE ind: pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
|
||||
pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
|
||||
osmo_sccp_sp_status_name(pcst->sp_status),
|
||||
osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
|
||||
osmo_fsm_inst_dispatch(lbp->fi, LB_PEER_EV_AVAILABLE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int sccp_lb_sap_up(struct osmo_prim_hdr *oph, void *_scu)
|
||||
{
|
||||
struct osmo_sccp_user *scu = _scu;
|
||||
@@ -163,6 +253,19 @@ static int sccp_lb_sap_up(struct osmo_prim_hdr *oph, void *_scu)
|
||||
rc = lb_peer_up_l2(sli, peer_addr, false, 0, oph->msg);
|
||||
break;
|
||||
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_PCSTATE, PRIM_OP_INDICATION):
|
||||
handle_pcstate_ind(sli, &prim->u.pcstate);
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_STATE, PRIM_OP_INDICATION):
|
||||
LOG_SCCP_LB(sli, LOGL_INFO,
|
||||
"SCCP-User-SAP: Ignoring %s.%s\n",
|
||||
osmo_scu_prim_type_name(oph->primitive),
|
||||
get_value_string(osmo_prim_op_names, oph->operation));
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_SCCP_LB_CL(sli, NULL, LOGL_ERROR, "%s(%s) unsupported\n", __func__, osmo_scu_prim_name(oph));
|
||||
rc = -1;
|
||||
|
||||
Reference in New Issue
Block a user