Work on management

Also merged provisioning and management into one source file.
This commit is contained in:
Andreas Eversberg 2022-12-26 14:45:13 +01:00
parent fbb97bdd73
commit 58937c291b
4 changed files with 744 additions and 182 deletions

View File

@ -22,13 +22,22 @@
*
*/
#warning The blocking_enable state and timer is a hack to delay port blocking messages during startup. (AN may not like to get blocking messages too early.) This must be replaced by a more elegant algorithm.
// FIXME: explain each process, especially the port blocking/unblocking states and process
#include <stdint.h>
#include <osmocom/gsm/tlv.h>
#include <errno.h>
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "v5x_le_ctrl_fsm.h"
#include "v5x_le_port_fsm.h"
#include "v5x_le_pstn_fsm.h"
#include "v52_le_lcp_fsm.h"
#include "v52_le_bcc_fsm.h"
#include "v52_le_pp_fsm.h"
#include "v5x_le_management.h"
#include "logging.h"
void v5x_le_mgmt_init(void)
@ -36,47 +45,71 @@ void v5x_le_mgmt_init(void)
LOGP(DV5MGMT, LOGL_NOTICE, "Using V5x management\n");
}
/* received management primitives from LE (NAT protocol via PH-socket) */
void v5x_mph_rcv_le(struct v5x_user_port *v5up, uint8_t prim, uint8_t *data, int length)
{
ph_socket_t *s = &v5up->ph_socket;
/*
* provisioning and port handling
*/
switch (prim) {
case PH_PRIM_CTRL_REQ:
if (length && *data == PH_CTRL_UNBLOCK) {
LOGP(DV5MGMT, LOGL_INFO, "Received unblocking from LE of port %d.\n", v5up->nr);
v5up->le_unblocked = true;
v5x_mph_snd(v5up, MPH_UBR);
if (v5up->pstn.proto && v5up->an_unblocked)
struct osmo_timer_list provisioning_timer;
struct osmo_timer_list blocking_enable_timer;
static void provisioning_cb(void *data)
{
struct v5x_interface *v5if = data;
/* ask for variant and interface ID */
LOGP(DV5MGMT, LOGL_INFO, "Requesting variant and interface ID.\n");
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID, NULL, NULL, NULL);
}
static void blocking_enable_cb(void *data)
{
struct v5x_interface *v5if = data;
struct v5x_link *v5l;
struct v5x_user_port *v5up;
LOGP(DV5MGMT, LOGL_DEBUG, "Enable sending of port blocking/unblocking and sending all block states to AN.\n");
/* unblock all links */
if (v5if->dialect == V5X_DIALECT_V52) {
llist_for_each_entry(v5l, &v5if->links, list) {
LOGP(DV5MGMT, LOGL_INFO, "Send unblocking request for link %d.\n", v5l->id);
v52_le_lcp_mdu_snd(v5l, MDU_LUBR);
}
}
/* unblock all ports */
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (v5up->blocking_enabled)
continue;
v5up->blocking_enabled = true;
if (v5up->le_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, "Send unblock request to %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5x_port_mph_snd(v5up, MPH_UBR);
if (v5up->pstn.proto && v5up->an_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, "Send port unblocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_unblocked);
if (!v5up->an_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, "Reply with blocking, because AN is blocked.\n");
uint8_t ctrl = PH_CTRL_BLOCK;
ph_socket_tx_msg(&v5up->ph_socket, v5up->type == V5X_USER_TYPE_ISDN ? 3 : 0, PH_PRIM_CTRL_IND, &ctrl, 1);
}
} else {
LOGP(DV5MGMT, LOGL_INFO, "Send block indication to %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5x_port_mph_snd(v5up, MPH_BI);
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send port blocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
}
}
if (length && *data == PH_CTRL_BLOCK) {
LOGP(DV5MGMT, LOGL_INFO, "Received blocking from LE of port %d.\n", v5up->nr);
v5up->le_unblocked = false;
v5x_mph_snd(v5up, MPH_BI);
if (v5up->pstn.proto)
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
}
}
static void restart_all_pstn_ports(struct v5x_interface *v5if)
{
struct v5x_user_port *v5up;
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send restart request to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_restart_req);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_restart_compl);
}
break;
case PH_PRIM_ACT_REQ:
LOGP(DV5MGMT, LOGL_INFO, "Received activation from LE of port %d.\n", v5up->nr);
if (!v5up->an_unblocked) {
ph_socket_tx_msg(s, 3, PH_PRIM_DACT_IND, NULL, 0);
break;
}
v5x_mph_snd(v5up, MPH_AR);
break;
case PH_PRIM_DACT_REQ:
LOGP(DV5MGMT, LOGL_INFO, "Received deactivation from LE of port %d.\n", v5up->nr);
v5x_mph_snd(v5up, MPH_DR);
break;
default:
LOGP(DV5MGMT, LOGL_INFO, "Received unknown prim %d from LE for port %d.\n", prim, v5up->nr);
}
}
@ -85,100 +118,710 @@ static void _block_unblock_socket(struct v5x_user_port *v5up, bool block)
uint8_t ctrl;
if (block && v5up->an_unblocked) {
v5up->an_unblocked = 0;
v5up->an_unblocked = false;
ctrl = PH_CTRL_BLOCK;
ph_socket_tx_msg(&v5up->ph_socket, v5up->type == V5X_USER_TYPE_ISDN ? 3 : 0, PH_PRIM_CTRL_IND, &ctrl, 1);
ph_socket_tx_msg(&v5up->ph_socket, v5up->type == V5X_USER_TYPE_ISDN ? 3 : 0, PH_PRIM_CTRL_IND, &ctrl,
1);
return;
}
if (!block && !v5up->an_unblocked) {
v5up->an_unblocked = 1;
v5up->an_unblocked = true;
ctrl = PH_CTRL_UNBLOCK;
ph_socket_tx_msg(&v5up->ph_socket, v5up->type == V5X_USER_TYPE_ISDN ? 3 : 0, PH_PRIM_CTRL_IND, &ctrl, 1);
ph_socket_tx_msg(&v5up->ph_socket, v5up->type == V5X_USER_TYPE_ISDN ? 3 : 0, PH_PRIM_CTRL_IND, &ctrl,
1);
return;
}
}
/* messages from common control layer */
void v5x_le_common_ctrl_rcv(struct v5x_interface *v5if, uint8_t cfi, uint8_t variant, uint8_t rej_cause,
uint32_t interface_id)
{
struct v5x_user_port *v5up;
LOGP(DV5MGMT, LOGL_DEBUG, "Received common control message from control protocol. "
"(cfi = %d, variant = %d, rej_cause = %d, interface_id = %d)\n", cfi, variant, rej_cause, interface_id);
switch (cfi) {
case V5X_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID:
LOGP(DV5MGMT, LOGL_INFO, "AN requests variant and interface ID, replying.\n");
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_VARIANT_AND_INTERFACE_ID, NULL, &v5if->variant_local,
&v5if->id_local);
break;
case V5X_CTRL_ID_RESTART_REQUEST:
LOGP(DV5MGMT, LOGL_INFO, "AN requests restart, sending restart to every PSTN port and replying.\n");
/* all PSTN ports are restarted */
restart_all_pstn_ports(v5if);
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_RESTART_COMPLETE, NULL, NULL, NULL);
break;
case V5X_CTRL_ID_VARIANT_AND_INTERFACE_ID:
LOGP(DV5MGMT, LOGL_INFO, "AN replies variant and interface ID. (variant = %d, interface_id = %d)\n",
variant, interface_id);
v5if->variant_remote = variant;
v5if->variant_remote_valid = true;
if (v5if->variant_remote != v5if->variant_local) {
LOGP(DV5MGMT, LOGL_ERROR, "Variant does not match: AN(%d) != LE(%d)\n", v5if->variant_remote,
v5if->variant_local);
}
v5if->id_remote = interface_id;
v5if->id_remote_valid = true;
if (v5if->id_remote != v5if->id_local) {
LOGP(DV5MGMT, LOGL_ERROR, "Interface ID does not match: AN(%d) != LE(%d)\n", v5if->id_remote,
v5if->id_local);
}
if (v5if->variant_remote != v5if->variant_local || v5if->id_remote != v5if->id_local) {
LOGP(DV5MGMT, LOGL_ERROR, "****************************************************************\n");
LOGP(DV5MGMT, LOGL_ERROR, "You must set correct Variant and Interface ID on both AN and LE!\n");
LOGP(DV5MGMT, LOGL_ERROR, "****************************************************************\n");
break;
}
memset(&blocking_enable_timer, 0, sizeof(blocking_enable_timer));
blocking_enable_timer.data = v5if;
blocking_enable_timer.cb = blocking_enable_cb;
osmo_timer_schedule(&blocking_enable_timer, 4, 0); // FIXME: make configurable
break;
case V5X_CTRL_ID_RESTART_COMPLETE:
LOGP(DV5MGMT, LOGL_INFO, "AN indicated complete restart.\n");
break;
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_ISDN_REQUEST:
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_REQUEST:
case V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_REQUEST:
LOGP(DV5MGMT, LOGL_INFO, "Multiple port unblocking received.\n");
LOGP(DV5MGMT, LOGL_INFO, "Accepting multiple port unblocking, sending reply.\n");
v5x_le_ctrl_common_snd(v5if, cfi + 1, NULL, NULL, NULL);
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (cfi == V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_REQUEST && !v5up->pstn.proto)
continue;
if (cfi == V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_REQUEST && v5up->pstn.proto)
continue;
v5up->blocking_enabled = true;
if (v5up->le_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, " -> Set %s port %d into unblocked state.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
_block_unblock_socket(v5up, false);
if (v5up->pstn.proto) {
v5x_le_port_pstn_unblock(v5up->port_fi);
LOGP(DV5MGMT, LOGL_INFO, " -> Send port unblocked control to PSTN port %d.\n",
v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_unblocked);
} else
v5x_le_port_isdn_unblock(v5up->port_fi);
}
}
LOGP(DV5MGMT, LOGL_INFO, "Completed multiple port unblocking, sending info.\n");
v5x_le_ctrl_common_snd(v5if, cfi + 3, NULL, NULL, NULL);
break;
case V5X_CTRL_ID_BLK_ALL_PSTN_REQUEST:
case V5X_CTRL_ID_BLK_ALL_ISDN_REQUEST:
LOGP(DV5MGMT, LOGL_INFO, "Multiple port blocking request from remote.\n");
LOGP(DV5MGMT, LOGL_INFO, "Accepting multiple port blocking, sending reply.\n");
v5x_le_ctrl_common_snd(v5if, cfi + 1, NULL, NULL, NULL);
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (cfi == V5X_CTRL_ID_BLK_ALL_PSTN_REQUEST && !v5up->pstn.proto)
continue;
if (cfi == V5X_CTRL_ID_BLK_ALL_ISDN_REQUEST && v5up->pstn.proto)
continue;
v5up->blocking_enabled = true;
LOGP(DV5MGMT, LOGL_INFO, " -> Set %s port %d into blocked state.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
_block_unblock_socket(v5up, true);
if (v5up->pstn.proto) {
v5x_le_port_pstn_block(v5up->port_fi);
LOGP(DV5MGMT, LOGL_INFO, " -> Send port blocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
} else
v5x_le_port_isdn_block(v5up->port_fi);
}
LOGP(DV5MGMT, LOGL_INFO, "Completed multiple port blocking, sending info.\n");
v5x_le_ctrl_common_snd(v5if, cfi + 3, NULL, NULL, NULL);
break;
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_ISDN_COMPLETED:
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_COMPLETED:
case V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_COMPLETED:
LOGP(DV5MGMT, LOGL_INFO, "Completed multiple port blocking by remote. Updating blocked ports.\n");
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (cfi == V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_COMPLETED && !v5up->pstn.proto)
continue;
if (cfi == V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_COMPLETED && v5up->pstn.proto)
continue;
if (!v5up->le_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, " -> Send block indication to %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5x_port_mph_snd(v5up, MPH_BI);
}
}
case V5X_CTRL_ID_BLK_ALL_PSTN_COMPLETED:
case V5X_CTRL_ID_BLK_ALL_ISDN_COMPLETED:
break;
default:
LOGP(DV5MGMT, LOGL_NOTICE, "Ignoring common control message with cfi = %d\n", cfi);
}
}
/* perform provisioning */
void v5x_le_provisioning_start(struct v5x_interface *v5if)
{
memset(&provisioning_timer, 0, sizeof(provisioning_timer));
provisioning_timer.data = v5if;
provisioning_timer.cb = provisioning_cb;
osmo_timer_schedule(&provisioning_timer, 1, 0); // FIXME: make configurable
}
void v5x_le_pstn_restart(struct v5x_interface *v5if)
{
/* request a restart */
LOGP(DV5MGMT, LOGL_NOTICE, "Perform PSTN restart.\n");
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_RESTART_REQUEST, NULL, NULL, NULL);
/* all PSTN ports are restarted */
restart_all_pstn_ports(v5if);
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_RESTART_COMPLETE, NULL, NULL, NULL);
}
/* received management primitives from LE (NAT protocol via PH-socket) */
void v5x_le_nat_ph_rcv(struct v5x_user_port *v5up, uint8_t prim, uint8_t *data, int length)
{
ph_socket_t *s = &v5up->ph_socket;
switch (prim) {
case PH_PRIM_CTRL_REQ:
if (length && *data == PH_CTRL_UNBLOCK) {
LOGP(DV5MGMT, LOGL_INFO, "Received unblocking from LE of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5up->le_unblocked = true;
if (v5up->blocking_enabled) {
v5x_port_mph_snd(v5up, MPH_UBR);
if (v5up->pstn.proto && v5up->an_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, "Send port unblocked control to PSTN port %d.\n",
v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_unblocked);
}
}
if (!v5up->an_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, "Reply with blocking, because AN is blocked.\n");
uint8_t ctrl = PH_CTRL_BLOCK;
ph_socket_tx_msg(&v5up->ph_socket, v5up->type == V5X_USER_TYPE_ISDN ? 3 : 0,
PH_PRIM_CTRL_IND, &ctrl, 1);
}
}
if (length && *data == PH_CTRL_BLOCK) {
LOGP(DV5MGMT, LOGL_INFO, "Received blocking from LE of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5up->le_unblocked = false;
if (v5up->blocking_enabled) {
v5x_port_mph_snd(v5up, MPH_BI);
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send port blocked control to PSTN port %d.\n",
v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
}
}
}
break;
case PH_PRIM_ACT_REQ:
LOGP(DV5MGMT, LOGL_INFO, "Received activation from LE of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
if (!v5up->an_unblocked) {
ph_socket_tx_msg(s, 3, PH_PRIM_DACT_IND, NULL, 0);
break;
}
v5x_port_mph_snd(v5up, MPH_AR);
break;
case PH_PRIM_DACT_REQ:
LOGP(DV5MGMT, LOGL_INFO, "Received deactivation from LE of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5x_port_mph_snd(v5up, MPH_DR);
break;
default:
LOGP(DV5MGMT, LOGL_INFO, "Received unknown prim %d from LE for %s port %d.\n", prim,
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
}
}
/* received management primitives from AN (via port control protocol) */
void v5x_mph_rcv_an(struct v5x_user_port *v5up, enum v5x_mph_prim prim, uint8_t perf_grading)
void v5x_le_port_mph_rcv(struct v5x_user_port *v5up, enum v5x_mph_prim prim, uint8_t perf_grading)
{
switch (prim) {
case MPH_UBR:
LOGP(DV5MGMT, LOGL_INFO, "Received unblocking request from AN of port %d.\n", v5up->nr);
LOGP(DV5MGMT, LOGL_INFO, "Received unblocking request from AN of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5up->blocking_enabled = true;
if (v5up->le_unblocked) {
LOGP(DV5MGMT, LOGL_INFO, "Reply with unblocking request.\n");
v5x_mph_snd(v5up, MPH_UBR);
LOGP(DV5MGMT, LOGL_INFO, "Reply with unblocking request, because port available at LE.\n");
v5x_port_mph_snd(v5up, MPH_UBR);
_block_unblock_socket(v5up, false);
if (v5up->pstn.proto)
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send port unblocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_unblocked);
} else
LOGP(DV5MGMT, LOGL_INFO, "Ignore unblocking request from AN, because LE is blocked.\n");
}
} else {
LOGP(DV5MGMT, LOGL_INFO, "Reply with blocking indication, because port unavailable at LE.\n");
v5up->an_unblocked = false;
v5x_port_mph_snd(v5up, MPH_BI);
}
break;
case MPH_UBI:
LOGP(DV5MGMT, LOGL_INFO, "Received unblocking indication from AN of port %d.\n", v5up->nr);
LOGP(DV5MGMT, LOGL_INFO, "Received unblocking indication from AN of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5up->blocking_enabled = true;
_block_unblock_socket(v5up, false);
if (v5up->pstn.proto)
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send port unblocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_unblocked);
}
break;
case MPH_BR:
LOGP(DV5MGMT, LOGL_INFO, "Received blocking request from AN of port %d.\n", v5up->nr);
v5x_mph_snd(v5up, MPH_BI);
LOGP(DV5MGMT, LOGL_INFO, "Received blocking request from AN of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5up->blocking_enabled = true;
LOGP(DV5MGMT, LOGL_INFO, "Reply with blocking indication.\n");
v5x_port_mph_snd(v5up, MPH_BI);
_block_unblock_socket(v5up, true);
if (v5up->pstn.proto)
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send port blocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
}
break;
case MPH_BI:
LOGP(DV5MGMT, LOGL_INFO, "Received blocking indication from AN of port %d.\n", v5up->nr);
LOGP(DV5MGMT, LOGL_INFO, "Received blocking indication from AN of %s port %d.\n",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
v5up->blocking_enabled = true;
_block_unblock_socket(v5up, true);
if (v5up->pstn.proto)
if (v5up->pstn.proto) {
LOGP(DV5MGMT, LOGL_INFO, "Send port blocked control to PSTN port %d.\n", v5up->nr);
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
}
break;
case MPH_AI:
LOGP(DV5MGMT, LOGL_INFO, "Received activation indication from AN of port %d.\n", v5up->nr);
LOGP(DV5MGMT, LOGL_INFO, "Received activation indication from AN of ISDN port %d.\n", v5up->nr);
ph_socket_tx_msg(&v5up->ph_socket, 3, PH_PRIM_ACT_IND, NULL, 0);
break;
case MPH_AWI:
break;
case MPH_DSAI:
break;
case MPH_DI:
LOGP(DV5MGMT, LOGL_INFO, "Received deactivation indication from AN of port %d.\n", v5up->nr);
LOGP(DV5MGMT, LOGL_INFO, "Received deactivation indication from AN of ISDN port %d.\n", v5up->nr);
ph_socket_tx_msg(&v5up->ph_socket, 3, PH_PRIM_DACT_IND, NULL, 0);
break;
case MPH_GI:
LOGP(DV5MGMT, LOGL_INFO, "Received performance grading from AN for ISDN port %d: %s\n", v5up->nr,
(perf_grading) ? "Degraded" : "Normal grade");
break;
default:
LOGP(DV5MGMT, LOGL_INFO, "Received unknown prim %d from AN for port %d.\n", prim, v5up->nr);
LOGP(DV5MGMT, LOGL_INFO, "Received unknown prim %d from AN for %s port %d.\n", prim, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
}
}
/* receive FE-message from NAT (PH-socket) and forward it to the PSTN protocol */
void v5x_nat_rcv_fe(struct v5x_user_port *v5up, struct msgb *msg)
{
enum v5x_fe_prim prim;
prim = *msg->data;
msgb_pull(msg, 1);
LOGP(DV5MGMT, LOGL_INFO, "FE message: NAT -> PSTN_LE of port %d.\n", v5up->nr);
v5x_le_pstn_fe_snd(v5up, prim, msg);
}
/* receive FE-message from PSTN protocol and forward it to NAT (PH-socket) */
void v5x_pstn_rcv_fe(struct v5x_user_port *v5up, enum v5x_fe_prim prim, struct msgb *msg)
{
*msgb_push(msg, 1) = prim;
LOGP(DV5MGMT, LOGL_INFO, "FE message: PSTN_LE -> NAT of port %d.\n", v5up->nr);
ph_socket_tx_msg(&v5up->ph_socket, 0, PH_PRIM_DATA_IND, msg->data, msg->len);
msgb_free(msg);
}
/* receive MDU primitives from PSTN protocol */
void v5x_pstn_rcv_mdu(struct v5x_user_port *v5up, enum v5x_mgmt_prim prim)
void v5x_le_pstn_mdu_rcv(struct v5x_user_port *v5up, enum v5x_mgmt_prim prim)
{
switch (prim) {
case MDU_error_ind:
LOGP(DV5MGMT, LOGL_NOTICE, "Received MDU-error_indication from PSTN protocol of port %d.\n", v5up->nr);
break;
case MDU_CTRL_port_restart_ack:
//FIXME: handle restart procedure
LOGP(DV5MGMT, LOGL_INFO, "Received restart acknowledge from PSTN protocol of port %d.\n", v5up->nr);
break;
default:
LOGP(DV5MGMT, LOGL_INFO, "Received unknown prim %d from PSTN protocol for port %d.\n", prim, v5up->nr);
}
}
/* flush all channels from non-operational link */
static void flush_link(struct v5x_link *v5l)
{
struct v5x_user_port *v5up;
int t;
for (t = 1; t <= 31; t++) {
if (!v5l->ts[t].b_channel)
continue;
if ((v5up = v5l->ts[t].v5up)) {
if (v5up->ts[0] == &v5l->ts[t]) {
v5up->ts[0] = NULL;
v5up->ts_activated[0] = 0;
}
if (v5up->ts[1] == &v5l->ts[t]) {
v5up->ts[1] = NULL;
v5up->ts_activated[1] = 0;
}
v5l->ts[t].v5up = NULL;
}
}
}
/*
* LCP handling
*/
/* receive MDU primitives from LCP protocol */
void v52_le_lcp_mdu_rcv(struct v5x_link *v5l, enum v5x_mgmt_prim prim)
{
switch (prim) {
case MDU_AI:
LOGP(DV5MGMT, LOGL_INFO, "Link %d is active.\n", v5l->id);
break;
case MDU_DI:
LOGP(DV5MGMT, LOGL_INFO, "Link %d is inactive.\n", v5l->id);
break;
case MDU_LAI:
LOGP(DV5MGMT, LOGL_INFO, "Link %d becomes active in blocked state, try unblocking.\n", v5l->id);
v52_le_lcp_mdu_snd(v5l, MDU_LUBR);
break;
case MDU_IDReq:
LOGP(DV5MGMT, LOGL_INFO, "Remote side perform link ID check of link %d, replying.\n", v5l->id);
v52_le_lcp_mdu_snd(v5l, MDU_IDAck);
break;
case MDU_IDAck:
break;
case MDU_IDRel:
LOGP(DV5MGMT, LOGL_INFO, "Remote side ID check done.\n");
break;
case MDU_IDRej:
break;
case MDU_EIg:
break;
case MDU_LUBR:
LOGP(DV5MGMT, LOGL_INFO, "Remote side unblocks link ID %d, replying.\n", v5l->id);
v52_le_lcp_mdu_snd(v5l, MDU_LUBR);
break;
case MDU_LUBI:
LOGP(DV5MGMT, LOGL_INFO, "Remote side link ID %d is now unblocked.\n", v5l->id);
break;
case MDU_LBI:
LOGP(DV5MGMT, LOGL_INFO, "LCP indicated blocked link ID %d.\n", v5l->id);
flush_link(v5l);
break;
case MDU_LBR:
case MDU_LBRN:
LOGP(DV5MGMT, LOGL_INFO, "Remote request blocking of link link ID %d, replying.\n", v5l->id);
flush_link(v5l);
v52_le_lcp_mdu_snd(v5l, MDU_LBI);
break;
default:
LOGP(DV5MGMT, LOGL_INFO, "Received unknown prim %d from LCP protocol for link ID %d.\n", prim, v5l->id);
}
}
/*
* forwarding messages between PSTN and gateway application
*/
/* receive FE-message from NAT (PH-socket) and forward it to the PSTN protocol */
void v5x_le_nat_fe_rcv(struct v5x_user_port *v5up, struct msgb *msg)
{
enum v5x_fe_prim prim;
prim = *msg->data;
msgb_pull(msg, 1);
if (!v5x_le_port_isdn_is_operational(v5up->port_fi)) {
LOGP(DV5MGMT, LOGL_NOTICE, "Dropping (NAT->LE) message of non-operational PSTN port for L3Addr %d.\n",
v5up->nr);
msgb_free(msg);
return;
}
LOGP(DV5MGMT, LOGL_INFO, "FE message: NAT -> PSTN_LE of PSTN port %d.\n", v5up->nr);
v5x_le_pstn_fe_snd(v5up, prim, msg);
}
/* receive FE-message from PSTN protocol and forward it to NAT (PH-socket) */
void v5x_le_pstn_fe_rcv(struct v5x_user_port *v5up, enum v5x_fe_prim prim, struct msgb *msg)
{
*msgb_push(msg, 1) = prim;
if (!v5x_le_port_isdn_is_operational(v5up->port_fi)) {
LOGP(DV5MGMT, LOGL_NOTICE, "Dropping (AN->NAT) message of non-operational PSTN port for L3Addr %d.\n",
v5up->nr);
msgb_free(msg);
return;
}
LOGP(DV5MGMT, LOGL_INFO, "FE message: PSTN_LE -> NAT of PSTN port %d.\n", v5up->nr);
ph_socket_tx_msg(&v5up->ph_socket, 0, PH_PRIM_DATA_IND, msg->data, msg->len);
msgb_free(msg);
}
/*
* BCC channel handling
*/
/* assign channel */
void v5x_le_channel_assign(struct v5x_user_port *v5up, int channel)
{
struct v5x_interface *v5if = v5up->interface;
struct v5x_link *v5l = NULL;
int found, t;
OSMO_ASSERT(channel >= 1 && channel <= 2);
/* the channels are pre-assigned with V5.1, so only activation state is set */
if (v5if->dialect == V5X_DIALECT_V51) {
if (!v5up->ts[channel - 1]) {
LOGP(DV5MGMT, LOGL_ERROR, "Cannot activate channel, because no TS is assigned for %s port "
"%d.\n", (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5l->id);
return;
}
if (v5up->ts_activated[channel - 1])
return;
LOGP(DV5MGMT, LOGL_DEBUG, "Activating channel %d for %s port %d at TS %d of link %d.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr,
v5up->ts[channel - 1]->nr, v5up->ts[channel - 1]->link->id);
v5up->ts_activated[channel - 1] = 1;
return;
}
/* channel already assigned, just activate it, if not already */
if (v5up->ts[channel - 1]) {
v5up->ts_activated[channel - 1] = 1;
return;
}
/* hunt for a channel */
found = 0;
llist_for_each_entry(v5l, &v5if->links, list) {
if (!v52_le_lcp_is_operational(v5l->fi)) {
LOGP(DV5MGMT, LOGL_NOTICE, "While searching for a bearer channel: Skipping link with ID %d, "
"because it is not operational.\n", v5l->id);
continue;
}
for (t = 1; t <= 31; t++) {
if (!v5l->ts[t].b_channel)
continue;
if (!v5l->ts[t].v5up) {
found = 1;
break;
}
}
if (found)
break;
}
if (!found) {
LOGP(DV5MGMT, LOGL_NOTICE, "No free channel found.\n");
return;
}
/* assign channel */
v5l->ts[t].v5up = v5up;
v5up->ts[channel - 1] = &v5l->ts[t];
/* request BCC to allocate channel on AN */
v52_le_bcc_mdu_snd(v5if, v5up->nr, (v5up->type == V5X_USER_TYPE_ISDN), v5up->ts[channel - 1]->link->id,
v5up->ts[channel - 1]->nr, 1, channel, NULL, (v5if->use_capability) ? &v5if->capability : NULL,
MDU_BCC_allocation_req);
}
/* unassign channel */
void v5x_le_channel_unassign(struct v5x_user_port *v5up, int channel)
{
struct v5x_interface *v5if = v5up->interface;
/* the channels are pre-assigned with V5.1, so only activation state is set */
if (v5if->dialect == V5X_DIALECT_V51) {
if (!v5up->ts_activated[channel - 1])
return;
if (!v5up->ts[channel - 1]) {
LOGP(DV5MGMT, LOGL_ERROR, "Cannot deactivate channel, because no TS is assigned for %s port "
"%d.\n", (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
return;
}
LOGP(DV5MGMT, LOGL_DEBUG, "Deactivating channel %d for %s port %d at TS %d of link %d.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr,
v5up->ts[channel - 1]->nr, v5up->ts[channel - 1]->link->id);
v5up->ts_activated[channel - 1] = 0;
return;
}
/* deactivate */
v5up->ts_activated[channel - 1] = 0;
/* if not assigned */
if (!v5up->ts[channel - 1])
return;
/* unassign or abort ongoing BCC allocation */
v52_le_bcc_mdu_snd(v5if, v5up->nr, v5up->type == V5X_USER_TYPE_ISDN, v5up->ts[channel - 1]->link->id,
v5up->ts[channel - 1]->nr, 1, channel, NULL, 0, MDU_BCC_deallocation_req);
}
int v52_le_bcc_mdu_rcv(struct v5x_interface *v5if, uint8_t link_id, uint8_t ts,
uint8_t __attribute__((unused)) *isdn_multislot, enum v5x_mgmt_prim prim, const uint8_t *cause,
uint8_t cause_len)
{
struct v5x_link *v5l;
struct v5x_user_port *v5up;
int channel = 0;
if (ts > 31) {
LOGP(DV5MGMT, LOGL_ERROR, "TS %d out of range.\n", ts);
return -EINVAL;
}
v5l = v5x_link_find_id(v5if, link_id);
if (!v5l) {
LOGP(DV5MGMT, LOGL_ERROR, "Invalid link ID %d.\n", link_id);
return -EINVAL;
}
v5up = v5l->ts[ts].v5up;
if (!v5up) {
LOGP(DV5MGMT, LOGL_NOTICE, "TS %d of link ID %d is not assigned.\n", ts, link_id);
return 0;
}
if (v5up->ts[0] == &v5l->ts[ts])
channel = 1;
if (v5up->ts[1] == &v5l->ts[ts])
channel = 2;
OSMO_ASSERT(channel);
switch (prim) {
case MDU_BCC_allocation_conf:
LOGP(DV5MGMT, LOGL_INFO, "Assigned channel %d for %s port %d at TS %d of link %d.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr, ts, link_id);
v5up->ts_activated[channel - 1] = 1;
break;
case MDU_BCC_deallocation_conf:
LOGP(DV5MGMT, LOGL_INFO, "Unassigned channel %d for %s port %d at TS %d of link %d.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr, ts, link_id);
v5l->ts[ts].v5up = NULL;
v5up->ts[0] = NULL;
break;
case MDU_BCC_allocation_reject_ind:
case MDU_BCC_deallocation_reject_ind:
if (cause_len < 1)
break;
LOGP(DV5MGMT, LOGL_ERROR, "Failed to (un)assign channel %d for %s port %d at TS %d of link %d: %s.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr, ts, link_id,
get_value_string(v52_bcc_reject_cause_type_str,
cause[0] & 0x7f));
if (cause_len > 1)
LOGP(DV5MGMT, LOGL_ERROR, " -> Diagnostic: %s\n", osmo_hexdump(cause + 1, cause_len - 1));
break;
case MDU_BCC_protocol_error_ind:
if (cause_len < 1)
break;
LOGP(DV5MGMT, LOGL_ERROR, "Failed to (un)assign channel %d for %s port %d at TS %d of link %d: %s.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr, ts, link_id,
get_value_string(v5x_cause_type_str, cause[0] & 0x7f));
if (cause_len > 1)
LOGP(DV5MGMT, LOGL_ERROR, " -> Diagnostic: %s\n", osmo_hexdump(cause + 1, cause_len - 1));
if (cause_len >= 3 && cause[1] == 0x20 && cause[2] == 0x47) {
LOGP(DV5MGMT, LOGL_ERROR, "AN rejects information-transfer-capability information element, "
"please disable via VTY!\n");
}
break;
default:
LOGP(DV5MGMT, LOGL_ERROR, "Failed to (un)assign channel %d for %s port %d at TS %d of link %d.\n",
channel, (v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr, ts, link_id);
}
return 0;
}
/*
* Protection protocol handling
*/
static void switchover_request_link(struct v5x_link *v5l, uint8_t link_id, uint8_t ts)
{
LOGP(DV5MGMT, LOGL_NOTICE, "Switch over request from AN to link %d and TS %d.\n", link_id, ts);
if (!v5l) {
LOGP(DV5MGMT, LOGL_ERROR, " -> Rejecting, because requested link is not primary, nor secondary.\n");
v52_le_pp_mdu_snd(v5l->interface, MDU_Protection_switch_over_rej, link_id, ts,
V52_PP_REJECT_CAUSE_T_TARGET_CC_NOT_PROV);
return;
}
if (ts != v5l->c_channel[0].ts->nr) {
LOGP(DV5MGMT, LOGL_ERROR, " -> Rejecting, because requested TS is not a C-channel.\n");
v52_le_pp_mdu_snd(v5l->interface, MDU_Protection_switch_over_rej, link_id, ts,
V52_PP_REJECT_CAUSE_T_TARGET_CC_NOT_PROV);
return;
}
if (!v52_le_lcp_is_operational(v5l->fi)) {
LOGP(DV5MGMT, LOGL_ERROR, " -> Rejecting, because requested link is not operational.\n");
v52_le_pp_mdu_snd(v5l->interface, MDU_Protection_switch_over_rej, link_id, ts,
V52_PP_REJECT_CAUSE_T_TARGET_CC_NOT_OPER);
return;
}
if (v5l == v5l->interface->cc_link) {
LOGP(DV5MGMT, LOGL_ERROR, " -> Rejecting, because requested allocation exists already.\n");
v52_le_pp_mdu_snd(v5l->interface, MDU_Protection_switch_over_rej, link_id, ts,
V52_PP_REJECT_CAUSE_T_ALLOC_EXISTS_ALREADY);
return;
}
LOGP(DV5MGMT, LOGL_NOTICE, "Sending switch over command to AN.\n");
v52_le_pp_mdu_snd(v5l->interface, MDU_Protection_switch_over_com, link_id, ts, 0);
}
static void switchover_request(struct v5x_interface *v5if)
{
LOGP(DV5MGMT, LOGL_NOTICE, "Switch over request from AN, due to link failure.\n");
if (v5if->primary_link == v5if->cc_link) {
LOGP(DV5MGMT, LOGL_NOTICE, "Sending switch over command to AN. (go to secondary link)\n");
v52_le_pp_mdu_snd(v5if, MDU_Protection_switch_over_com, v5if->secondary_link->id, 16, 0);
}
if (v5if->secondary_link == v5if->cc_link) {
LOGP(DV5MGMT, LOGL_NOTICE, "Sending switch over command to AN. (go to primary link)\n");
v52_le_pp_mdu_snd(v5if, MDU_Protection_switch_over_com, v5if->primary_link->id, 16, 0);
}
}
int v52_le_pp_mdu_rcv(struct v5x_interface *v5if, enum v5x_mgmt_prim prim, uint8_t link_id, uint8_t ts,
const uint8_t *cause, uint8_t cause_len)
{
struct v5x_link *v5l = NULL;
/* get link from what the AN is talking about */
if (link_id == v5if->primary_link->id)
v5l = v5if->primary_link;
if (link_id == v5if->secondary_link->id)
v5l = v5if->secondary_link;
switch (prim) {
case MDU_Protection_switch_over_ack:
LOGP(DV5MGMT, LOGL_NOTICE, "Switch over request from LE to link %d and TS %d was acked.\n", link_id,
ts);
LOGP(DV5MGMT, LOGL_NOTICE, "Performing switch over.\n");
if (v5l)
v5if->cc_link = v5l;
break;
case MDU_Protection_switch_over_req:
if (ts)
switchover_request_link(v5l, link_id, ts);
else
switchover_request(v5if);
break;
case MDU_Protection_switch_over_reject_ind:
if (cause_len < 1)
break;
LOGP(DV5MGMT, LOGL_ERROR, "Switch over to link %d and TS %d was rejected by AN: %s.\n", link_id, ts,
get_value_string(v52_pp_reject_cause_type_str, cause[0] & 0x7f));
break;
case MDU_Protection_switch_over_error_ind:
LOGP(DV5MGMT, LOGL_NOTICE, "Switch over request from LE to link %d and TS %d failed.\n", link_id, ts);
break;
case MDU_Protection_reset_SN_ind:
LOGP(DV5MGMT, LOGL_NOTICE, "AN resets serial numbers at Protection protocol.\n");
break;
case MDU_Protection_reset_SN_com:
LOGP(DV5MGMT, LOGL_NOTICE, "LE resets serial numbers at Protection protocol.\n");
break;
case MDU_Protection_reset_SN_ack:
LOGP(DV5MGMT, LOGL_NOTICE, "AN acknowledges reset serial numbers at Protection protocol.\n");
break;
case MDU_Protection_reset_SN_error_ind:
LOGP(DV5MGMT, LOGL_NOTICE, "Switch over request failed, due to serial numbers reset at Protection "
"protocol.\n");
break;
case MDU_Protection_protocol_error_ind:
if (cause_len < 1)
break;
LOGP(DV5MGMT, LOGL_ERROR, "Protocol error: %s.\n",
get_value_string(v5x_cause_type_str, cause[0] & 0x7f));
if (cause_len > 1)
LOGP(DV5MGMT, LOGL_ERROR, " -> Diagnostic: %s\n", osmo_hexdump(cause + 1, cause_len - 1));
break;
default:
LOGP(DV5MGMT, LOGL_ERROR, "Unknown message primitive %d.\n", prim);
}
return 0;
}

View File

@ -1,7 +1,20 @@
void v5x_le_mgmt_init(void);
void v5x_mph_rcv_le(struct v5x_user_port *v5up, uint8_t prim, uint8_t *data, int length);
void v5x_mph_rcv_an(struct v5x_user_port *v5up, enum v5x_mph_prim prim, uint8_t perf_grading);
void v5x_nat_rcv_fe(struct v5x_user_port *v5up, struct msgb *msg);
void v5x_pstn_rcv_fe(struct v5x_user_port *v5up, enum v5x_fe_prim prim, struct msgb *msg);
void v5x_pstn_rcv_mdu(struct v5x_user_port *v5up, enum v5x_mgmt_prim prim);
void v5x_le_common_ctrl_rcv(struct v5x_interface *v5if, uint8_t cfi, uint8_t variant, uint8_t rej_cause,
uint32_t interface_id);
void v5x_le_provisioning_start(struct v5x_interface *v5if);
void v5x_le_pstn_restart(struct v5x_interface *v5if);
void v5x_le_nat_ph_rcv(struct v5x_user_port *v5up, uint8_t prim, uint8_t *data, int length);
void v5x_le_port_mph_rcv(struct v5x_user_port *v5up, enum v5x_mph_prim prim, uint8_t perf_grading);
void v5x_le_nat_fe_rcv(struct v5x_user_port *v5up, struct msgb *msg);
void v5x_le_pstn_fe_rcv(struct v5x_user_port *v5up, enum v5x_fe_prim prim, struct msgb *msg);
void v5x_le_pstn_mdu_rcv(struct v5x_user_port *v5up, enum v5x_mgmt_prim prim);
void v52_le_lcp_mdu_rcv(struct v5x_link *v5l, enum v5x_mgmt_prim prim);
int v52_le_pp_mdu_rcv(struct v5x_interface *v5if, enum v5x_mgmt_prim prim, uint8_t link_id, uint8_t ts,
const uint8_t *cause, uint8_t cause_len);
void v5x_le_channel_assign(struct v5x_user_port *v5up, int channel);
void v5x_le_channel_unassign(struct v5x_user_port *v5up, int channel);
int v52_le_bcc_mdu_rcv(struct v5x_interface *v5if, uint8_t link_id, uint8_t ts,
uint8_t __attribute__((unused)) *isdn_multislot, enum v5x_mgmt_prim prim, const uint8_t *cause,
uint8_t cause_len);

View File

@ -1,90 +0,0 @@
/* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
*
* All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "v5x_le_ctrl_fsm.h"
#include "v5x_le_provisioning.h"
#include "logging.h"
/* ITU-T G.964 Section 14.5 V5.1-re-provisioning procedures */
/* This is incomplete and very minimal */
void v5x_le_provisioning_init(void)
{
LOGP(DV5PROV, LOGL_NOTICE, "Using V5x provisioning\n");
}
/* messages from common control layer */
void v5x_le_provisioning_rcv(struct v5x_interface *v5if, uint8_t cfi, uint8_t variant, uint8_t rej_cause,
uint32_t interface_id)
{
LOGP(DV5PROV, LOGL_DEBUG, "Received common control message from control protocol. "
"(cfi = %d, variant = %d, rej_cause = %d, interface_id = %d)\n", cfi, variant, rej_cause, interface_id);
switch (cfi) {
case V5X_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID:
LOGP(DV5PROV, LOGL_INFO, "AN requests variant and interface ID, replying.\n");
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_VARIANT_AND_INTERFACE_ID, NULL, &v5if->variant, &v5if->id);
break;
case V5X_CTRL_ID_RESTART_REQUEST:
LOGP(DV5PROV, LOGL_INFO, "AN requests restart, replying.\n");
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_RESTART_COMPLETE, NULL, NULL, NULL);
break;
case V5X_CTRL_ID_VARIANT_AND_INTERFACE_ID:
LOGP(DV5PROV, LOGL_INFO, "AN replies variant and interface ID. (variant = %d, interface_id = %d)\n",
variant, interface_id);
if (variant != v5if->variant)
LOGP(DV5PROV, LOGL_ERROR, "Variant does not match: AN(%d) != LE(%d)\n", variant, v5if->variant);
if (interface_id != v5if->id) {
LOGP(DV5PROV, LOGL_ERROR, "Interface ID does not match: AN(%d) != LE(%d)\n", variant,
v5if->variant);
}
break;
case V5X_CTRL_ID_RESTART_COMPLETE:
LOGP(DV5PROV, LOGL_INFO, "AN replies restart.\n");
break;
default:
LOGP(DV5PROV, LOGL_NOTICE, "Ignoring common control message with cfi = %d\n", cfi);
}
}
/* perform provisioning */
void v5x_le_provisioning_start(struct v5x_interface *v5if)
{
/* ask for variant and interface ID */
LOGP(DV5PROV, LOGL_INFO, "Requesting variant and interface ID.\n");
v5x_le_ctrl_common_snd(v5if, V5X_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID, NULL, NULL, NULL);
#if 0
Do not send a restart, because it will make Fastlink reset the link after two minutes.
Also port states will not be indicted. (blocked/unblocked)
/* request a restart */
LOGP(DV5PROV, LOGL_INFO, "Requesting restart.\n");
v51_snd_ctrl_common(v5if, V51_CTRL_ID_RESTART_REQUEST, NULL, NULL, NULL);
#endif
}

View File

@ -1,4 +0,0 @@
void v5x_le_provisioning_init(void);
void v5x_le_provisioning_rcv(struct v5x_interface *v5if, uint8_t cfi, uint8_t variant, uint8_t rej_cause, uint32_t interface_id);
void v5x_le_provisioning_start(struct v5x_interface *v5if);