Work on v5x_data.c and v5x_internal.h
This commit is contained in:
parent
be536b9029
commit
11c87bdea7
394
src/v5x_data.c
394
src/v5x_data.c
|
@ -1,3 +1,4 @@
|
|||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
|
@ -6,9 +7,14 @@
|
|||
#include "v5x_internal.h"
|
||||
#include "v5x_protocol.h"
|
||||
#include "lapv5.h"
|
||||
#include "layer1.h"
|
||||
#include "v5x_l1_fsm.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"
|
||||
|
||||
|
@ -27,11 +33,25 @@ struct v5x_instance *v5x_instance_alloc(void *ctx)
|
|||
return v5i;
|
||||
}
|
||||
|
||||
static void v5x_ts_init(struct v5x_timeslot *v5ts, uint8_t nr, struct v5x_link *v5l, uint16_t l3_addr)
|
||||
void v5x_instance_free(struct v5x_instance *v5i)
|
||||
{
|
||||
struct v5x_interface *v5if, *v5if2;
|
||||
|
||||
llist_for_each_entry_safe(v5if, v5if2, &v5i->interfaces, list)
|
||||
v5x_interface_free(v5if);
|
||||
|
||||
talloc_free(v5i);
|
||||
}
|
||||
|
||||
static void v5x_ts_init(struct v5x_timeslot *v5ts, uint8_t nr, struct v5x_link *v5l, bool b_channel)
|
||||
{
|
||||
/* Never use slot 16 as B-channel, because some drivers (mISDN) will not allow this. */
|
||||
if (nr == 16)
|
||||
b_channel = false;
|
||||
|
||||
v5ts->nr = nr;
|
||||
v5ts->link = v5l;
|
||||
v5ts->l3_address = l3_addr;
|
||||
v5ts->b_channel = b_channel;
|
||||
}
|
||||
|
||||
static void v5x_cchan_init(struct v5x_c_channel *v5cc, struct v5x_link *v5l, struct v5x_timeslot *v5ts, bool active)
|
||||
|
@ -41,80 +61,242 @@ static void v5x_cchan_init(struct v5x_c_channel *v5cc, struct v5x_link *v5l, str
|
|||
v5cc->active = active;
|
||||
}
|
||||
|
||||
static void v5x_link_init(struct v5x_link *v5l, struct v5x_interface *v5if, uint8_t id)
|
||||
struct v5x_link *v5x_link_create(struct v5x_interface *v5if, uint8_t id)
|
||||
{
|
||||
int count;
|
||||
struct v5x_link *v5l;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
if (v5x_link_find_id(v5if, id)) {
|
||||
LOGP(DV5, LOGL_ERROR, "Link %d already exists.\n", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = v5x_link_count(v5if);
|
||||
|
||||
v5l = talloc_zero(v5if, struct v5x_link);
|
||||
if (!v5l)
|
||||
return NULL;
|
||||
|
||||
llist_add_tail(&v5l->list, &v5if->links);
|
||||
count++;
|
||||
|
||||
v5l->id = id;
|
||||
v5l->interface = v5if;
|
||||
v5l->e1_line = -1;
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(v5l->ts); i++) {
|
||||
v5x_ts_init(&v5l->ts[i], i, v5l, 0 /*l3_addr*/);
|
||||
/* primary and secondary link will get TS 16 */
|
||||
if (count <= 2) {
|
||||
v5x_cchan_init(&v5l->c_channel[0], v5l, &v5l->ts[16], true);
|
||||
}
|
||||
|
||||
/* primary c-channel must always be present */
|
||||
v5x_cchan_init(&v5l->c_channel[0], v5l, &v5l->ts[16], true);
|
||||
for (i = 1; i < ARRAY_SIZE(v5l->ts); i++) {
|
||||
bool b_channel = true;
|
||||
if (v5l->c_channel[0].ts && v5l->c_channel[0].ts->nr == i)
|
||||
b_channel = false;
|
||||
if (v5l->c_channel[1].ts && v5l->c_channel[1].ts->nr == i)
|
||||
b_channel = false;
|
||||
if (v5l->c_channel[2].ts && v5l->c_channel[2].ts->nr == i)
|
||||
b_channel = false;
|
||||
v5x_ts_init(&v5l->ts[i], i, v5l, b_channel);
|
||||
}
|
||||
|
||||
v5l->l1 = v5x_l1_fsm_create(v5if, v5l, id);
|
||||
if (!v5l->l1)
|
||||
goto error;
|
||||
|
||||
if (v5if->dialect == V5X_DIALECT_V52) {
|
||||
v5l->fi = v52_le_lcp_create(v5if, v5l, id);
|
||||
if (!v5l->fi)
|
||||
goto error;
|
||||
|
||||
v5l->ctrl = v5x_le_ctrl_create(V5X_CTRL_TYPE_LINK, v5if, v5l, id);
|
||||
if (!v5l->ctrl)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
v5if->primary_link = v5l;
|
||||
v5if->cc_link = v5l;
|
||||
}
|
||||
if (count == 2) {
|
||||
v5if->secondary_link = v5l;
|
||||
/* add PP */
|
||||
v5if->protection.pp = v52_le_pp_create(v5if);
|
||||
if (!v5if->protection.pp)
|
||||
goto error;
|
||||
v5if->protection.li[0] = lapv5_instance_alloc(1, &ph_data_req_dl_prot, v5if->primary_link, v5x_dl_rcv,
|
||||
v5if->primary_link, &lapd_profile_lapv5dl, "protection0");
|
||||
if (!v5if->protection.li[0])
|
||||
goto error;
|
||||
v5if->protection.li[1] = lapv5_instance_alloc(1, &ph_data_req_dl_prot, v5if->secondary_link, v5x_dl_rcv,
|
||||
v5if->secondary_link, &lapd_profile_lapv5dl, "protection1");
|
||||
if (!v5if->protection.li[1])
|
||||
goto error;
|
||||
}
|
||||
|
||||
return v5l;
|
||||
|
||||
error:
|
||||
rc = v5x_link_destroy(v5l);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect,
|
||||
int (*ph_data_req_cb)(struct msgb *msg, void *cbdata))
|
||||
int v5x_link_destroy(struct v5x_link *v5l)
|
||||
{
|
||||
struct v5x_interface *v5if = talloc_zero(v5i, struct v5x_interface);
|
||||
//struct v5x_link *v5l;
|
||||
struct v5x_c_channel *primary_c_chan;
|
||||
struct v5x_interface *v5if = v5l->interface;
|
||||
int count;
|
||||
struct v5x_user_port *v5up;
|
||||
int i;
|
||||
|
||||
count = v5x_link_count(v5l->interface);
|
||||
if (count > 1 && v5l->interface->primary_link == v5l) {
|
||||
LOGP(DV5, LOGL_ERROR, "Link %d is primary. Cannot remove it, while other links exist.\n", v5l->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (count > 2 && v5l->interface->secondary_link == v5l) {
|
||||
LOGP(DV5, LOGL_ERROR, "Link %d is secondary (standby). Cannot remove it, while other (not primary) links exist.\n", v5l->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* detach user ports */
|
||||
for (i = 1; i < (int)ARRAY_SIZE(v5l->ts); i++) {
|
||||
if ((v5up = v5l->ts[i].v5up)) {
|
||||
if (v5up->ts[0] == &v5l->ts[i]) {
|
||||
v5up->ts[0] = NULL;
|
||||
v5up->ts_activated[0] = 0;
|
||||
}
|
||||
if (v5up->ts[1] == &v5l->ts[i]) {
|
||||
v5up->ts[1] = NULL;
|
||||
v5up->ts_activated[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (v5l->ctrl)
|
||||
v5x_le_ctrl_destroy(v5l->ctrl);
|
||||
|
||||
if (v5l->fi)
|
||||
v52_le_lcp_destroy(v5l->fi);
|
||||
|
||||
if (v5l->l1)
|
||||
v5x_l1_fsm_destroy(v5l->l1);
|
||||
|
||||
if (v5l->interface->primary_link == v5l)
|
||||
v5l->interface->primary_link = NULL;
|
||||
if (v5l->interface->secondary_link == v5l)
|
||||
v5l->interface->secondary_link = NULL;
|
||||
if (v5l->interface->cc_link == v5l)
|
||||
v5l->interface->cc_link = NULL;
|
||||
|
||||
llist_del(&v5l->list);
|
||||
count--;
|
||||
|
||||
talloc_free(v5l);
|
||||
|
||||
/* if we have only one link left */
|
||||
if (count == 1) {
|
||||
/* remove PP */
|
||||
if (v5if->protection.li[0]) {
|
||||
lapv5_instance_free(v5if->protection.li[0]);
|
||||
v5if->protection.li[0] = NULL;
|
||||
}
|
||||
if (v5if->protection.li[1]) {
|
||||
lapv5_instance_free(v5if->protection.li[1]);
|
||||
v5if->protection.li[1] = NULL;
|
||||
}
|
||||
if (v5if->protection.pp) {
|
||||
v52_le_pp_destroy(v5if->protection.pp);
|
||||
v5if->protection.pp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect)
|
||||
{
|
||||
struct v5x_interface *v5if;
|
||||
struct v5x_link *v5l;
|
||||
// struct v5x_c_channel *primary_c_chan;
|
||||
|
||||
v5if = talloc_zero(v5i, struct v5x_interface);
|
||||
if (!v5if)
|
||||
return NULL;
|
||||
|
||||
INIT_LLIST_HEAD(&v5if->links);
|
||||
INIT_LLIST_HEAD(&v5if->user_ports);
|
||||
INIT_LLIST_HEAD(&v5if->bcc_procs);
|
||||
|
||||
llist_add_tail(&v5if->list, &v5i->interfaces);
|
||||
|
||||
v5if->instance = v5i;
|
||||
v5if->dialect = dialect;
|
||||
|
||||
/* primary link must alwasy be present */
|
||||
v5x_link_init(&v5if->links[0], v5if, 0);
|
||||
v5if->primary_link = &v5if->links[0];
|
||||
|
||||
primary_c_chan = &v5if->primary_link->c_channel[0];
|
||||
|
||||
v5if->control.ctrl = v5x_le_ctrl_create(v5if, NULL, 0);
|
||||
if (!v5if->control.ctrl)
|
||||
return NULL;
|
||||
v5if->control.li = lapv5_instance_alloc(1, ph_data_req_cb, v5if, v5x_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "control");
|
||||
v5if->control.c_chan = primary_c_chan;
|
||||
|
||||
v5if->pstn.li = lapv5_instance_alloc(1, ph_data_req_cb, v5if, v5x_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "pstn");
|
||||
v5if->pstn.c_chan = primary_c_chan;
|
||||
|
||||
if (v5if->dialect == V5X_DIALECT_V52) {
|
||||
v5if->lcp.li = lapv5_instance_alloc(1, ph_data_req_cb, v5if, v5x_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "lcp");
|
||||
v5if->lcp.c_chan = primary_c_chan;
|
||||
|
||||
v5if->bcc.li = lapv5_instance_alloc(1, ph_data_req_cb, v5if, v5x_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "bcc");
|
||||
v5if->bcc.c_chan = primary_c_chan;
|
||||
|
||||
v5if->protection[0].li = lapv5_instance_alloc(1, ph_data_req_cb, v5if, v5x_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "protection0");
|
||||
v5if->protection[0].c_chan = primary_c_chan;
|
||||
|
||||
//protection[1] ?
|
||||
if (v5if->dialect == V5X_DIALECT_V51) {
|
||||
v5l = v5x_link_create(v5if, 0);
|
||||
if (!v5l)
|
||||
goto error;
|
||||
}
|
||||
|
||||
INIT_LLIST_HEAD(&v5if->user_ports);
|
||||
v5if->control.ctrl = v5x_le_ctrl_create(V5X_CTRL_TYPE_COMMON, v5if, v5if, 0);
|
||||
if (!v5if->control.ctrl)
|
||||
goto error;
|
||||
v5if->control.li = lapv5_instance_alloc(1, &ph_data_req_dl_cc, v5if, v5x_dl_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "control");
|
||||
if (!v5if->control.li)
|
||||
goto error;
|
||||
|
||||
llist_add_tail(&v5if->list, &v5i->interfaces);
|
||||
v5if->pstn.li = lapv5_instance_alloc(1, &ph_data_req_dl_cc, v5if, v5x_dl_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "pstn");
|
||||
if (!v5if->pstn.li)
|
||||
goto error;
|
||||
|
||||
if (v5if->dialect == V5X_DIALECT_V52) {
|
||||
v5if->lcp.li = lapv5_instance_alloc(1, &ph_data_req_dl_cc, v5if, v5x_dl_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "lcp");
|
||||
if (!v5if->lcp.li)
|
||||
goto error;
|
||||
|
||||
v5if->bcc.li = lapv5_instance_alloc(1, &ph_data_req_dl_cc, v5if, v5x_dl_rcv, v5if,
|
||||
&lapd_profile_lapv5dl, "bcc");
|
||||
if (!v5if->bcc.li)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return v5if;
|
||||
|
||||
error:
|
||||
v5x_interface_free(v5if);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void v5x_interface_free(struct v5x_interface *v5if) {
|
||||
struct v5x_user_port *v5up, *v5up2;
|
||||
struct v52_bcc_proc *bcc, *bcc2;
|
||||
struct v5x_link *v5l;
|
||||
int rc;
|
||||
|
||||
if (!v5if)
|
||||
return;
|
||||
|
||||
llist_for_each_entry_safe(v5up, v5up2, &v5if->user_ports, list)
|
||||
v5x_user_port_destroy(v5up);
|
||||
|
||||
llist_for_each_entry_safe(bcc, bcc2, &v5if->bcc_procs, list)
|
||||
v52_le_bcc_destroy(bcc);
|
||||
|
||||
/* delete reversed safely */
|
||||
while (!llist_empty(&v5if->links)) {
|
||||
v5l = llist_last_entry(&v5if->links, struct v5x_link, list);
|
||||
rc = v5x_link_destroy(v5l);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
if (v5if->control.ctrl)
|
||||
v5x_le_ctrl_destroy(v5if->control.ctrl);
|
||||
|
||||
if (v5if->control.li)
|
||||
lapv5_instance_free(v5if->control.li);
|
||||
|
||||
|
@ -127,11 +309,6 @@ void v5x_interface_free(struct v5x_interface *v5if) {
|
|||
if (v5if->bcc.li)
|
||||
lapv5_instance_free(v5if->bcc.li);
|
||||
|
||||
if (v5if->protection[0].li)
|
||||
lapv5_instance_free(v5if->protection[0].li);
|
||||
if (v5if->protection[1].li)
|
||||
lapv5_instance_free(v5if->protection[1].li);
|
||||
|
||||
llist_del(&v5if->list);
|
||||
|
||||
talloc_free(v5if);
|
||||
|
@ -143,15 +320,34 @@ struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t
|
|||
struct v5x_user_port *v5up;
|
||||
int rc;
|
||||
|
||||
if ((v5up = v5if->links[0].ts[ts1].v5up)) {
|
||||
LOGP(DV5, LOGL_ERROR, "Time slot %d is already assigned to another user port\n", ts1);
|
||||
if (v5x_user_port_find(v5if, nr, (type == V5X_USER_TYPE_ISDN))) {
|
||||
LOGP(DV5, LOGL_ERROR, "User port %d already exists.\n", nr);
|
||||
return NULL;
|
||||
}
|
||||
if (type == V5X_USER_TYPE_ISDN) {
|
||||
if ((v5up = v5if->links[0].ts[ts2].v5up)) {
|
||||
LOGP(DV5, LOGL_ERROR, "Time slot %d is already assigned to another user port\n", ts2);
|
||||
|
||||
if (v5if->dialect == V5X_DIALECT_V51) {
|
||||
struct v5x_link *v5l;
|
||||
|
||||
v5l = llist_first_entry(&v5if->links, struct v5x_link, list);
|
||||
if (!v5l->ts[ts1].b_channel) {
|
||||
LOGP(DV5, LOGL_ERROR, "Time slot %d is not a B-channel, select a different one.\n", ts1);
|
||||
return NULL;
|
||||
}
|
||||
if ((v5up = v5l->ts[ts1].v5up)) {
|
||||
LOGP(DV5, LOGL_ERROR, "Time slot %d is already assigned to another user port.\n", ts1);
|
||||
return NULL;
|
||||
}
|
||||
if (type == V5X_USER_TYPE_ISDN) {
|
||||
if (!v5l->ts[ts2].b_channel) {
|
||||
LOGP(DV5, LOGL_ERROR, "Time slot %d is not a B-channel, select a different one.\n",
|
||||
ts2);
|
||||
return NULL;
|
||||
}
|
||||
if ((v5up = v5l->ts[ts2].v5up)) {
|
||||
LOGP(DV5, LOGL_ERROR, "Time slot %d is already assigned to another user port.\n", ts2);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v5up = talloc_zero(v5if, struct v5x_user_port);
|
||||
|
@ -160,27 +356,29 @@ struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t
|
|||
|
||||
llist_add_tail(&v5up->list, &v5if->user_ports);
|
||||
|
||||
v5up->inst = v5if;
|
||||
v5up->interface = v5if;
|
||||
v5up->nr = nr;
|
||||
v5up->type = type;
|
||||
|
||||
/* assign ports */
|
||||
if (v5if->dialect == V5X_DIALECT_V51) {
|
||||
struct v5x_link *v5l;
|
||||
|
||||
v5l = llist_first_entry(&v5if->links, struct v5x_link, list);
|
||||
OSMO_ASSERT(ts1 >= 1 && ts1 <= 31);
|
||||
v5if->links[0].ts[ts1].v5up = v5up;
|
||||
v5up->ts_nr[0] = ts1;
|
||||
v5l->ts[ts1].v5up = v5up;
|
||||
v5up->ts[0] = &v5l->ts[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;
|
||||
v5l->ts[ts2].v5up = v5up;
|
||||
v5up->ts[1] = &v5l->ts[ts2];
|
||||
}
|
||||
}
|
||||
|
||||
v5up->ctrl = v5x_le_ctrl_create(NULL, v5up, nr);
|
||||
v5up->ctrl = v5x_le_ctrl_create(V5X_CTRL_TYPE_PORT, v5up, v5up, nr);
|
||||
if (!v5up->ctrl) {
|
||||
LOGP(DV5, LOGL_ERROR, "Failed to create control protocol\n");
|
||||
v5x_user_port_destroy(v5up);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
@ -191,8 +389,7 @@ struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t
|
|||
v5up->port_fi = v5x_le_port_isdn_create(v5up, nr);
|
||||
if (!v5up->port_fi) {
|
||||
LOGP(DV5, LOGL_ERROR, "Failed to create port control\n");
|
||||
v5x_user_port_destroy(v5up);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case V5X_USER_TYPE_PSTN:
|
||||
|
@ -202,14 +399,12 @@ struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t
|
|||
v5up->port_fi = v5x_le_port_pstn_create(v5up, nr);
|
||||
if (!v5up->port_fi) {
|
||||
LOGP(DV5, LOGL_ERROR, "Failed to create port control\n");
|
||||
v5x_user_port_destroy(v5up);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
v5up->pstn.proto = v5x_le_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;
|
||||
goto error;
|
||||
}
|
||||
/* bring port into service */
|
||||
v5x_le_pstn_mdu_snd(v5up, MDU_CTRL_port_blocked);
|
||||
|
@ -219,27 +414,36 @@ struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t
|
|||
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;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* start ctrl FSM for this port */
|
||||
if (v5if->control.established)
|
||||
v5x_le_ctrl_start(v5up->ctrl);
|
||||
|
||||
return v5up;
|
||||
|
||||
error:
|
||||
v5x_user_port_destroy(v5up);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void v5x_user_port_destroy(struct v5x_user_port *v5up)
|
||||
{
|
||||
struct v5x_interface *v5if = v5up->inst;
|
||||
|
||||
LOGP(DV5, LOGL_NOTICE, "Destroying V5 user port with L3 addr %d\n", v5up->nr);
|
||||
|
||||
/* close fitst, because it sends messages */
|
||||
/* close first, because it sends messages */
|
||||
ph_socket_exit(&v5up->ph_socket);
|
||||
|
||||
/* 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->ts[0]) {
|
||||
v5up->ts[0]->v5up = NULL;
|
||||
v5up->ts[0] = NULL;
|
||||
}
|
||||
if (v5up->ts[1]) {
|
||||
v5up->ts[1]->v5up = NULL;
|
||||
v5up->ts[1] = NULL;
|
||||
}
|
||||
|
||||
if (v5up->ctrl)
|
||||
v5x_le_ctrl_destroy(v5up->ctrl);
|
||||
|
@ -265,3 +469,35 @@ struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int v5x_link_count(struct v5x_interface *v5if)
|
||||
{
|
||||
struct v5x_link *v5l;
|
||||
int count = 0;
|
||||
|
||||
llist_for_each_entry(v5l, &v5if->links, list)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
struct v5x_link *v5x_link_find_id(struct v5x_interface *v5if, uint8_t id)
|
||||
{
|
||||
struct v5x_link *v5l;
|
||||
|
||||
llist_for_each_entry(v5l, &v5if->links, list) {
|
||||
if (v5l->id == id)
|
||||
return v5l;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,21 @@ enum v5x_mph_prim {
|
|||
MPH_GI, /* Grading Information */
|
||||
MPH_DB, /* Block D-Channel from user port */
|
||||
MPH_DU, /* Unblock D-Channel from user port */
|
||||
MPH_ID, /* Identity Sa7=0 signal request (TX) */
|
||||
MPH_NOR, /* Normal Sa7=1 signal request (TX) */
|
||||
MPH_IDR, /* Request Sa7 signal (RX) */
|
||||
MPH_IDI, /* Indicate Sa7=0 signal (RX) */
|
||||
MPH_EIg, /* Indicate Sa7=1 singal (RX) */
|
||||
MPH_EIa, /* Indicate LOS */
|
||||
MPH_EIb, /* RAI */
|
||||
MPH_EIc, /* AIS */
|
||||
MPH_EId, /* Internal failure */
|
||||
MPH_EIe, /* CRC received */
|
||||
MPH_EIf, /* E-bit received */
|
||||
MPH_stop, /* See L1 FSM */
|
||||
MPH_proceed, /* See L1 FSM */
|
||||
MPH_EIbr, /* See L1 FSM */
|
||||
MPH_EIdr, /* See L1 FSM */
|
||||
};
|
||||
|
||||
/* Table 3/G.964 */
|
||||
|
@ -64,14 +79,56 @@ enum v5x_fe_prim {
|
|||
FE_disconnect_compl_ind = 0x33,
|
||||
};
|
||||
|
||||
/* Table 3/G.964 */
|
||||
enum v5x_mgmt_prim {
|
||||
/* Table 3/G.964 */
|
||||
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,
|
||||
/* Table 14/G.965 */
|
||||
MDU_AI,
|
||||
MDU_DI,
|
||||
MDU_LAI,
|
||||
MDU_IDReq,
|
||||
MDU_IDAck,
|
||||
MDU_IDRel,
|
||||
MDU_IDRej,
|
||||
MDU_EIg,
|
||||
MDU_LUBR,
|
||||
MDU_LUBI,
|
||||
MDU_LBI,
|
||||
MDU_LBR,
|
||||
MDU_LBRN,
|
||||
/* Table 26/G.965 */
|
||||
MDU_BCC_allocation_req,
|
||||
MDU_BCC_allocation_conf,
|
||||
MDU_BCC_allocation_reject_ind,
|
||||
MDU_BCC_allocation_error_ind,
|
||||
MDU_BCC_deallocation_req,
|
||||
MDU_BCC_deallocation_conf,
|
||||
MDU_BCC_deallocation_reject_ind,
|
||||
MDU_BCC_deallocation_error_ind,
|
||||
MDU_BCC_audit_req,
|
||||
MDU_BCC_audit_conf,
|
||||
MDU_BCC_audit_error_ind,
|
||||
MDU_BCC_AN_fault_ind,
|
||||
MDU_BCC_protocol_error_ind,
|
||||
/* Table 50/G.965 */
|
||||
MDU_Protection_switch_over_com,
|
||||
MDU_Protection_OS_switch_over_com,
|
||||
MDU_Protection_switch_over_ack,
|
||||
MDU_Protection_switch_over_rej,
|
||||
MDU_Protection_switch_over_req,
|
||||
MDU_Protection_switch_over_reject_ind,
|
||||
MDU_Protection_switch_over_error_ind,
|
||||
MDU_Protection_reset_SN_ind,
|
||||
MDU_Protection_reset_SN_com,
|
||||
MDU_Protection_reset_SN_req,
|
||||
MDU_Protection_reset_SN_ack,
|
||||
MDU_Protection_reset_SN_error_ind,
|
||||
MDU_Protection_protocol_error_ind,
|
||||
};
|
||||
|
||||
struct osmo_fsm_inst;
|
||||
|
@ -86,11 +143,19 @@ enum v5x_user_type {
|
|||
V5X_USER_TYPE_PSTN = 2,
|
||||
};
|
||||
|
||||
enum v5x_ctrl_type {
|
||||
V5X_CTRL_TYPE_COMMON = 1,
|
||||
V5X_CTRL_TYPE_PORT = 2,
|
||||
V5X_CTRL_TYPE_LINK = 3,
|
||||
};
|
||||
|
||||
/* forward-declarations */
|
||||
struct v5x_interface;
|
||||
struct v5x_instance;
|
||||
struct v5x_user_port;
|
||||
struct v5x_link;
|
||||
struct v5x_l1_proto;
|
||||
struct v52_pp_proto;
|
||||
|
||||
/* A C-channel is a 64k timeslot used for signalling */
|
||||
struct v5x_c_channel {
|
||||
|
@ -104,16 +169,20 @@ 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;
|
||||
bool b_channel; /* channel can be used as b-channel */
|
||||
};
|
||||
|
||||
/* one physical E1 interface used within a V5.2 interface */
|
||||
struct v5x_link {
|
||||
struct llist_head list; /* interface.links */
|
||||
uint8_t id;
|
||||
struct v5x_interface *interface; /* back-pointer */
|
||||
struct v5x_timeslot ts[32]; /* 32 E1 slots; 0 not available */
|
||||
struct v5x_c_channel c_channel[3]; /* 64k signaling possible on TS16, TS15 and TS31 */
|
||||
struct osmo_fsm_inst *l1_link_fi; /* Layer 1 Link FSM instance */
|
||||
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 */
|
||||
};
|
||||
|
||||
/* one V5.x interface between AN (Access Network) and LE (Local Exchange) */
|
||||
|
@ -121,43 +190,54 @@ struct v5x_interface {
|
|||
struct llist_head list; /* instance.interfaces */
|
||||
struct v5x_instance *instance; /* back-pointer */
|
||||
enum v5x_dialect dialect;
|
||||
uint32_t id; /* interface id */
|
||||
uint8_t variant; /* provitioning variant */
|
||||
struct v5x_link *primary_link; /* one of the links below */
|
||||
struct v5x_link *secondary_link; /* one of the links below */
|
||||
/* 1..16 links in one interface */
|
||||
struct v5x_link links[16];
|
||||
uint32_t id_local, id_remote; /* interface id */
|
||||
uint8_t variant_local, variant_remote; /* provitioning variant */
|
||||
bool id_remote_valid;
|
||||
bool variant_remote_valid;
|
||||
bool use_capability; /* use bearer transfer capability */
|
||||
uint8_t capability; /* bearer transfer capability */
|
||||
|
||||
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 {
|
||||
struct lapv5_instance *li; /* Link control data link */
|
||||
struct v5x_c_channel *c_chan; /* pointer to active C-channel */
|
||||
struct osmo_fsm_inst *fi; /* Link Control FSM instance */
|
||||
bool established; /* track if link is up or down */
|
||||
} lcp;
|
||||
struct {
|
||||
struct lapv5_instance *li; /* PSTN data link */
|
||||
struct v5x_c_channel *c_chan; /* pointer to active C-channel */
|
||||
bool established; /* track if link is up or down */
|
||||
} pstn;
|
||||
struct {
|
||||
struct lapv5_instance *li; /* BCC data link */
|
||||
struct v5x_c_channel *c_chan; /* pointer to active C-channel */
|
||||
bool established; /* track if link is up or down */
|
||||
} bcc;
|
||||
struct {
|
||||
struct lapv5_instance *li; /* Protection data link 1 + 2 */
|
||||
struct v5x_c_channel *c_chan; /* pointer to active C-channel */
|
||||
} protection[2];
|
||||
uint16_t cc_id; /* CC-ID of protected C-channel */
|
||||
struct v52_pp_proto *pp; /* protection protocol instance */
|
||||
struct lapv5_instance *li[2]; /* Protection data link 1 + 2 */
|
||||
bool established[2]; /* track if link is up or down */
|
||||
} protection;
|
||||
|
||||
struct llist_head links; /* list of v5x_link */
|
||||
struct v5x_link *primary_link; /* primary link */
|
||||
struct v5x_link *secondary_link; /* standby link */
|
||||
struct v5x_link *cc_link; /* currently used link for signaling (primary on startup) */
|
||||
struct llist_head user_ports; /* list of v5x_user_port */
|
||||
struct llist_head bcc_procs; /* list of v52_bcc_procs */
|
||||
};
|
||||
|
||||
struct v5x_l1_proto {
|
||||
struct v5x_link *v5l; /* back pointer */
|
||||
struct osmo_fsm_inst *fi; /* L1 FSM */
|
||||
int los, rai, ais, sa7_zero; /* RX signal states */
|
||||
};
|
||||
|
||||
struct v5x_ctrl_proto {
|
||||
struct v5x_user_port *v5up; /* back pointer, if port control is used */
|
||||
struct v5x_interface *v5if; /* back pointer, if common control is used */
|
||||
enum v5x_ctrl_type type; /* type of control protocol: common/port/link */
|
||||
void *priv; /* back pointer to the user */
|
||||
struct osmo_fsm_inst *fi; /* control FSM */
|
||||
struct llist_head tx_queue; /* list of message to be transmitted */
|
||||
struct msgb *tx_msg; /* copy of unacked message, for second try */
|
||||
|
@ -177,7 +257,7 @@ struct v5x_pstn_proto {
|
|||
/* 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 */
|
||||
struct v5x_interface *interface; /* 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 */
|
||||
|
@ -185,8 +265,7 @@ struct v5x_user_port {
|
|||
|
||||
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 */
|
||||
struct v5x_timeslot *ts[2]; /* two time slots */
|
||||
uint8_t ts_activated[2]; /* set if data stream is active */
|
||||
struct {
|
||||
} isdn;
|
||||
|
@ -194,22 +273,63 @@ struct v5x_user_port {
|
|||
struct v5x_pstn_proto *proto;
|
||||
} pstn;
|
||||
ph_socket_t ph_socket; /* unix socket to connect port to */
|
||||
bool blocking_enabled; /* we may only send blocking updates, if true */
|
||||
bool le_unblocked; /* if port is not blocked by LE */
|
||||
bool an_unblocked; /* if port is not blocked by AN */
|
||||
};
|
||||
|
||||
/* BCC process */
|
||||
struct v52_bcc_proc {
|
||||
struct llist_head list; /* part of v5x_instance.ports */
|
||||
struct v5x_interface *interface; /* back-pointer to instance we're part of */
|
||||
struct osmo_fsm_inst *fi; /* BCC FSM */
|
||||
uint16_t ref; /* reference of this process */
|
||||
uint8_t source_id; /* reference source */
|
||||
int timer; /* timer used */
|
||||
int expired; /* number of timeouts */
|
||||
uint16_t user_port_id; /* port ID */
|
||||
bool is_isdn; /* user port type */
|
||||
uint8_t link_id; /* link ID */
|
||||
uint8_t ts; /* TS nr */
|
||||
uint8_t override; /* override assigned channel */
|
||||
uint8_t isdn_slot; /* channel on ISDN interface */
|
||||
uint8_t *isdn_multislot; /* multiple slot assignment */
|
||||
bool use_capability; /* use bearer transfer capability */
|
||||
uint8_t capability; /* bearer transfer capability */
|
||||
};
|
||||
|
||||
struct v52_pp_mgmt_info {
|
||||
uint8_t link_id;
|
||||
uint8_t ts;
|
||||
uint8_t cause;
|
||||
};
|
||||
|
||||
/* PP process */
|
||||
struct v52_pp_proto {
|
||||
struct v5x_interface *interface; /* back pointer, if port control is used */
|
||||
struct osmo_fsm_inst *fi; /* PP FSM */
|
||||
uint8_t vp_s, vp_r; /* sequence numbers */
|
||||
bool vp_r_set; /* if we ever received a sequence number */
|
||||
struct v52_pp_mgmt_info info; /* keep management info for resend after timeout */
|
||||
int timeout_event; /* event when timer times out */
|
||||
int timeout_count; /* how many times the timer was started/timed out */
|
||||
};
|
||||
|
||||
struct v5x_instance {
|
||||
struct llist_head list; /* part of global list of instances */
|
||||
struct llist_head interfaces; /* v5x_interface.list */
|
||||
};
|
||||
|
||||
struct v5x_instance *v5x_instance_alloc(void *ctx);
|
||||
struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect,
|
||||
int (*ph_data_req_cb)(struct msgb *msg, void *cbdata));
|
||||
void v5x_instance_free(struct v5x_instance *v5i);
|
||||
struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect);
|
||||
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);
|
||||
void v5x_interface_free(struct v5x_interface *v5if);
|
||||
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);
|
||||
//FIXME: move this
|
||||
void ph_socket_rx_cb(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data, int length);
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue