Serveral fixes to v51_le_ctrl.c

This commit is contained in:
Andreas Eversberg 2022-12-03 12:47:03 +01:00
parent 537301f656
commit ae1a7de2b8
2 changed files with 131 additions and 93 deletions

View File

@ -23,7 +23,6 @@
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <arpa/inet.h>
#include <osmocom/core/utils.h>
@ -33,6 +32,8 @@
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "v51_le_ctrl.h"
#include "v51_le_provisioning.h"
#include "v52_le_user_port_fsm.h"
#include "logging.h"
#define S(x) (1 << (x))
@ -40,7 +41,6 @@
#define TIMEOUT 1
/* uncomment to test lost TX messages at the first transmission */
#warning fixme
//#define TEST_TX_FAILURE
/* PSTN Protocol FSM */
@ -81,43 +81,41 @@ static const struct value_string v51_ctrl_fsm_event_names[] = {
{ 0, NULL }
};
static int blocked = 1;
static void v51_mdu_ctrl(struct osmo_fsm_inst *fi, const struct tlv_parsed *tp)
{
struct v5x_ctrl_proto *ctrl = fi->priv;
LOGP(DV5CTRL, LOGL_NOTICE, "MDU-CTRL\n");
if (ctrl->v5if) {
puts("common control");
enum v51_ctrl_func_id cfi = *TLVP_VAL(tp, V51_CTRL_IEI_CTRL_F_ID) & 0x7f;
printf("cfi=%d\n", cfi);
if (cfi == V51_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID) {
puts("request variant+id");
v51_snd_ctrl_common(ctrl->v5if, V51_CTRL_ID_VARIANT_AND_INTERFACE_ID, NULL, &ctrl->v5if->variant, &ctrl->v5if->id);
}
if (cfi == V51_CTRL_ID_RESTART_REQUEST) {
puts("request restart");
v51_snd_ctrl_common(ctrl->v5if, V51_CTRL_ID_RESTART_COMPLETE, NULL, NULL, NULL);
}
uint8_t variant = 0;
uint8_t rej_cause = 0;
uint32_t interface_id = 0;
LOGP(DV5CTRL, LOGL_DEBUG, "MDU-CTRL received.\n");
if (TLVP_PRESENT(tp, V51_CTRL_IEI_VARIANT))
variant = *TLVP_VAL(tp, V51_CTRL_IEI_VARIANT) & 0x7f;
if (TLVP_PRESENT(tp, V51_CTRL_IEI_REJECTION_CAUSE))
rej_cause = *TLVP_VAL(tp, V51_CTRL_IEI_REJECTION_CAUSE) & 0x0f;
if (TLVP_PRESENT(tp, V51_CTRL_IEI_INTERFACE_ID))
interface_id = osmo_load32be_ext_2(TLVP_VAL(tp, V51_CTRL_IEI_INTERFACE_ID), 3);
v51_rcv_provisioning(ctrl->v5if, cfi, variant, rej_cause, interface_id);
}
if (ctrl->v5up) {
puts("port control");
enum v51_ctrl_func_el cfe = *TLVP_VAL(tp, V51_CTRL_IEI_CTRL_F_ELEMENT) & 0x7f;
printf("cfe=%d\n", cfe);
if (cfe == V51_CTRL_FE201_UNBLOCK) {
puts("request unblock");
if (blocked) {
blocked = 0;
v51_snd_ctrl_port(ctrl->v5up, V51_CTRL_FE201_UNBLOCK);
}
}
if (cfe == V51_CTRL_FE203_BLOCK) {
puts("request block");
if (!blocked) {
blocked = 1;
v51_snd_ctrl_port(ctrl->v5up, V51_CTRL_FE203_BLOCK);
}
enum v51_ctrl_func_id cfe = *TLVP_VAL(tp, V51_CTRL_IEI_CTRL_F_ELEMENT) & 0x7f;
uint8_t perf_grading = 0;
LOGP(DV5CTRL, LOGL_DEBUG, "FE received for address %d.\n", ctrl->v5up->nr);
if (TLVP_PRESENT(tp, V51_CTRL_IEI_PERFORMANCE_GRADING))
perf_grading = *TLVP_VAL(tp, V51_CTRL_IEI_PERFORMANCE_GRADING) & 0x0f;
switch (ctrl->v5up->type) {
case V5X_USER_TYPE_ISDN:
v51_ctrl_le_i_port_rcv(ctrl->v5up, cfe, perf_grading);
break;
case V5X_USER_TYPE_PSTN:
v51_ctrl_le_p_port_rcv(ctrl->v5up, cfe);
break;
}
}
}
@ -228,23 +226,23 @@ static int v51_ctrl_fsm_timer_cb(struct osmo_fsm_inst *fi)
static void v51_ctrl_fsm_oos(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case V51_CTRL_EV_MDU_START_TRAFFIC:
/* go to IN_SERVICE */
osmo_fsm_inst_state_chg(fi, V51_CTRL_ST_IN_SERVICE, 0, 0);
break;
case V51_CTRL_EV_MDU_STOP_TRAFFIC:
v51_mdu_error(fi, "Got MDU-stop, but traffic not started.");
break;
case V51_CTRL_EV_MDU_CTRL:
msgb_free(data);
v51_mdu_error(fi, "Got MDU-CTRL, but traffic not started.");
break;
case V51_CTRL_EV_RX_CONTROL:
v51_mdu_error(fi, "Received CONTROL, but traffic not started.");
break;
case V51_CTRL_EV_RX_CONTROL_ACK:
v51_mdu_error(fi, "Received CONTROL ACK, but traffic not started.");
break;
case V51_CTRL_EV_MDU_START_TRAFFIC:
/* go to IN_SERVICE */
osmo_fsm_inst_state_chg(fi, V51_CTRL_ST_IN_SERVICE, 0, 0);
break;
case V51_CTRL_EV_MDU_STOP_TRAFFIC:
v51_mdu_error(fi, "Got MDU-stop, but traffic not started.");
break;
case V51_CTRL_EV_MDU_CTRL:
msgb_free(data);
v51_mdu_error(fi, "Got MDU-CTRL, but traffic not started.");
break;
case V51_CTRL_EV_RX_CONTROL:
v51_mdu_error(fi, "Received CONTROL, but traffic not started.");
break;
case V51_CTRL_EV_RX_CONTROL_ACK:
v51_mdu_error(fi, "Received CONTROL ACK, but traffic not started.");
break;
}
}
@ -252,17 +250,17 @@ static void v51_ctrl_fsm_oos(struct osmo_fsm_inst *fi, uint32_t event, void *dat
static void v51_ctrl_fsm_ins(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case V51_CTRL_EV_MDU_START_TRAFFIC:
break;
case V51_CTRL_EV_MDU_STOP_TRAFFIC:
v51_ctrl_stop(fi);
break;
case V51_CTRL_EV_MDU_CTRL:
v51_ctrl_send(fi->priv, data);
break;
case V51_CTRL_EV_RX_CONTROL:
v51_mdu_ctrl(fi, data);
break;
case V51_CTRL_EV_MDU_START_TRAFFIC:
break;
case V51_CTRL_EV_MDU_STOP_TRAFFIC:
v51_ctrl_stop(fi);
break;
case V51_CTRL_EV_MDU_CTRL:
v51_ctrl_send(fi->priv, data);
break;
case V51_CTRL_EV_RX_CONTROL:
v51_mdu_ctrl(fi, data);
break;
}
}
@ -270,20 +268,20 @@ static void v51_ctrl_fsm_ins(struct osmo_fsm_inst *fi, uint32_t event, void *dat
static void v51_ctrl_fsm_aa(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case V51_CTRL_EV_MDU_START_TRAFFIC:
break;
case V51_CTRL_EV_MDU_STOP_TRAFFIC:
v51_ctrl_stop(fi);
break;
case V51_CTRL_EV_MDU_CTRL:
v51_ctrl_send(fi->priv, data);
break;
case V51_CTRL_EV_RX_CONTROL:
v51_mdu_ctrl(fi, data);
break;
case V51_CTRL_EV_RX_CONTROL_ACK:
v51_ctrl_ack(fi, data);
break;
case V51_CTRL_EV_MDU_START_TRAFFIC:
break;
case V51_CTRL_EV_MDU_STOP_TRAFFIC:
v51_ctrl_stop(fi);
break;
case V51_CTRL_EV_MDU_CTRL:
v51_ctrl_send(fi->priv, data);
break;
case V51_CTRL_EV_RX_CONTROL:
v51_mdu_ctrl(fi, data);
break;
case V51_CTRL_EV_RX_CONTROL_ACK:
v51_ctrl_ack(fi, data);
break;
}
}
@ -334,11 +332,20 @@ struct osmo_fsm v51_ctrl_fsm = {
.event_names = v51_ctrl_fsm_event_names,
};
void v51_ctrl_init(void)
{
int rc;
rc = osmo_fsm_register(&v51_ctrl_fsm);
OSMO_ASSERT(!rc);
LOGP(DV5CTRL, LOGL_NOTICE, "Using V5x control protocol\n");
}
struct v5x_ctrl_proto *v51_ctrl_create(struct v5x_interface *v5if, struct v5x_user_port *v5up, uint16_t nr)
{
struct v5x_ctrl_proto *ctrl;
assert((v5if && !v5up) || (!v5if && v5up));
OSMO_ASSERT((v5if && !v5up) || (!v5if && v5up));
ctrl = talloc_zero((v5if) ? : v5up->inst, struct v5x_ctrl_proto);
if (!ctrl)
@ -348,20 +355,34 @@ struct v5x_ctrl_proto *v51_ctrl_create(struct v5x_interface *v5if, struct v5x_us
INIT_LLIST_HEAD(&ctrl->tx_queue);
ctrl->fi = osmo_fsm_inst_alloc(&v51_ctrl_fsm, ctrl, ctrl, LOGL_DEBUG, NULL);
if (!ctrl->fi)
if (!ctrl->fi) {
v51_ctrl_destroy(ctrl);
return NULL;
}
osmo_fsm_inst_update_id_f(ctrl->fi, "%d", nr);
return ctrl;
}
void v51_ctrl_destroy(struct v5x_ctrl_proto *ctrl)
{
/* get rid of pending messages */
msgb_queue_free(&ctrl->tx_queue);
if (ctrl->tx_msg)
msgb_free(ctrl->tx_msg);
if (ctrl->fi)
osmo_fsm_inst_free(ctrl->fi);
free(ctrl);
}
/***********************************************************************
* V5 Message encoding / sending
***********************************************************************/
/* G.964 Section 14.4.1.1 / Table 48 */
struct msgb *v51_enc_ctrl_port(struct v5x_user_port *v5up, enum v51_ctrl_func_el cfe)
struct msgb *v51_enc_ctrl_port(struct v5x_user_port *v5up, enum v51_ctrl_func_el cfe, bool is_isdn)
{
uint8_t cfe_ie = cfe | 0x80;
struct v51_l3_hdr *l3h;
@ -371,7 +392,7 @@ struct msgb *v51_enc_ctrl_port(struct v5x_user_port *v5up, enum v51_ctrl_func_el
l3h = (struct v51_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V51_CTRL_PDISC;
l3h->l3_addr = ntohs(v51_l3_addr_enc(v5up->nr, true));
l3h->l3_addr = ntohs(v51_l3_addr_enc(v5up->nr, is_isdn));
l3h->msg_type = V51_CTRL_MSGT_PORT_CTRL;
msgb_tlv_put(msg, V51_CTRL_IEI_CTRL_F_ELEMENT, 1, &cfe_ie);
@ -380,7 +401,7 @@ struct msgb *v51_enc_ctrl_port(struct v5x_user_port *v5up, enum v51_ctrl_func_el
}
/* G.964 Section 14.4.1.2 / Table 49 */
static struct msgb *v51_enc_ctrl_port_ack(struct v5x_user_port *v5up, enum v51_ctrl_func_el cfe)
static struct msgb *v51_enc_ctrl_port_ack(struct v5x_user_port *v5up, enum v51_ctrl_func_el cfe, bool is_isdn)
{
uint8_t cfe_ie = cfe | 0x80;
struct v51_l3_hdr *l3h;
@ -390,7 +411,7 @@ static struct msgb *v51_enc_ctrl_port_ack(struct v5x_user_port *v5up, enum v51_c
l3h = (struct v51_l3_hdr *) msgb_put(msg, sizeof(*l3h));
l3h->pdisc = V51_CTRL_PDISC;
l3h->l3_addr = ntohs(v51_l3_addr_enc(v5up->nr, true));
l3h->l3_addr = ntohs(v51_l3_addr_enc(v5up->nr, is_isdn));
l3h->msg_type = V51_CTRL_MSGT_PORT_CTRL_ACK;
msgb_tlv_put(msg, V51_CTRL_IEI_CTRL_F_ELEMENT, 1, &cfe_ie);
@ -400,7 +421,7 @@ static struct msgb *v51_enc_ctrl_port_ack(struct v5x_user_port *v5up, enum v51_c
/* G.964 Section 14.4.1.3 / Table 50 */
static struct msgb *v51_enc_ctrl_common(struct v5x_interface *v5if, enum v51_ctrl_func_id cfi,
uint8_t *rej_cause, uint8_t *variant, uint32_t *interface_id)
uint8_t *variant, uint8_t *rej_cause, uint32_t *interface_id)
{
uint8_t cfi_ie = cfi | 0x80;
struct v51_l3_hdr *l3h;
@ -462,10 +483,11 @@ static int v51_rcv_ctrl_port(struct v5x_user_port *v5up, uint8_t msg_type, const
switch (msg_type) {
case V51_CTRL_MSGT_PORT_CTRL:
/* send ACK to AN */
v5x_snd(v5up->inst, V51_DLADDR_CTRL, v51_enc_ctrl_port_ack(v5up, cfe, v5up->type == V5X_USER_TYPE_ISDN));
/* FIXME: send event to FSM */
osmo_fsm_inst_dispatch(v5up->ctrl->fi, V51_CTRL_EV_RX_CONTROL, (void *)tp);
/* send ACK to AN */
return v5x_snd(v5up->inst, V51_DLADDR_CTRL, v51_enc_ctrl_port_ack(v5up, cfe));
return 0;
case V51_CTRL_MSGT_PORT_CTRL_ACK:
osmo_fsm_inst_dispatch(v5up->ctrl->fi, V51_CTRL_EV_RX_CONTROL_ACK, (void *)tp);
default:
@ -479,11 +501,11 @@ static int v51_rcv_ctrl_common(struct v5x_interface *v5if, uint8_t msg_type, con
switch (msg_type) {
case V51_CTRL_MSGT_COMMON_CTRL:
v5x_snd(v5if, V51_DLADDR_CTRL, v51_enc_ctrl_common_ack(v5if, cfi));
/* send event to FSM */
osmo_fsm_inst_dispatch(v5if->control.ctrl->fi, V51_CTRL_EV_RX_CONTROL, (void *)tp);
/* send ACK to AN */
printf("sending ack\n");
return v5x_snd(v5if, V51_DLADDR_CTRL, v51_enc_ctrl_common_ack(v5if, cfi));
return 0;
case V51_CTRL_MSGT_COMMON_CTRL_ACK:
/* send event to FSM */
osmo_fsm_inst_dispatch(v5if->control.ctrl->fi, V51_CTRL_EV_RX_CONTROL_ACK, (void *)tp);
@ -494,16 +516,26 @@ static int v51_rcv_ctrl_common(struct v5x_interface *v5if, uint8_t msg_type, con
}
/* receive message from lower (DL) layer */
int v51_rcv_ctrl(struct v5x_interface *v5if, uint16_t l3_addr, uint8_t msg_type, const struct tlv_parsed *tp)
int v51_rcv_ctrl(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;
switch (msg_type) {
case V51_CTRL_MSGT_PORT_CTRL:
case V51_CTRL_MSGT_PORT_CTRL_ACK:
v5up = v5x_user_port_find(v5if, l3_addr);
if (!v5up)
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);
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 v51_rcv_ctrl_port(v5up, msg_type, tp);
case V51_CTRL_MSGT_COMMON_CTRL:
case V51_CTRL_MSGT_COMMON_CTRL_ACK:
@ -523,14 +555,20 @@ int v51_rcv_ctrl(struct v5x_interface *v5if, uint16_t l3_addr, uint8_t msg_type,
int v51_snd_ctrl_common(struct v5x_interface *v5if, enum v51_ctrl_func_id cfi,
uint8_t *rej_cause, uint8_t *variant, uint32_t *interface_id)
{
osmo_fsm_inst_dispatch(v5if->control.ctrl->fi, V51_CTRL_EV_MDU_CTRL, v51_enc_ctrl_common(v5if, cfi, rej_cause, variant, interface_id));
LOGP(DV5CTRL, LOGL_DEBUG, "Sending MDU-CTRL.\n");
osmo_fsm_inst_dispatch(v5if->control.ctrl->fi, V51_CTRL_EV_MDU_CTRL,
v51_enc_ctrl_common(v5if, cfi, variant, rej_cause, interface_id));
return 0;
}
/* send port message from upper layer */
int v51_snd_ctrl_port(struct v5x_user_port *v5up, enum v51_ctrl_func_el cfe)
{
osmo_fsm_inst_dispatch(v5up->ctrl->fi, V51_CTRL_EV_MDU_CTRL, v51_enc_ctrl_port(v5up, cfe));
LOGP(DV5CTRL, LOGL_DEBUG, "Sending FE.\n");
osmo_fsm_inst_dispatch(v5up->ctrl->fi, V51_CTRL_EV_MDU_CTRL,
v51_enc_ctrl_port(v5up, cfe, v5up->type == V5X_USER_TYPE_ISDN));
return 0;
}
@ -540,5 +578,5 @@ void v51_start_ctrl(struct v5x_ctrl_proto *ctrl)
}
void v51_stop_ctrl(struct v5x_ctrl_proto *ctrl)
{
osmo_fsm_inst_dispatch(ctrl->fi, V51_CTRL_EV_MDU_START_TRAFFIC, NULL);
osmo_fsm_inst_dispatch(ctrl->fi, V51_CTRL_EV_MDU_STOP_TRAFFIC, NULL);
}

View File

@ -1,8 +1,8 @@
extern struct osmo_fsm v51_ctrl_fsm;
void v51_ctrl_init(void);
struct v5x_ctrl_proto *v51_ctrl_create(struct v5x_interface *v5if, struct v5x_user_port *v5up, uint16_t nr);
int v51_rcv_ctrl(struct v5x_interface *v5if, uint16_t l3_addr, uint8_t msg_type, const struct tlv_parsed *tp);
void v51_ctrl_destroy(struct v5x_ctrl_proto *ctrl);
int v51_rcv_ctrl(struct v5x_interface *v5if, uint16_t l3_addr, bool is_isdn, uint8_t msg_type, const struct tlv_parsed *tp);
int v51_snd_ctrl_common(struct v5x_interface *v5if, enum v51_ctrl_func_id cfi,
uint8_t *rej_cause, uint8_t *variant, uint32_t *interface_id);
int v51_snd_ctrl_port(struct v5x_user_port *v5up, enum v51_ctrl_func_el cfe);