Link structure of e1inp_line directly with V5 link

This way there is no lookup required, to get e1inp_line from v5
link and vice versa.

The E1 line is configured whenever it is added to the V5 link. This
happens when entering it in the VTY or loading the config. Also the
signaling channel is opened.

If E1 line is removed from the V5 link, all channels are closed.
This commit is contained in:
Andreas Eversberg 2023-02-12 16:16:25 +01:00
parent fdcce2bb7f
commit 86b7060848
6 changed files with 117 additions and 123 deletions

View File

@ -1,7 +1,6 @@
#include <stdio.h>
#include <errno.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/core/gsmtap.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/signal.h>
@ -28,39 +27,20 @@ static struct gsmtap_inst *g_gti = NULL;
#define GSMTAP_E1T1_V5EF 0x06
#endif
static inline struct e1inp_line *e1_line_from_link(struct v5x_link *v5l)
{
struct e1inp_line *e1_line;
if (v5l->e1_line < 0)
return NULL;
e1_line = e1inp_line_find(v5l->e1_line);
if (!e1_line)
return NULL;
return e1_line;
}
/* Callback function to receive L1 signal from E1 port */
static int inp_sig_cb(unsigned int subsys, unsigned int signal, void __attribute__((unused)) *handler_data,
void *signal_data)
{
struct input_signal_data *isd = signal_data;
struct v5x_interface *v5if;
struct v5x_link *v5l;
if (subsys != SS_L_INPUT)
return 0;
/* no interface */
if (llist_empty(&v5i->interfaces))
return 0;
v5if = llist_first_entry(&v5i->interfaces, struct v5x_interface, list);
/* not used by any link */
v5l = v5x_link_find_e1_line(v5if, isd->line->num);
if (!v5l)
if (!isd->line->ops)
return 0;
v5l = container_of(isd->line->ops, struct v5x_link, e1_line_ops);
switch (signal) {
case S_L_INP_LINE_LOS:
@ -112,12 +92,9 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal, void __attribute
/* Send L1 signal to E1 port */
int v5x_l1_signal_snd(struct v5x_link *v5l, enum l1_signal_prim prim)
{
struct e1inp_line *e1_line;
struct e1inp_line *e1_line = v5l->e1_line;
/* no line assigned */
if (v5l->e1_line < 0)
return 0;
e1_line = e1inp_line_find(v5l->e1_line);
if (!e1_line)
return 0;
@ -201,22 +178,14 @@ static void echo_rx(struct v5x_echo_proc *ep, uint8_t *data, int len)
/* data L1 -> L2 from E1 interface */
static void hdlc_rx_cb(struct e1inp_ts *ts, struct msgb *msg)
{
struct v5x_interface *v5if;
struct v5x_link *v5l;
/* no interface */
if (llist_empty(&v5i->interfaces)) {
msgb_free(msg);
return;
}
v5if = llist_first_entry(&v5i->interfaces, struct v5x_interface, list);
/* not used by any link */
v5l = v5x_link_find_e1_line(v5if, ts->line->num);
if (!v5l) {
if (!ts->line->ops) {
msgb_free(msg);
return;
}
v5l = container_of(ts->line->ops, struct v5x_link, e1_line_ops);
LOGP(DLINP, LOGL_DEBUG, "Link %d L1->L2: %s\n", v5l->id, msgb_hexdump(msg));
@ -232,23 +201,15 @@ static void hdlc_rx_cb(struct e1inp_ts *ts, struct msgb *msg)
/* data B-channel data from E1 interface */
static void raw_rx_cb(struct e1inp_ts *ts, struct msgb *msg)
{
struct v5x_interface *v5if;
struct v5x_link *v5l;
struct v5x_user_port *v5up;
/* no interface */
if (llist_empty(&v5i->interfaces)) {
msgb_free(msg);
return;
}
v5if = llist_first_entry(&v5i->interfaces, struct v5x_interface, list);
/* not used by any link */
v5l = v5x_link_find_e1_line(v5if, ts->line->num);
if (!v5l) {
if (!ts->line->ops) {
msgb_free(msg);
return;
}
v5l = container_of(ts->line->ops, struct v5x_link, e1_line_ops);
v5up = v5l->ts[ts->num].v5up;
/* not used by any user port */
@ -275,8 +236,8 @@ static void raw_rx_cb(struct e1inp_ts *ts, struct msgb *msg)
/* send HDLC frame to signaling channel (from ISDN) */
int ph_data_req_hdlc(struct msgb *msg, struct v5x_interface *v5if)
{
struct e1inp_line *e1_line;
e1_line = e1_line_from_link(v5if->cc_link);
struct e1inp_line *e1_line = v5if->cc_link->e1_line;
if (!e1_line) {
msgb_free(msg);
return 0;
@ -299,9 +260,8 @@ int ph_data_req_hdlc(struct msgb *msg, struct v5x_interface *v5if)
int ph_data_req_dl_cc(struct msgb *msg, void *cbdata)
{
struct v5x_interface *v5if = (struct v5x_interface *)cbdata;
struct e1inp_line *e1_line;
struct e1inp_line *e1_line = v5if->cc_link->e1_line;
e1_line = e1_line_from_link(v5if->cc_link);
if (!e1_line) {
msgb_free(msg);
return 0;
@ -329,9 +289,8 @@ int ph_data_req_dl_cc(struct msgb *msg, void *cbdata)
int ph_data_req_dl_prot(struct msgb *msg, void *cbdata)
{
struct v5x_link *v5l = (struct v5x_link *)cbdata;
struct e1inp_line *e1_line;
struct e1inp_line *e1_line = v5l->e1_line;
e1_line = e1_line_from_link(v5l);
if (!e1_line) {
msgb_free(msg);
return 0;
@ -357,14 +316,13 @@ int ph_data_req_dl_prot(struct msgb *msg, void *cbdata)
int ph_activate_req(struct v5x_timeslot *ts)
{
struct e1inp_line *e1_line;
struct e1inp_line *e1_line = ts->link->e1_line;
struct e1inp_ts *e1_ts;
int rc;
if (ts->b_activated)
return 0;
e1_line = e1_line_from_link(ts->link);
if (!e1_line)
return -EINVAL;
e1_ts = &e1_line->ts[ts->nr - 1];
@ -379,14 +337,13 @@ int ph_activate_req(struct v5x_timeslot *ts)
int ph_deactivate_req(struct v5x_timeslot *ts)
{
struct e1inp_line *e1_line;
struct e1inp_line *e1_line = ts->link->e1_line;
struct e1inp_ts *e1_ts;
int rc;
if (!ts->b_activated)
return 0;
e1_line = e1_line_from_link(ts->link);
if (!e1_line)
return -EINVAL;
e1_ts = &e1_line->ts[ts->nr - 1];
@ -402,10 +359,9 @@ int ph_deactivate_req(struct v5x_timeslot *ts)
/* send raw (B-channel) data to E1 interface */
static int ph_data_req_raw(struct v5x_link *v5l, struct msgb *msg, int ts_nr)
{
struct e1inp_line *e1_line;
struct e1inp_line *e1_line = v5l->e1_line;
/* no line assigned */
e1_line = e1_line_from_link(v5l);
if (!e1_line) {
msgb_free(msg);
return 0;
@ -480,18 +436,9 @@ static int v5le_rx_sign(struct msgb *msg)
return 0;
}
static const struct e1inp_line_ops v5le_e1_line_ops = {
.sign_link_up = NULL,
.sign_link_down = NULL,
.sign_link = v5le_rx_sign,
};
/* init all E1 lines and register input signals */
int e1_init(void)
/* init gsmtap */
int gsmtap_init(void)
{
struct e1inp_line *e1_line;
int i, ts;
if (gsmtap_ip) {
g_gti = gsmtap_source_init(gsmtap_ip, GSMTAP_UDP_PORT, 0);
if (!g_gti) {
@ -501,28 +448,65 @@ int e1_init(void)
gsmtap_source_add_sink(g_gti);
}
for (i = 0; i < 256; i++) {
e1_line = e1inp_line_find(i);
if (!e1_line)
continue;
e1inp_line_bind_ops(e1_line, &v5le_e1_line_ops);
for (ts = 1; ts <= 31; ts++) {
struct e1inp_ts *e1_ts = &e1_line->ts[ts-1];
if (ts == 16) { // FIXME: make this depending on c_channel
//e1inp_ts_config_sign(e1_ts, e1_line);
//e1inp_sign_link_create(e1_ts, E1INP_SIGN_NONE, NULL, 115/*TEI*/, 0/*SAPI*/);
e1inp_ts_config_hdlc(e1_ts, e1_line, hdlc_rx_cb);
} else
e1_ts->type = E1INP_TS_TYPE_NONE;
}
e1inp_line_update(e1_line);
}
return 0;
}
/* register signal to receive E1 events */
int l1_signal_init(void)
{
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
return 0;
}
/* init given E1 line and return e1inp_line structure pointer */
struct e1inp_line *e1_line_init(struct v5x_link *v5l, int e1_nr)
{
struct e1inp_line *e1_line;
int ts;
int rc;
e1_line = e1inp_line_find(e1_nr);
if (!e1_line)
return NULL;
/* link e1inp_line to v5l and vice versa */
/* must set ops before setting TS */
v5l->e1_line_ops.sign_link = v5le_rx_sign;
e1inp_line_bind_ops(e1_line, &v5l->e1_line_ops);
v5l->e1_line = e1_line;
for (ts = 1; ts <= 31; ts++) {
struct e1inp_ts *e1_ts = &e1_line->ts[ts-1];
if (ts == 16) { // FIXME: make this depending on c_channel
//e1inp_ts_config_sign(e1_ts, e1_line);
//e1inp_sign_link_create(e1_ts, E1INP_SIGN_NONE, NULL, 115/*TEI*/, 0/*SAPI*/);
e1inp_ts_config_hdlc(e1_ts, e1_line, hdlc_rx_cb);
} else
e1_ts->type = E1INP_TS_TYPE_NONE;
}
/* if config fails, remove link between e1inp_line and v5l */
rc = e1inp_line_update(e1_line);
if (rc < 0) {
e1_line_exit(v5l);
return NULL;
}
return e1_line;
}
void e1_line_exit(struct v5x_link *v5l)
{
struct e1inp_line *e1_line = v5l->e1_line;
int ts;
for (ts = 1; ts <= 31; ts++) {
struct e1inp_ts *e1_ts = &e1_line->ts[ts-1];
e1_ts->type = E1INP_TS_TYPE_NONE;
}
e1inp_line_update(e1_line);
e1inp_line_bind_ops(e1_line, NULL);
v5l->e1_line = NULL;
}

View File

@ -17,4 +17,7 @@ int ph_data_req_hdlc(struct msgb *msg, struct v5x_interface *v5if);
int ph_data_req_dl_cc(struct msgb *msg, void *cbdata);
int ph_data_req_dl_prot(struct msgb *msg, void *cbdata);
void ph_socket_rx_cb(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data, int length);
int e1_init(void);
int gsmtap_init(void);
int l1_signal_init(void);
struct e1inp_line *e1_line_init(struct v5x_link *v5l, int e1_nr);
void e1_line_exit(struct v5x_link *v5l);

View File

@ -46,8 +46,6 @@
#include <osmocom/vty/misc.h>
#include <osmocom/vty/cpu_sched_vty.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/abis/abis.h>
#include "v5x_internal.h"
@ -259,7 +257,11 @@ int main(int argc, char **argv)
return rc;
}
rc = e1_init();
rc = gsmtap_init();
if (rc < 0)
return rc;
rc = l1_signal_init();
if (rc < 0)
return rc;

View File

@ -1,6 +1,5 @@
#include <osmocom/vty/command.h>
#include <osmocom/abis/e1_input.h>
#include "v5x_internal.h"
#include "v5x_protocol.h"
@ -10,6 +9,7 @@
#include "v5x_le_port_fsm.h"
#include "v5x_le_pstn_fsm.h"
#include "v5x_le_management.h"
#include "layer1.h"
#include "../config.h"
extern struct v5x_instance *v5i;
@ -501,24 +501,34 @@ DEFUN(cfg_e1_line, cfg_e1_line_cmd,
"E1 configuration\n" "E1 line configuration\n" "E1 line number to use for link")
{
struct v5x_link *v5l = vty->index, *search_v5l;
struct e1inp_line *e1l;
int e1_line = atoi(argv[0]);
struct e1inp_line *e1_line;
unsigned int num = atoi(argv[0]);
/* nothing has changed, same line number */
if (v5l->e1_line && v5l->e1_line->num == num)
return CMD_SUCCESS;
/* is there someone using this line number already? only can happen with multi-link (V5.2) */
llist_for_each_entry(search_v5l, &v5l->interface->links, list) {
if (search_v5l->e1_line < 0)
if (!search_v5l->e1_line)
continue;
if (search_v5l->e1_line == e1_line) {
vty_out(vty, "%%E1 line %d already used by another link ID %d.%s", e1_line, search_v5l->id,
VTY_NEWLINE);
if (search_v5l->e1_line->num == num) {
vty_out(vty, "%%E1 line %d already used by link ID %d.%s", num, search_v5l->id, VTY_NEWLINE);
return CMD_WARNING;
}
}
v5l->e1_line = e1_line;
e1l = e1inp_line_find(e1_line);
if (!e1l)
vty_out(vty, "%%E1 line %d is not created. Create it and restart application.%s", e1_line,
VTY_NEWLINE);
/* remove line, if attached */
if (v5l->e1_line)
e1_line_exit(v5l);
/* add line, if created */
e1_line = e1_line_init(v5l, num);
if (!e1_line) {
vty_out(vty, "%%E1 line %d is not created. Please create it first.%s", num, VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
@ -528,7 +538,10 @@ DEFUN(cfg_no_e1_line, cfg_no_e1_line_cmd,
{
struct v5x_link *v5l = vty->index;
v5l->e1_line = -1;
/* remove line, if attached */
if (v5l->e1_line)
e1_line_exit(v5l);
return CMD_SUCCESS;
}
@ -734,10 +747,10 @@ static int config_write_interface_v51(struct vty *vty)
vty_out(vty, " id %d%s", v5if->id_local, VTY_NEWLINE);
vty_out(vty, " variant %d%s", v5if->variant_local, VTY_NEWLINE);
vty_out(vty, " link%s", VTY_NEWLINE);
if (v5l->e1_line < 0)
if (!v5l->e1_line)
vty_out(vty, " no e1 line%s", VTY_NEWLINE);
else
vty_out(vty, " e1 line %d%s", v5l->e1_line, VTY_NEWLINE);
vty_out(vty, " e1 line %d%s", v5l->e1_line->num, VTY_NEWLINE);
config_write_user_port(vty, v5if);
}
return CMD_SUCCESS;
@ -767,10 +780,10 @@ static int config_write_interface_v52(struct vty *vty)
vty_out(vty, " # primary%s", VTY_NEWLINE);
if (v5l == v5if->secondary_link)
vty_out(vty, " # secondary%s", VTY_NEWLINE);
if (v5l->e1_line < 0)
if (!v5l->e1_line)
vty_out(vty, " no e1 line%s", VTY_NEWLINE);
else
vty_out(vty, " e1 line %d%s", v5l->e1_line, VTY_NEWLINE);
vty_out(vty, " e1 line %d%s", v5l->e1_line->num, VTY_NEWLINE);
}
config_write_user_port(vty, v5if);
}

View File

@ -84,7 +84,6 @@ struct v5x_link *v5x_link_create(struct v5x_interface *v5if, uint8_t id)
v5l->id = id;
v5l->interface = v5if;
v5l->e1_line = -1;
/* primary and secondary link will get TS 16 */
if (count <= 2) {
@ -191,6 +190,9 @@ int v5x_link_destroy(struct v5x_link *v5l)
if (v5l->interface->cc_link == v5l)
v5l->interface->cc_link = NULL;
if (v5l->e1_line)
e1_line_exit(v5l);
llist_del(&v5l->list);
count--;
@ -525,14 +527,3 @@ struct v5x_link *v5x_link_find_id(struct v5x_interface *v5if, uint8_t id)
}
return NULL;
}
struct v5x_link *v5x_link_find_e1_line(struct v5x_interface *v5if, uint8_t e1_line)
{
struct v5x_link *v5l;
llist_for_each_entry(v5l, &v5if->links, list) {
if (v5l->e1_line == e1_line)
return v5l;
}
return NULL;
}

View File

@ -30,6 +30,7 @@
#include <osmocom/core/fsm.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/lapd_core.h>
#include <osmocom/abis/e1_input.h>
#include "libecho/echo.h"
#include "libecho/answertone.h"
@ -185,7 +186,8 @@ struct v5x_link {
struct v5x_l1_proto *l1; /* Layer 1 Link FSM protocol */
struct v5x_ctrl_proto *ctrl; /* Link control protocol instance */
struct osmo_fsm_inst *fi; /* Link Control FSM instance */
int e1_line; /* E1 line to use or -1 if not */
struct e1inp_line *e1_line; /* E1 line to use or NULL if not */
struct e1inp_line_ops e1_line_ops; /* use e1pinp_line->ops to point back to v5x_link */
};
/* one V5.x interface between AN (Access Network) and LE (Local Exchange) */
@ -350,4 +352,3 @@ struct v5x_link *v5x_link_create(struct v5x_interface *v5if, uint8_t id);
int v5x_link_destroy(struct v5x_link *v5l);
int v5x_link_count(struct v5x_interface *v5if);
struct v5x_link *v5x_link_find_id(struct v5x_interface *v5if, uint8_t id);
struct v5x_link *v5x_link_find_e1_line(struct v5x_interface *v5if, uint8_t id);