Work on v5x_data.c and v5x_internal.h

This commit is contained in:
Andreas Eversberg 2022-12-16 16:39:24 +01:00
parent 0b9f3309f5
commit de95171aef
2 changed files with 327 additions and 23 deletions

View File

@ -1,4 +1,3 @@
#include <assert.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/linuxlist.h>
@ -7,7 +6,10 @@
#include "v5x_protocol.h"
#include "v51_le_ctrl.h"
#include "v52_le_user_port_fsm.h"
#include "v5x_l2_mgmt.h"
#include "v5x_le_pstn_fsm.h"
#include "lapv5.h"
#include "logging.h"
static LLIST_HEAD(v5_instances);
@ -100,42 +102,279 @@ struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dia
return v5if;
}
struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t nr, enum v5x_user_type type)
#warning hacking
int ph_data_req_raw(struct msgb *msg, int ts);
void ph_socket_rx_cb(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data, int length)
{
struct v5x_user_port *v5up = s->priv;
switch (prim) {
case PH_PRIM_CTRL_REQ:
/* deactivate channels, if active */
if ((channel == 0 || channel == 3) && length && *data == PH_CTRL_BLOCK) {
v5up->ts_activated[0] = 0;
v5up->ts_activated[1] = 0;
}
v5x_mph_rcv_le(v5up, prim, data, length);
break;
case PH_PRIM_ACT_REQ:
if (channel == 1 || channel == 2) {
v5up->ts_activated[channel - 1] = 1;
ph_socket_tx_msg(s, channel, PH_PRIM_ACT_IND, NULL, 0);
break;
}
v5x_mph_rcv_le(v5up, prim, data, length);
break;
case PH_PRIM_DACT_REQ:
if (channel == 1 || channel == 2) {
v5up->ts_activated[channel - 1] = 0;
ph_socket_tx_msg(s, channel, PH_PRIM_DACT_IND, NULL, 0);
break;
}
v5x_mph_rcv_le(v5up, prim, data, length);
break;
case PH_PRIM_DATA_REQ:
if (v5up->type == V5X_USER_TYPE_PSTN && channel == 0) {
struct msgb *msg = msgb_alloc_headroom(length + 32, 32, "V5 PSTN MSG");
memcpy(msgb_put(msg, length), data, length);
v5x_fe_rcv_le(v5up, msg);
} else if (v5up->type == V5X_USER_TYPE_ISDN && channel == 3) {
struct msgb *msg = msgb_alloc_headroom(length + 32, 32, "V5 EF MSG");
memcpy(msgb_put(msg, length), data, length);
lapv5ef_tx(v5up, msg);
} else if ((channel == 1 || channel == 2) && v5up->ts_nr[channel - 1]) {
struct msgb *msg = msgb_alloc_headroom(length + 32, 32, "B MSG");
memcpy(msgb_put(msg, length), data, length);
ph_data_req_raw(msg, v5up->ts_nr[channel - 1]);
}
/* always confirm */
ph_socket_tx_msg(s, channel, PH_PRIM_DATA_CNF, NULL, 0);
break;
}
}
struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t nr, enum v5x_user_type type, uint8_t ts1, uint8_t ts2)
{
struct v5x_user_port *v5up;
int rc;
v5up = talloc_zero(v5if, struct v5x_user_port);
if (!v5up)
return NULL;
v5up->inst = v5if;
v5up->type = type;
v5up->ctrl = v51_ctrl_create(NULL, v5up, nr);
if (!v5up->ctrl)
return NULL;
switch (type) {
case V5X_USER_TYPE_ISDN:
assert(nr <= 8191);
v5up->port_fi = v51_ctrl_le_i_port_create(v5up, nr);
break;
case V5X_USER_TYPE_PSTN:
assert(nr <= 32767);
v5up->port_fi = v51_ctrl_le_p_port_create(v5up, nr);
break;
}
v5up->nr = nr;
llist_add_tail(&v5up->list, &v5if->user_ports);
v5up->inst = v5if;
v5up->nr = nr;
v5up->type = type;
/* assign ports */
if (v5if->dialect == V5X_DIALECT_V51) {
OSMO_ASSERT(ts1 >= 1 && ts1 <= 31);
v5if->links[0].ts[ts1].v5up = v5up;
v5up->ts_nr[0] = ts1;
if (type == V5X_USER_TYPE_ISDN) {
OSMO_ASSERT(ts2 >= 1 && ts2 <= 31);
v5if->links[0].ts[ts2].v5up = v5up;
v5up->ts_nr[1] = ts2;
}
}
v5up->ctrl = v51_ctrl_create(NULL, v5up, nr);
if (!v5up->ctrl) {
LOGP(DV5, LOGL_ERROR, "Failed to create control protocol\n");
v5x_user_port_destroy(v5up);
return NULL;
}
switch (type) {
case V5X_USER_TYPE_ISDN:
sprintf(v5up->ifname, "isdn-%d", nr);
OSMO_ASSERT(nr <= 8175);
v5up->port_fi = v51_ctrl_le_i_port_create(v5up, nr);
if (!v5up->port_fi) {
LOGP(DV5, LOGL_ERROR, "Failed to create port control\n");
v5x_user_port_destroy(v5up);
return NULL;
}
break;
case V5X_USER_TYPE_PSTN:
sprintf(v5up->ifname, "pstn-%d", nr);
OSMO_ASSERT(nr <= 32767);
v5up->port_fi = v51_ctrl_le_p_port_create(v5up, nr);
if (!v5up->port_fi) {
LOGP(DV5, LOGL_ERROR, "Failed to create port control\n");
v5x_user_port_destroy(v5up);
return NULL;
}
v5up->pstn.proto = v5x_pstn_create(v5up, nr);
if (!v5up->pstn.proto) {
LOGP(DV5, LOGL_ERROR, "Failed to create PSTN protocol\n");
v5x_user_port_destroy(v5up);
return NULL;
}
/* bring port into service */
v5x_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
break;
}
rc = ph_socket_init(&v5up->ph_socket, ph_socket_rx_cb, v5up, v5up->ifname, 1);
if (rc < 0) {
LOGP(DV5, LOGL_ERROR, "Failed to create PH-socket\n");
v5x_user_port_destroy(v5up);
return NULL;
}
return v5up;
}
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr)
void v5x_user_port_destroy(struct v5x_user_port *v5up)
{
struct v5x_interface *v5if = v5up->inst;
/* unassign ports */
if (v5up->ts_nr[0])
v5if->links[v5up->link_nr[0]].ts[v5up->ts_nr[0]].v5up = NULL;
if (v5up->ts_nr[1])
v5if->links[v5up->link_nr[1]].ts[v5up->ts_nr[1]].v5up = NULL;
if (v5up->ctrl)
v51_ctrl_destroy(v5up->ctrl);
if (v5up->port_fi)
osmo_fsm_inst_free(v5up->port_fi);
if (v5up->pstn.proto)
v5x_pstn_destroy(v5up->pstn.proto);
ph_socket_exit(&v5up->ph_socket);
llist_del(&v5up->list);
free(v5up);
}
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr, bool is_isdn)
{
struct v5x_user_port *v5up;
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (v5up->nr == nr)
if (v5up->nr == nr && is_isdn == (v5up->type == V5X_USER_TYPE_ISDN))
return v5up;
}
return NULL;
}
#include <osmocom/vty/command.h>
enum v5_vty_node {
INTERFACE_NODE = _LAST_OSMOVTY_NODE + 1,
};
struct cmd_node interface_node = {
INTERFACE_NODE,
"%s(config-if)# ",
1,
};
DEFUN(cfg_interface, cfg_interface_cmd,
"interface", "Configure the V5 interface")
{
struct v5x_instance *v5i = (struct v5x_instance *)v5_instances.next;
struct v5x_interface *v5if = (struct v5x_interface *)v5i->interfaces.next;
vty->node = INTERFACE_NODE;
vty->index = v5if;
return CMD_SUCCESS;
}
DEFUN(cfg_port_pstn, cfg_port_pstn_cmd,
"port pstn <0-32767> <1-31>",
"Create V5 user port\n" "PSTN user port\n" "L3 address\n" "Time slot")
{
struct v5x_interface *v5if = vty->index;
struct v5x_user_port *v5up;
v5up = v5x_user_port_find(v5if, atoi(argv[0]), false);
if (v5up) {
vty_out(vty, "%%Given PSTN user port already exists, remove first.%s", VTY_NEWLINE);
return CMD_WARNING;
}
v5up = v5x_user_port_create(v5if, atoi(argv[0]), V5X_USER_TYPE_PSTN, atoi(argv[1]), 0);
if (!v5up) {
vty_out(vty, "%%Failed to create PSTN user port.%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_no_port_pstn, cfg_no_port_pstn_cmd,
"no port pstn <0-32767>",
NO_STR "Delete V5 user port\n" "PSTN user port\n" "L3 address\n")
{
struct v5x_interface *v5if = vty->index;
struct v5x_user_port *v5up;
v5up = v5x_user_port_find(v5if, atoi(argv[0]), false);
if (!v5up) {
vty_out(vty, "%%Given PSTN user port does not exist.%s", VTY_NEWLINE);
return CMD_WARNING;
}
//FIXME: delete
return CMD_SUCCESS;
}
DEFUN(cfg_port_isdn, cfg_port_isdn_cmd,
"port isdn <0-8175> <1-31> <1-31>",
"Create V5 user port\n" "ISDN user port\n" "L3 address\n" "Time slot 1\n" "Time slot 2\n")
{
struct v5x_interface *v5if = vty->index;
struct v5x_user_port *v5up;
v5up = v5x_user_port_find(v5if, atoi(argv[0]), true);
if (v5up) {
vty_out(vty, "%%Given ISDN user port already exists, remove first.%s", VTY_NEWLINE);
return CMD_WARNING;
}
v5up = v5x_user_port_create(v5if, atoi(argv[0]), V5X_USER_TYPE_ISDN, atoi(argv[1]), atoi(argv[2]));
if (!v5up) {
vty_out(vty, "%%Failed to create ISDN user port.%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_no_port_isdn, cfg_no_port_isdn_cmd,
"no port isdn <0-8175>",
NO_STR "Delete V5 user port\n" "ISDN user port\n" "L3 address\n")
{
struct v5x_interface *v5if = vty->index;
struct v5x_user_port *v5up;
v5up = v5x_user_port_find(v5if, atoi(argv[0]), true);
if (!v5up) {
vty_out(vty, "%%Given ISDN user port does not exist.%s", VTY_NEWLINE);
return CMD_WARNING;
}
//FIXME: delete
return CMD_SUCCESS;
}
static int config_write_interface(struct vty *vty)
{
//FIXME
return CMD_SUCCESS;
}
int v5x_vty_init(void)
{
install_element(CONFIG_NODE, &cfg_interface_cmd);
install_node(&interface_node, config_write_interface);
install_element(INTERFACE_NODE, &cfg_port_pstn_cmd);
install_element(INTERFACE_NODE, &cfg_no_port_pstn_cmd);
install_element(INTERFACE_NODE, &cfg_port_isdn_cmd);
install_element(INTERFACE_NODE, &cfg_no_port_isdn_cmd);
return 0;
}

View File

@ -26,7 +26,50 @@
#include <stdint.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/lapd_core.h>
#include "ph_socket.h"
/* Table 35/G.964 */
enum v5x_mph_prim {
MPH_UBR, /* Unblock (req) */
MPH_UBI, /* Unblock (ind) */
MPH_BR, /* Block (req) */
MPH_BI, /* Block (ind) */
MPH_AR, /* Activate (req) */
MPH_AI, /* Activate (ind) */
MPH_AWI, /* Access activation by user (ind) */
MPH_DSAI, /* DS Activated (ind) */
MPH_DR, /* Deactivate (req) */
MPH_DI, /* Deactivate (ind) */
MPH_GI, /* Grading Information */
MPH_DB, /* Block D-Channel from user port */
MPH_DU, /* Unblock D-Channel from user port */
};
/* Table 3/G.964 */
enum v5x_fe_prim {
FE_establish_req = 0x00,
FE_establish_ack_ind = 0x03,
FE_establish_ind = 0x01,
FE_establish_ack_req = 0x02,
FE_line_signal_req = 0x10,
FE_line_signal_ind = 0x11,
FE_protocol_param_req = 0x20,
FE_disconnect_req = 0x30,
FE_disconnect_compl_req = 0x32,
FE_disconnect_compl_ind = 0x33,
};
/* Table 3/G.964 */
enum v5x_mgmt_prim {
MDU_CTRL_port_blocked,
MDU_CTRL_port_unblocked,
MDU_CTRL_port_restart_req,
MDU_CTRL_port_restart_ack,
MDU_CTRL_port_restart_compl,
MDU_error_ind,
};
struct osmo_fsm_inst;
@ -57,6 +100,7 @@ struct v5x_c_channel {
struct v5x_timeslot {
uint8_t nr;
struct v5x_link *link; /* back-pointer */
struct v5x_user_port *v5up; /* user port that this TS is assigned to */
uint16_t l3_address;
};
@ -81,10 +125,10 @@ struct v5x_interface {
/* 1..16 links in one interface */
struct v5x_link links[16];
struct osmo_fsm_inst *fi; /* Interface FSM instance */
struct {
struct v5x_ctrl_proto *ctrl; /* common control protocol instance */
struct lapv5_instance *li; /* Control data link */
bool established; /* track if link is up or down */
struct v5x_c_channel *c_chan; /* pointer to active C-channel */
} control;
struct {
@ -116,20 +160,39 @@ struct v5x_ctrl_proto {
struct msgb *tx_msg; /* copy of unacked message, for second try */
};
struct v5x_pstn_proto {
struct v5x_user_port *v5up; /* back pointer, if port control is used */
struct osmo_fsm_inst *fi; /* control FSM */
uint8_t S_s, S_a, S_r; /* sequence numbers */
struct msgb *tx_msg; /* copy of unacked message, for repitition */
int timeout_event; /* event when timer times out */
int timeout_count; /* how many times the timer was started/timed out */
struct osmo_timer_list timer_Tr; /* extra timer for receive sequence ack */
struct osmo_timer_list timer_Tt; /* extra timer for transmit sequence ack */
};
/* one user-facing port (subscriber line) */
struct v5x_user_port {
struct llist_head list; /* part of v5x_instance.ports */
struct v5x_interface *inst; /* back-pointer to instance we're part of */
uint16_t nr; /* port-number in decoded form (0..32767) */
char ifname[64]; /* name of interface, also used for PH-socket */
enum v5x_user_type type; /* type of port (ISDN/PSTN) */
struct v5x_ctrl_proto *ctrl; /* port control protocol instance */
struct osmo_fsm_inst *port_fi; /* port FSM */
uint8_t ts_nr[2]; /* time slots used (one for PSTN, two for ISDN) */
uint8_t link_nr[2]; /* link used */
uint8_t ts_activated[2]; /* set if data stream is active */
struct {
} isdn;
struct {
struct v5x_pstn_proto *proto;
} pstn;
ph_socket_t ph_socket; /* unix socket to connect port to */
bool le_unblocked; /* if port is not blocked by LE */
bool an_unblocked; /* if port is not blocked by AN */
};
struct v5x_instance {
@ -140,5 +203,7 @@ struct v5x_instance {
struct v5x_instance *v5x_instance_alloc(void *ctx);
struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect,
uint32_t id, uint8_t variant, int (*ph_data_req_cb)(struct msgb *msg, void *cbdata));
struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t nr, enum v5x_user_type);
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr);
struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t nr, enum v5x_user_type, uint8_t ts1, uint8_t ts2);
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr, bool is_isdn);
void v5x_user_port_destroy(struct v5x_user_port *v5up);
int v5x_vty_init(void);