Work on v5x_le_ctrl_fsm.c

This commit is contained in:
Andreas Eversberg 2022-12-26 14:46:18 +01:00
parent b53b6f7338
commit be536b9029
2 changed files with 185 additions and 64 deletions

View File

@ -1,3 +1,5 @@
/* port/common/link CTRL protocol FSM / G.964 14.4 / G.965 16.3 */
/* (C) 2021 by Harald Welte <laforge@gnumonks.org>
* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
*
@ -21,6 +23,10 @@
*
*/
/***********************************************************************/
/* internal data structures */
/***********************************************************************/
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
@ -34,30 +40,20 @@
#include "v5x_protocol.h"
#include "v5x_le_ctrl_fsm.h"
#include "v5x_le_port_fsm.h"
#include "v5x_le_provisioning.h"
#include "v52_le_lcp_fsm.h"
#include "v5x_le_management.h"
#include "logging.h"
#define S(x) (1 << (x))
#define TIMEOUT 1
#define TIMEOUT 1 // T01 T02 TLCT01
/* uncomment to test lost TX messages at the first transmission */
//#define TEST_TX_FAILURE
/* PSTN Protocol FSM */
enum v5x_le_ctrl_fsm_state {
V5X_PSTN_PROT_S_OUT_OF_SERVICE, /* LE0 */
V5X_PSTN_PROT_S_NULL, /* LE1 */
V5X_PSTN_PROT_S_PATH_INIT_BY_LE, /* LE2 */
V5X_PSTN_PROT_S_PATH_INIT_BY_AN, /* LE3 */
V5X_PSTN_PROT_S_PATH_ACTIVE, /* LE4 */
V5X_PSTN_PROT_S_PATH_DISC_REQ, /* LE5 */
V5X_PSTN_PROT_S_PORT_BLOCKED, /* LE6 */
};
/***********************************************************************
* port/common CTRL protocol FSM / G.964 Section 14
***********************************************************************/
/***********************************************************************/
/* state names, event names, primitives, ... */
/***********************************************************************/
enum v5x_ctrl_fsm_state {
V5X_CTRL_ST_OUT_OF_SERVICE = 0,
@ -85,12 +81,23 @@ static const struct value_string v5x_ctrl_fsm_event_names[] = {
static void v5x_ctrl_mdu(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)
{
struct v5x_ctrl_proto *ctrl = fi->priv;
struct v5x_interface *v5if = ctrl->priv;
struct v5x_user_port *v5up = ctrl->priv;
struct v5x_link *v5l = ctrl->priv;
enum v5x_ctrl_func_id cfi;
uint8_t variant;
uint8_t rej_cause;
uint32_t interface_id;
enum v5x_ctrl_func_id cfe;
uint8_t perf_grading;
enum v52_link_ctrl_func lcf;
if (ctrl->v5if) {
enum v5x_ctrl_func_id cfi = *TLVP_VAL(tp, V5X_CTRL_IEI_CTRL_F_ID) & 0x7f;
uint8_t variant = 0;
uint8_t rej_cause = 0;
uint32_t interface_id = 0;
switch (ctrl->type) {
case V5X_CTRL_TYPE_COMMON:
cfi = *TLVP_VAL(tp, V5X_CTRL_IEI_CTRL_F_ID) & 0x7f;
variant = 0;
rej_cause = 0;
interface_id = 0;
LOGP(DV5CTRL, LOGL_DEBUG, "MDU-CTRL received.\n");
@ -100,29 +107,37 @@ static void v5x_ctrl_mdu(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)
rej_cause = *TLVP_VAL(tp, V5X_CTRL_IEI_REJECTION_CAUSE) & 0x0f;
if (TLVP_PRESENT(tp, V5X_CTRL_IEI_INTERFACE_ID))
interface_id = osmo_load32be_ext_2(TLVP_VAL(tp, V5X_CTRL_IEI_INTERFACE_ID), 3);
v5x_le_provisioning_rcv(ctrl->v5if, cfi, variant, rej_cause, interface_id);
}
if (ctrl->v5up) {
enum v5x_ctrl_func_id cfe = *TLVP_VAL(tp, V5X_CTRL_IEI_CTRL_F_ELEMENT) & 0x7f;
uint8_t perf_grading = 0;
v5x_le_common_ctrl_rcv(v5if, cfi, variant, rej_cause, interface_id);
break;
case V5X_CTRL_TYPE_PORT:
cfe = *TLVP_VAL(tp, V5X_CTRL_IEI_CTRL_F_ELEMENT) & 0x7f;
perf_grading = 0;
LOGP(DV5CTRL, LOGL_DEBUG, "FE received for address %d.\n", ctrl->v5up->nr);
LOGP(DV5CTRL, LOGL_DEBUG, "FE received for address %d.\n", v5up->nr);
if (TLVP_PRESENT(tp, V5X_CTRL_IEI_PERFORMANCE_GRADING))
perf_grading = *TLVP_VAL(tp, V5X_CTRL_IEI_PERFORMANCE_GRADING) & 0x0f;
switch (ctrl->v5up->type) {
switch (v5up->type) {
case V5X_USER_TYPE_ISDN:
v5x_le_port_isdn_rcv(ctrl->v5up, cfe, perf_grading);
v5x_le_port_isdn_fe_rcv(v5up, cfe, perf_grading);
break;
case V5X_USER_TYPE_PSTN:
v5x_le_port_pstn_rcv(ctrl->v5up, cfe);
v5x_le_port_pstn_fe_rcv(v5up, cfe);
break;
}
break;
case V5X_CTRL_TYPE_LINK:
lcf = *TLVP_VAL(tp, V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION) & 0x7f;
LOGP(DV5CTRL, LOGL_DEBUG, "FE received for link ID %d.\n", v5l->id);
v52_le_lcp_fe_rcv(v5l, lcf);
break;
}
}
/* display MDU-error_indication */
static void v5x_mdu_error(struct osmo_fsm_inst *fi, const char *error)
static void v5x_mdu_error(struct osmo_fsm_inst __attribute__((unused)) *fi, const char *error)
{
LOGP(DV5CTRL, LOGL_NOTICE, "MDU-error_indication: %s\n", error);
}
@ -131,6 +146,9 @@ static void v5x_mdu_error(struct osmo_fsm_inst *fi, const char *error)
static void v5x_ctrl_send(struct v5x_ctrl_proto *ctrl, struct msgb *msg)
{
struct osmo_fsm_inst *fi = ctrl->fi;
struct v5x_interface *v5if = ctrl->priv;
struct v5x_user_port *v5up = ctrl->priv;
struct v5x_link *v5l = ctrl->priv;
switch (fi->state) {
case V5X_CTRL_ST_IN_SERVICE:
@ -138,12 +156,22 @@ static void v5x_ctrl_send(struct v5x_ctrl_proto *ctrl, struct msgb *msg)
/* no message, clone current message and store to be repeated */
ctrl->tx_msg = msgb_copy(msg, NULL);
/* go to AWAIT_PENDING_ACK */
osmo_fsm_inst_state_chg(fi, V5X_CTRL_ST_AWAIT_ACK, TIMEOUT, (ctrl->v5up) ? 1 : 2);
osmo_fsm_inst_state_chg(fi, V5X_CTRL_ST_AWAIT_ACK, TIMEOUT, 0);
/* send message towards DL */
#ifdef TEST_TX_FAILURE
msgb_free(msg);
#else
v5x_snd((ctrl->v5if) ? : ctrl->v5up->inst, V5X_DLADDR_CTRL, msg);
switch (ctrl->type) {
case V5X_CTRL_TYPE_COMMON:
v5x_dl_snd(v5if, V5X_DLADDR_CTRL, msg);
break;
case V5X_CTRL_TYPE_PORT:
v5x_dl_snd(v5up->interface, V5X_DLADDR_CTRL, msg);
break;
case V5X_CTRL_TYPE_LINK:
v5x_dl_snd(v5l->interface, V52_DLADDR_LCP, msg);
break;
}
#endif
break;
case V5X_CTRL_ST_AWAIT_ACK:
@ -155,7 +183,7 @@ static void v5x_ctrl_send(struct v5x_ctrl_proto *ctrl, struct msgb *msg)
}
/* receive acknowledge */
static void v5x_ctrl_ack(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)
static void v5x_ctrl_ack(struct osmo_fsm_inst *fi, const struct tlv_parsed __attribute__((unused)) *tp)
{
struct v5x_ctrl_proto *ctrl = fi->priv;
struct msgb *msg;
@ -197,6 +225,9 @@ static void v5x_ctrl_stop(struct osmo_fsm_inst *fi)
static int v5x_ctrl_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
struct v5x_ctrl_proto *ctrl = fi->priv;
struct v5x_interface *v5if = ctrl->priv;
struct v5x_user_port *v5up = ctrl->priv;
struct v5x_link *v5l = ctrl->priv;
struct msgb *msg;
if (ctrl->tx_msg) {
@ -206,7 +237,17 @@ static int v5x_ctrl_fsm_timer_cb(struct osmo_fsm_inst *fi)
osmo_timer_schedule(&fi->timer, TIMEOUT, 0);
msg = ctrl->tx_msg;
ctrl->tx_msg = NULL;
v5x_snd((ctrl->v5if) ? : ctrl->v5up->inst, V5X_DLADDR_CTRL, msg);
switch (ctrl->type) {
case V5X_CTRL_TYPE_COMMON:
v5x_dl_snd(v5if, V5X_DLADDR_CTRL, msg);
break;
case V5X_CTRL_TYPE_PORT:
v5x_dl_snd(v5up->interface, V5X_DLADDR_CTRL, msg);
break;
case V5X_CTRL_TYPE_LINK:
v5x_dl_snd(v5l->interface, V52_DLADDR_LCP, msg);
break;
}
} else {
LOGP(DV5CTRL, LOGL_DEBUG, "Timer fired the second time, indicate an error.\n");
/* second expiry: send MDU-error_ind; go to IN_SERVICE */
@ -244,6 +285,8 @@ static void v5x_ctrl_fsm_oos(struct osmo_fsm_inst *fi, uint32_t event, void *dat
case V5X_CTRL_EV_RX_CONTROL_ACK:
v5x_mdu_error(fi, "Received CONTROL ACK, but traffic not started.");
break;
default:
OSMO_ASSERT(0);
}
}
@ -262,6 +305,8 @@ static void v5x_ctrl_fsm_ins(struct osmo_fsm_inst *fi, uint32_t event, void *dat
case V5X_CTRL_EV_RX_CONTROL:
v5x_ctrl_mdu(fi, data);
break;
default:
OSMO_ASSERT(0);
}
}
@ -283,6 +328,8 @@ static void v5x_ctrl_fsm_aa(struct osmo_fsm_inst *fi, uint32_t event, void *data
case V5X_CTRL_EV_RX_CONTROL_ACK:
v5x_ctrl_ack(fi, data);
break;
default:
OSMO_ASSERT(0);
}
}
@ -342,17 +389,17 @@ void v5x_le_ctrl_init(void)
LOGP(DV5CTRL, LOGL_NOTICE, "Using V5x control protocol\n");
}
struct v5x_ctrl_proto *v5x_le_ctrl_create(struct v5x_interface *v5if, struct v5x_user_port *v5up, uint16_t nr)
struct v5x_ctrl_proto *v5x_le_ctrl_create(enum v5x_ctrl_type type, void *ctx, void *priv, uint16_t nr)
{
struct v5x_ctrl_proto *ctrl;
OSMO_ASSERT((v5if && !v5up) || (!v5if && v5up));
OSMO_ASSERT(priv);
ctrl = talloc_zero((v5if) ? : v5up->inst, struct v5x_ctrl_proto);
ctrl = talloc_zero(ctx, struct v5x_ctrl_proto);
if (!ctrl)
return NULL;
ctrl->v5if = v5if;
ctrl->v5up = v5up;
ctrl->type = type;
ctrl->priv = priv;
INIT_LLIST_HEAD(&ctrl->tx_queue);
ctrl->fi = osmo_fsm_inst_alloc(&v5x_ctrl_fsm, ctrl, ctrl, LOGL_DEBUG, NULL);
@ -393,7 +440,7 @@ static struct msgb *v5x_enc_ctrl_port(struct v5x_user_port *v5up, enum v5x_ctrl_
l3h = (struct v5x_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V5X_CTRL_PDISC;
l3h->l3_addr = ntohs(v5x_l3_addr_enc(v5up->nr, is_isdn));
l3h->l3_addr = htons(v5x_l3_addr_enc(v5up->nr, is_isdn));
l3h->msg_type = V5X_CTRL_MSGT_PORT_CTRL;
msgb_tlv_put(msg, V5X_CTRL_IEI_CTRL_F_ELEMENT, 1, &cfe_ie);
@ -412,7 +459,7 @@ static struct msgb *v5x_enc_ctrl_port_ack(struct v5x_user_port *v5up, enum v5x_c
l3h = (struct v5x_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V5X_CTRL_PDISC;
l3h->l3_addr = ntohs(v5x_l3_addr_enc(v5up->nr, is_isdn));
l3h->l3_addr = htons(v5x_l3_addr_enc(v5up->nr, is_isdn));
l3h->msg_type = V5X_CTRL_MSGT_PORT_CTRL_ACK;
msgb_tlv_put(msg, V5X_CTRL_IEI_CTRL_F_ELEMENT, 1, &cfe_ie);
@ -421,8 +468,8 @@ static struct msgb *v5x_enc_ctrl_port_ack(struct v5x_user_port *v5up, enum v5x_c
}
/* G.964 Section 14.4.1.3 / Table 50 */
static struct msgb *v5x_enc_ctrl_common(struct v5x_interface *v5if, enum v5x_ctrl_func_id cfi,
uint8_t *variant, uint8_t *rej_cause, uint32_t *interface_id)
static struct msgb *v5x_enc_ctrl_common(enum v5x_ctrl_func_id cfi, uint8_t *variant, uint8_t *rej_cause,
uint32_t *interface_id)
{
uint8_t cfi_ie = cfi | 0x80;
struct v5x_l3_hdr *l3h;
@ -432,7 +479,7 @@ static struct msgb *v5x_enc_ctrl_common(struct v5x_interface *v5if, enum v5x_ctr
l3h = (struct v5x_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V5X_CTRL_PDISC;
l3h->l3_addr = ntohs(v5x_l3_addr_enc(V5X_DLADDR_CTRL, true));
l3h->l3_addr = htons(v5x_l3_addr_enc(V5X_DLADDR_CTRL, true));
l3h->msg_type = V5X_CTRL_MSGT_COMMON_CTRL;
msgb_tlv_put(msg, V5X_CTRL_IEI_CTRL_F_ID, 1, &cfi_ie);
@ -456,7 +503,7 @@ static struct msgb *v5x_enc_ctrl_common(struct v5x_interface *v5if, enum v5x_ctr
}
/* G.964 Section 14.4.1.4 / Table 51 */
static struct msgb *v5x_enc_ctrl_common_ack(struct v5x_interface *v5if, enum v5x_ctrl_func_id cfi)
static struct msgb *v5x_enc_ctrl_common_ack(enum v5x_ctrl_func_id cfi)
{
uint8_t cfi_ie = cfi | 0x80;
struct v5x_l3_hdr *l3h;
@ -474,6 +521,44 @@ static struct msgb *v5x_enc_ctrl_common_ack(struct v5x_interface *v5if, enum v5x
return msg;
}
/* G.965 Section 16.3.1.1 / Table 19 */
static struct msgb *v52_enc_ctrl_link_ack(struct v5x_link *v5l, enum v52_link_ctrl_func lcf)
{
uint8_t lcf_ie = lcf | 0x80;
struct v5x_l3_hdr *l3h;
struct msgb *msg = msgb_alloc_v5x();
if (!msg)
return NULL;
l3h = (struct v5x_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V5X_CTRL_PDISC;
l3h->l3_addr = htons(v5l->id);
l3h->msg_type = V52_CTRL_MSGT_LCP_LINK_CTRL_ACK;
msgb_tlv_put(msg, V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION, 1, &lcf_ie);
return msg;
}
/* G.965 Section 16.3.1.2 / Table 20 */
static struct msgb *v52_enc_ctrl_link(struct v5x_link *v5l, enum v52_link_ctrl_func lcf)
{
uint8_t lcf_ie = lcf | 0x80;
struct v5x_l3_hdr *l3h;
struct msgb *msg = msgb_alloc_v5x();
if (!msg)
return NULL;
l3h = (struct v5x_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V5X_CTRL_PDISC;
l3h->l3_addr = htons(v5l->id);
l3h->msg_type = V52_CTRL_MSGT_LCP_LINK_CTRL;
msgb_tlv_put(msg, V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION, 1, &lcf_ie);
return msg;
}
/***********************************************************************
* V5 Message receiving / decoding
***********************************************************************/
@ -485,7 +570,7 @@ static int v5x_rcv_ctrl_port(struct v5x_user_port *v5up, uint8_t msg_type, const
switch (msg_type) {
case V5X_CTRL_MSGT_PORT_CTRL:
/* send ACK to AN */
v5x_snd(v5up->inst, V5X_DLADDR_CTRL, v5x_enc_ctrl_port_ack(v5up, cfe, v5up->type == V5X_USER_TYPE_ISDN));
v5x_dl_snd(v5up->interface, V5X_DLADDR_CTRL, v5x_enc_ctrl_port_ack(v5up, cfe, v5up->type == V5X_USER_TYPE_ISDN));
/* FIXME: send event to FSM */
osmo_fsm_inst_dispatch(v5up->ctrl->fi, V5X_CTRL_EV_RX_CONTROL, (void *)tp);
return 0;
@ -502,7 +587,7 @@ static int v5x_rcv_ctrl_common(struct v5x_interface *v5if, uint8_t msg_type, con
switch (msg_type) {
case V5X_CTRL_MSGT_COMMON_CTRL:
v5x_snd(v5if, V5X_DLADDR_CTRL, v5x_enc_ctrl_common_ack(v5if, cfi));
v5x_dl_snd(v5if, V5X_DLADDR_CTRL, v5x_enc_ctrl_common_ack(cfi));
/* send event to FSM */
osmo_fsm_inst_dispatch(v5if->control.ctrl->fi, V5X_CTRL_EV_RX_CONTROL, (void *)tp);
/* send ACK to AN */
@ -516,33 +601,57 @@ static int v5x_rcv_ctrl_common(struct v5x_interface *v5if, uint8_t msg_type, con
}
}
static int v52_rcv_ctrl_link(struct v5x_link *v5l, uint8_t msg_type, const struct tlv_parsed *tp)
{
enum v52_link_ctrl_func lcf = *TLVP_VAL(tp, V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION) & 0x7f;
switch (msg_type) {
case V52_CTRL_MSGT_LCP_LINK_CTRL:
v5x_dl_snd(v5l->interface, V52_DLADDR_LCP, v52_enc_ctrl_link_ack(v5l, lcf));
/* send event to FSM */
osmo_fsm_inst_dispatch(v5l->ctrl->fi, V5X_CTRL_EV_RX_CONTROL, (void *)tp);
/* send ACK to AN */
return 0;
case V52_CTRL_MSGT_LCP_LINK_CTRL_ACK:
/* send event to FSM */
osmo_fsm_inst_dispatch(v5l->ctrl->fi, V5X_CTRL_EV_RX_CONTROL_ACK, (void *)tp);
return 0;
default:
return -EINVAL;
}
}
/* receive message from lower (DL) layer */
int v5x_le_ctrl_rcv(struct v5x_interface *v5if, uint16_t l3_addr, bool is_isdn, uint8_t msg_type, const struct tlv_parsed *tp)
int v5x_le_ctrl_dl_rcv(struct v5x_interface *v5if, uint16_t l3_addr, bool is_isdn, uint8_t msg_type,
const struct tlv_parsed *tp)
{
struct v5x_user_port *v5up;
struct v5x_link *v5l;
switch (msg_type) {
case V5X_CTRL_MSGT_PORT_CTRL:
case V5X_CTRL_MSGT_PORT_CTRL_ACK:
v5up = v5x_user_port_find(v5if, l3_addr, is_isdn);
if (!v5up) {
LOGP(DV5CTRL, LOGL_ERROR, "Received port control message from unknown layer 3 address %d. Please check provisioning!\n", l3_addr);
LOGP(DV5CTRL, LOGL_ERROR, "Received %s port control message with unknown layer 3 address %d. "
"Please check provisioning!\n", is_isdn ? "ISDN" : "PSTN", l3_addr);
return -ENODEV;
}
if (v5up->type == V5X_USER_TYPE_ISDN && !is_isdn) {
LOGP(DV5CTRL, LOGL_ERROR, "Received port control message from layer 3 address %d. AN is set to PSTN, LE to ISDN, please check provisioning!", l3_addr);
return -EIO;
}
if (v5up->type == V5X_USER_TYPE_PSTN && is_isdn) {
LOGP(DV5CTRL, LOGL_ERROR, "Received port control message from layer 3 address %d. AN is set to ISDN, LE to PSTN, please check provisioning!", l3_addr);
return -EIO;
}
return v5x_rcv_ctrl_port(v5up, msg_type, tp);
case V5X_CTRL_MSGT_COMMON_CTRL:
case V5X_CTRL_MSGT_COMMON_CTRL_ACK:
if (l3_addr != V5X_DLADDR_CTRL)
return -EINVAL;
return v5x_rcv_ctrl_common(v5if, msg_type, tp);
case V52_CTRL_MSGT_LCP_LINK_CTRL:
case V52_CTRL_MSGT_LCP_LINK_CTRL_ACK:
v5l = v5x_link_find_id(v5if, l3_addr);
if (!v5l) {
LOGP(DV5CTRL, LOGL_ERROR, "Received link control message with unknown link ID %d. Please "
"check provisioning!\n", l3_addr);
return -ENODEV;
}
return v52_rcv_ctrl_link(v5l, msg_type, tp);
}
return -EINVAL;
@ -556,23 +665,33 @@ int v5x_le_ctrl_rcv(struct v5x_interface *v5if, uint16_t l3_addr, bool is_isdn,
int v5x_le_ctrl_common_snd(struct v5x_interface *v5if, enum v5x_ctrl_func_id cfi,
uint8_t *rej_cause, uint8_t *variant, uint32_t *interface_id)
{
LOGP(DV5CTRL, LOGL_DEBUG, "Sending MDU-CTRL.\n");
LOGP(DV5CTRL, LOGL_DEBUG, "Sending MDU-CTRL (from common control).\n");
osmo_fsm_inst_dispatch(v5if->control.ctrl->fi, V5X_CTRL_EV_MDU_CTRL,
v5x_enc_ctrl_common(v5if, cfi, variant, rej_cause, interface_id));
v5x_enc_ctrl_common(cfi, variant, rej_cause, interface_id));
return 0;
}
/* send port message from upper layer */
int v5x_le_ctrl_port_snd(struct v5x_user_port *v5up, enum v5x_ctrl_func_el cfe)
{
LOGP(DV5CTRL, LOGL_DEBUG, "Sending FE.\n");
LOGP(DV5CTRL, LOGL_DEBUG, "Sending FE (from port).\n");
osmo_fsm_inst_dispatch(v5up->ctrl->fi, V5X_CTRL_EV_MDU_CTRL,
v5x_enc_ctrl_port(v5up, cfe, v5up->type == V5X_USER_TYPE_ISDN));
return 0;
}
/* send link message from upper layer */
int v52_le_ctrl_link_snd(struct v5x_link *v5l, enum v52_link_ctrl_func lcf)
{
LOGP(DV5CTRL, LOGL_DEBUG, "Sending FE (from LCP).\n");
osmo_fsm_inst_dispatch(v5l->ctrl->fi, V5X_CTRL_EV_MDU_CTRL,
v52_enc_ctrl_link(v5l, lcf));
return 0;
}
void v5x_le_ctrl_start(struct v5x_ctrl_proto *ctrl)
{
osmo_fsm_inst_dispatch(ctrl->fi, V5X_CTRL_EV_MDU_START_TRAFFIC, NULL);

View File

@ -1,10 +1,12 @@
void v5x_le_ctrl_init(void);
struct v5x_ctrl_proto *v5x_le_ctrl_create(struct v5x_interface *v5if, struct v5x_user_port *v5up, uint16_t nr);
struct v5x_ctrl_proto *v5x_le_ctrl_create(enum v5x_ctrl_type type, void *ctx, void *priv, uint16_t nr);
void v5x_le_ctrl_destroy(struct v5x_ctrl_proto *ctrl);
int v5x_le_ctrl_rcv(struct v5x_interface *v5if, uint16_t l3_addr, bool is_isdn, uint8_t msg_type, const struct tlv_parsed *tp);
int v5x_le_ctrl_dl_rcv(struct v5x_interface *v5if, uint16_t l3_addr, bool is_isdn, uint8_t msg_type,
const struct tlv_parsed *tp);
int v5x_le_ctrl_common_snd(struct v5x_interface *v5if, enum v5x_ctrl_func_id cfi,
uint8_t *rej_cause, uint8_t *variant, uint32_t *interface_id);
uint8_t *rej_cause, uint8_t *variant, uint32_t *interface_id);
int v5x_le_ctrl_port_snd(struct v5x_user_port *v5up, enum v5x_ctrl_func_el cfe);
int v52_le_ctrl_link_snd(struct v5x_link *v5l, enum v52_link_ctrl_func lcf);
void v5x_le_ctrl_start(struct v5x_ctrl_proto *ctrl);
void v5x_le_ctrl_stop(struct v5x_ctrl_proto *ctrl);