osmo-v5/v5x_data.c

145 lines
3.7 KiB
C

#include <osmocom/core/talloc.h>
#include <osmocom/core/linuxlist.h>
#include "v5x_internal.h"
#include "v5x_protocol.h"
#include "v51_le_ctrl.h"
#include "lapv5.h"
static LLIST_HEAD(v5_instances);
struct v5x_instance *v5x_instance_alloc(void *ctx)
{
struct v5x_instance *v5i = talloc_zero(ctx, struct v5x_instance);
if (!v5i)
return NULL;
INIT_LLIST_HEAD(&v5i->interfaces);
llist_add_tail(&v5i->list, &v5_instances);
return v5i;
}
static void v5x_ts_init(struct v5x_timeslot *v5ts, uint8_t nr, struct v5x_link *v5l, uint16_t l3_addr)
{
v5ts->nr = nr;
v5ts->link = v5l;
v5ts->l3_address = l3_addr;
}
static void v5x_cchan_init(struct v5x_c_channel *v5cc, struct v5x_link *v5l, struct v5x_timeslot *v5ts, bool active)
{
v5cc->link = v5l;
v5cc->ts = v5ts;
v5cc->active = active;
}
static void v5x_link_init(struct v5x_link *v5l, struct v5x_interface *v5if, uint8_t id)
{
unsigned int i;
v5l->id = id;
v5l->interface = v5if;
for (i = 1; i < ARRAY_SIZE(v5l->ts); i++) {
v5x_ts_init(&v5l->ts[i], i, v5l, 0 /*l3_addr*/);
}
/* primary c-channel must always be present */
v5x_cchan_init(&v5l->c_channel[0], v5l, &v5l->ts[16], true);
}
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_interface *v5if = talloc_zero(v5i, struct v5x_interface);
//struct v5x_link *v5l;
struct v5x_c_channel *primary_c_chan;
v5if->instance = v5i;
v5if->dialect = dialect;
v5if->id = id;
v5if->variant = variant;
/* 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 = v51_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] ?
}
INIT_LLIST_HEAD(&v5if->user_ports);
llist_add_tail(&v5if->list, &v5i->interfaces);
return v5if;
}
struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t nr, bool is_isdn)
{
struct v5x_user_port *v5up;
v5up = talloc_zero(v5if, struct v5x_user_port);
if (!v5up)
return NULL;
v5up->inst = v5if;
v5up->is_isdn = is_isdn;
v5up->ctrl = v51_ctrl_create(NULL, v5up, nr);
if (!v5up->ctrl)
return NULL;
if (is_isdn) {
/* TODO: allocate fi
v5up->state = v52_isdn_state_create(v5up, nr);
if (!v5up->state)
return NULL;
*/
} else {
/* TODO: allocate fi
v5up->state = v52_pstn_state_create(v5up, nr);
if (!v5up->state)
return NULL;
v5up->pstn.proto = v52_pstn_protocol_create(v5up, nr);
if (!v5up->pstn.proto)
return NULL;
*/
}
v5up->nr = nr;
llist_add_tail(&v5up->list, &v5if->user_ports);
return v5up;
}
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr)
{
struct v5x_user_port *v5up;
llist_for_each_entry(v5up, &v5if->user_ports, list) {
if (v5up->nr == nr)
return v5up;
}
return NULL;
}