trxcon: rework L1CTL socket API to support multiple clients

Change-Id: I1cfc49f36ead6e2ba0a6110b0fb65c55412ef5e3
This commit is contained in:
Vadim Yanitskiy 2022-07-20 06:20:01 +07:00
parent a89492a4dd
commit 506e9085e3
7 changed files with 272 additions and 270 deletions

View File

@ -7,21 +7,21 @@
#include <osmocom/bb/trxcon/l1ctl_proto.h>
/* Event handlers */
int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg);
int l1ctl_rx_cb(struct l1ctl_client *l1c, struct msgb *msg);
int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint8_t result,
const struct l1ctl_info_dl *dl_info, uint8_t bsic);
int l1ctl_tx_ccch_mode_conf(struct l1ctl_link *l1l, uint8_t mode);
int l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn,
int l1ctl_tx_ccch_mode_conf(struct l1ctl_client *l1c, uint8_t mode);
int l1ctl_tx_pm_conf(struct l1ctl_client *l1c, uint16_t band_arfcn,
int dbm, int last);
int l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type);
int l1ctl_tx_reset_ind(struct l1ctl_link *l1l, uint8_t type);
int l1ctl_tx_reset_conf(struct l1ctl_client *l1c, uint8_t type);
int l1ctl_tx_reset_ind(struct l1ctl_client *l1c, uint8_t type);
int l1ctl_tx_dt_ind(struct l1ctl_link *l1l,
int l1ctl_tx_dt_ind(struct l1ctl_client *l1c,
const struct l1ctl_info_dl *dl_info,
const uint8_t *l2, size_t l2_len,
bool traffic);
int l1ctl_tx_dt_conf(struct l1ctl_link *l1l,
int l1ctl_tx_dt_conf(struct l1ctl_client *l1c,
struct l1ctl_info_dl *data, bool traffic);
int l1ctl_tx_rach_conf(struct l1ctl_link *l1l,
int l1ctl_tx_rach_conf(struct l1ctl_client *l1c,
uint16_t band_arfcn, uint32_t fn);

View File

@ -6,7 +6,6 @@
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/fsm.h>
#define L1CTL_LENGTH 256
#define L1CTL_HEADROOM 32
@ -17,22 +16,49 @@
*/
#define L1CTL_MSG_LEN_FIELD 2
enum l1ctl_fsm_states {
L1CTL_STATE_IDLE = 0,
L1CTL_STATE_CONNECTED,
struct l1ctl_client;
typedef int l1ctl_conn_data_func(struct l1ctl_client *, struct msgb *);
typedef void l1ctl_conn_state_func(struct l1ctl_client *);
struct l1ctl_server_cfg {
/* UNIX socket path to listen on */
const char *sock_path;
/* talloc context to be used for new clients */
void *talloc_ctx;
/* maximum number of connected clients */
unsigned int num_clients_max;
/* functions to be called on various events */
l1ctl_conn_data_func *conn_read_cb; /* mandatory */
l1ctl_conn_state_func *conn_accept_cb; /* optional */
l1ctl_conn_state_func *conn_close_cb; /* optional */
};
struct l1ctl_link {
struct osmo_fsm_inst *fsm;
struct osmo_fd listen_bfd;
struct osmo_wqueue wq;
struct l1ctl_server {
/* list of connected clients */
struct llist_head clients;
/* number of connected clients */
unsigned int num_clients;
/* socket on which we listen for connections */
struct osmo_fd ofd;
/* server configuration */
const struct l1ctl_server_cfg *cfg;
};
/* Some private data */
struct l1ctl_client {
/* list head in l1ctl_server.clients */
struct llist_head list;
/* struct l1ctl_server we belong to */
struct l1ctl_server *server;
/* client's write queue */
struct osmo_wqueue wq;
/* some private data */
void *priv;
};
struct l1ctl_link *l1ctl_link_init(void *tall_ctx, const char *sock_path);
void l1ctl_link_shutdown(struct l1ctl_link *l1l);
int l1ctl_server_start(struct l1ctl_server *server,
const struct l1ctl_server_cfg *cfg);
void l1ctl_server_shutdown(struct l1ctl_server *server);
int l1ctl_link_send(struct l1ctl_link *l1l, struct msgb *msg);
int l1ctl_link_close_conn(struct l1ctl_link *l1l);
int l1ctl_client_send(struct l1ctl_client *client, struct msgb *msg);
void l1ctl_client_conn_close(struct l1ctl_client *client);

View File

@ -4,7 +4,7 @@
struct l1sched_state;
struct trx_instance;
struct l1ctl_link;
struct l1ctl_client;
enum trxcon_fsm_states {
TRXCON_STATE_IDLE = 0,
@ -28,7 +28,7 @@ struct trxcon_inst {
struct l1sched_state *sched;
/* L1/L2 interfaces */
struct trx_instance *trx;
struct l1ctl_link *l1l;
struct l1ctl_client *l1c;
/* TODO: implement this as an FSM state with timeout */
struct osmo_timer_list fbsb_timer;

View File

@ -77,7 +77,7 @@ static struct msgb *l1ctl_alloc_msg(uint8_t msg_type)
return msg;
}
int l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn,
int l1ctl_tx_pm_conf(struct l1ctl_client *l1c, uint16_t band_arfcn,
int dbm, int last)
{
struct l1ctl_pm_conf *pmc;
@ -101,10 +101,10 @@ int l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn,
l1h->flags |= L1CTL_F_DONE;
}
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
int l1ctl_tx_reset_ind(struct l1ctl_link *l1l, uint8_t type)
int l1ctl_tx_reset_ind(struct l1ctl_client *l1c, uint8_t type)
{
struct msgb *msg;
struct l1ctl_reset *res;
@ -118,10 +118,10 @@ int l1ctl_tx_reset_ind(struct l1ctl_link *l1l, uint8_t type)
res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
res->type = type;
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
int l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type)
int l1ctl_tx_reset_conf(struct l1ctl_client *l1c, uint8_t type)
{
struct msgb *msg;
struct l1ctl_reset *res;
@ -134,7 +134,7 @@ int l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type)
res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
res->type = type;
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
static struct l1ctl_info_dl *put_dl_info_hdr(struct msgb *msg,
@ -164,10 +164,10 @@ static struct l1ctl_fbsb_conf *fbsb_conf_make(struct msgb *msg, uint8_t result,
return conf;
}
int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint8_t result,
const struct l1ctl_info_dl *dl_info, uint8_t bsic)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_fbsb_conf *conf;
struct msgb *msg;
@ -189,10 +189,10 @@ int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
if (osmo_timer_pending(&trxcon->fbsb_timer))
osmo_timer_del(&trxcon->fbsb_timer);
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
int l1ctl_tx_ccch_mode_conf(struct l1ctl_link *l1l, uint8_t mode)
int l1ctl_tx_ccch_mode_conf(struct l1ctl_client *l1c, uint8_t mode)
{
struct l1ctl_ccch_mode_conf *conf;
struct msgb *msg;
@ -204,13 +204,13 @@ int l1ctl_tx_ccch_mode_conf(struct l1ctl_link *l1l, uint8_t mode)
conf = (struct l1ctl_ccch_mode_conf *) msgb_put(msg, sizeof(*conf));
conf->ccch_mode = mode;
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
/**
* Handles both L1CTL_DATA_IND and L1CTL_TRAFFIC_IND.
*/
int l1ctl_tx_dt_ind(struct l1ctl_link *l1l,
int l1ctl_tx_dt_ind(struct l1ctl_client *l1c,
const struct l1ctl_info_dl *dl_info,
const uint8_t *l2, size_t l2_len,
bool traffic)
@ -232,10 +232,10 @@ int l1ctl_tx_dt_ind(struct l1ctl_link *l1l,
}
/* Put message to upper layers */
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
int l1ctl_tx_rach_conf(struct l1ctl_link *l1l,
int l1ctl_tx_rach_conf(struct l1ctl_client *l1c,
uint16_t band_arfcn, uint32_t fn)
{
struct l1ctl_info_dl *dl;
@ -251,14 +251,14 @@ int l1ctl_tx_rach_conf(struct l1ctl_link *l1l,
dl->band_arfcn = htons(band_arfcn);
dl->frame_nr = htonl(fn);
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
/**
* Handles both L1CTL_DATA_CONF and L1CTL_TRAFFIC_CONF.
*/
int l1ctl_tx_dt_conf(struct l1ctl_link *l1l,
int l1ctl_tx_dt_conf(struct l1ctl_client *l1c,
struct l1ctl_info_dl *data, bool traffic)
{
struct msgb *msg;
@ -271,7 +271,7 @@ int l1ctl_tx_dt_conf(struct l1ctl_link *l1l,
/* Copy DL frame header from source message */
put_dl_info_hdr(msg, data);
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
static enum gsm_phys_chan_config l1ctl_ccch_mode2pchan_config(enum ccch_mode mode)
@ -297,8 +297,8 @@ static enum gsm_phys_chan_config l1ctl_ccch_mode2pchan_config(enum ccch_mode mod
/* FBSB expire timer */
static void fbsb_timer_cb(void *data)
{
struct l1ctl_link *l1l = (struct l1ctl_link *) data;
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_client *l1c = (struct l1ctl_client *) data;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_info_dl *dl;
struct msgb *msg;
@ -319,12 +319,12 @@ static void fbsb_timer_cb(void *data)
/* Ask SCH handler not to send L1CTL_FBSB_CONF anymore */
trxcon->fbsb_conf_sent = true;
l1ctl_link_send(l1l, msg);
l1ctl_client_send(l1c, msg);
}
static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_fbsb_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
enum gsm_phys_chan_config ch_config;
struct l1ctl_fbsb_req *fbsb;
uint16_t band_arfcn;
@ -372,7 +372,7 @@ static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
trx_if_cmd_poweron(trxcon->trx);
/* Start FBSB expire timer */
trxcon->fbsb_timer.data = l1l;
trxcon->fbsb_timer.data = l1c;
trxcon->fbsb_timer.cb = fbsb_timer_cb;
LOGP(DL1C, LOGL_INFO, "Starting FBSB timer %u ms\n", timeout * GSM_TDMA_FN_DURATION_uS / 1000);
osmo_timer_schedule(&trxcon->fbsb_timer, 0,
@ -383,10 +383,10 @@ exit:
return rc;
}
static int l1ctl_rx_pm_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_pm_req(struct l1ctl_client *l1c, struct msgb *msg)
{
uint16_t band_arfcn_start, band_arfcn_stop;
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_pm_req *pmr;
int rc = 0;
@ -415,9 +415,9 @@ exit:
return rc;
}
static int l1ctl_rx_reset_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_reset_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_reset *res;
int rc = 0;
@ -448,14 +448,14 @@ static int l1ctl_rx_reset_req(struct l1ctl_link *l1l, struct msgb *msg)
}
/* Confirm */
rc = l1ctl_tx_reset_conf(l1l, res->type);
rc = l1ctl_tx_reset_conf(l1c, res->type);
exit:
msgb_free(msg);
return rc;
}
static int l1ctl_rx_echo_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_echo_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct l1ctl_hdr *l1h;
@ -467,12 +467,12 @@ static int l1ctl_rx_echo_req(struct l1ctl_link *l1l, struct msgb *msg)
l1h->msg_type = L1CTL_ECHO_CONF;
msg->data = msg->l1h;
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_ccch_mode_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
enum gsm_phys_chan_config ch_config;
struct l1ctl_ccch_mode_req *req;
struct l1sched_ts *ts;
@ -506,16 +506,16 @@ static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
/* Confirm reconfiguration */
if (!rc)
rc = l1ctl_tx_ccch_mode_conf(l1l, req->ccch_mode);
rc = l1ctl_tx_ccch_mode_conf(l1c, req->ccch_mode);
exit:
msgb_free(msg);
return rc;
}
static int l1ctl_rx_rach_req(struct l1ctl_link *l1l, struct msgb *msg, bool ext)
static int l1ctl_rx_rach_req(struct l1ctl_client *l1c, struct msgb *msg, bool ext)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_info_ul *ul;
struct l1sched_ts_prim *prim;
struct l1sched_ts_prim_rach rach;
@ -631,9 +631,9 @@ static int l1ctl_proc_est_req_h1(struct trx_instance *trx, struct l1ctl_h1 *h)
return 0;
}
static int l1ctl_rx_dm_est_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_dm_est_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
enum gsm_phys_chan_config config;
struct l1ctl_dm_est_req *est_req;
struct l1ctl_info_ul *ul;
@ -691,9 +691,9 @@ exit:
return rc;
}
static int l1ctl_rx_dm_rel_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_dm_rel_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_DM_REL_REQ, resetting scheduler\n");
@ -707,10 +707,10 @@ static int l1ctl_rx_dm_rel_req(struct l1ctl_link *l1l, struct msgb *msg)
/**
* Handles both L1CTL_DATA_REQ and L1CTL_TRAFFIC_REQ.
*/
static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
static int l1ctl_rx_dt_req(struct l1ctl_client *l1c,
struct msgb *msg, bool traffic)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_info_ul *ul;
struct l1sched_ts_prim *prim;
uint8_t chan_nr, link_id;
@ -742,9 +742,9 @@ static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
return rc;
}
static int l1ctl_rx_param_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_param_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_par_req *par_req;
struct l1ctl_info_ul *ul;
@ -766,9 +766,9 @@ static int l1ctl_rx_param_req(struct l1ctl_link *l1l, struct msgb *msg)
return 0;
}
static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_tch_mode_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_tch_mode_req *req;
struct l1sched_lchan_state *lchan;
struct l1sched_ts *ts;
@ -807,12 +807,12 @@ static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
l1h->msg_type = L1CTL_TCH_MODE_CONF;
return l1ctl_link_send(l1l, msg);
return l1ctl_client_send(l1c, msg);
}
static int l1ctl_rx_crypto_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_crypto_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_crypto_req *req;
struct l1ctl_info_ul *ul;
struct l1sched_ts *ts;
@ -849,7 +849,7 @@ exit:
return rc;
}
int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg)
int l1ctl_rx_cb(struct l1ctl_client *l1c, struct msgb *msg)
{
struct l1ctl_hdr *l1h;
@ -858,33 +858,33 @@ int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg)
switch (l1h->msg_type) {
case L1CTL_FBSB_REQ:
return l1ctl_rx_fbsb_req(l1l, msg);
return l1ctl_rx_fbsb_req(l1c, msg);
case L1CTL_PM_REQ:
return l1ctl_rx_pm_req(l1l, msg);
return l1ctl_rx_pm_req(l1c, msg);
case L1CTL_RESET_REQ:
return l1ctl_rx_reset_req(l1l, msg);
return l1ctl_rx_reset_req(l1c, msg);
case L1CTL_ECHO_REQ:
return l1ctl_rx_echo_req(l1l, msg);
return l1ctl_rx_echo_req(l1c, msg);
case L1CTL_CCCH_MODE_REQ:
return l1ctl_rx_ccch_mode_req(l1l, msg);
return l1ctl_rx_ccch_mode_req(l1c, msg);
case L1CTL_RACH_REQ:
return l1ctl_rx_rach_req(l1l, msg, false);
return l1ctl_rx_rach_req(l1c, msg, false);
case L1CTL_EXT_RACH_REQ:
return l1ctl_rx_rach_req(l1l, msg, true);
return l1ctl_rx_rach_req(l1c, msg, true);
case L1CTL_DM_EST_REQ:
return l1ctl_rx_dm_est_req(l1l, msg);
return l1ctl_rx_dm_est_req(l1c, msg);
case L1CTL_DM_REL_REQ:
return l1ctl_rx_dm_rel_req(l1l, msg);
return l1ctl_rx_dm_rel_req(l1c, msg);
case L1CTL_DATA_REQ:
return l1ctl_rx_dt_req(l1l, msg, false);
return l1ctl_rx_dt_req(l1c, msg, false);
case L1CTL_TRAFFIC_REQ:
return l1ctl_rx_dt_req(l1l, msg, true);
return l1ctl_rx_dt_req(l1c, msg, true);
case L1CTL_PARAM_REQ:
return l1ctl_rx_param_req(l1l, msg);
return l1ctl_rx_param_req(l1c, msg);
case L1CTL_TCH_MODE_REQ:
return l1ctl_rx_tch_mode_req(l1l, msg);
return l1ctl_rx_tch_mode_req(l1c, msg);
case L1CTL_CRYPTO_REQ:
return l1ctl_rx_crypto_req(l1l, msg);
return l1ctl_rx_crypto_req(l1c, msg);
/* Not (yet) handled messages */
case L1CTL_NEIGH_PM_REQ:

View File

@ -1,9 +1,10 @@
/*
* OsmocomBB <-> SDR connection bridge
* GSM L1 control socket (/tmp/osmocom_l2) handlers
* UNIX socket server for L1CTL
*
* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
* (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2022 by by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@ -24,60 +25,33 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/bb/trxcon/trxcon.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/l1ctl_link.h>
#include <osmocom/bb/trxcon/l1ctl.h>
static struct value_string l1ctl_evt_names[] = {
{ 0, NULL } /* no events? */
};
static struct osmo_fsm_state l1ctl_fsm_states[] = {
[L1CTL_STATE_IDLE] = {
.out_state_mask = GEN_MASK(L1CTL_STATE_CONNECTED),
.name = "IDLE",
},
[L1CTL_STATE_CONNECTED] = {
.out_state_mask = GEN_MASK(L1CTL_STATE_IDLE),
.name = "CONNECTED",
},
};
static struct osmo_fsm l1ctl_fsm = {
.name = "l1ctl_link_fsm",
.states = l1ctl_fsm_states,
.num_states = ARRAY_SIZE(l1ctl_fsm_states),
.log_subsys = DL1C,
.event_names = l1ctl_evt_names,
};
static int l1ctl_link_read_cb(struct osmo_fd *bfd)
static int l1ctl_client_read_cb(struct osmo_fd *ofd)
{
struct l1ctl_link *l1l = (struct l1ctl_link *) bfd->data;
struct l1ctl_client *client = (struct l1ctl_client *)ofd->data;
struct msgb *msg;
uint16_t len;
int rc;
/* Attempt to read from socket */
rc = read(bfd->fd, &len, L1CTL_MSG_LEN_FIELD);
rc = read(ofd->fd, &len, L1CTL_MSG_LEN_FIELD);
if (rc < L1CTL_MSG_LEN_FIELD) {
LOGP(DL1D, LOGL_NOTICE, "L1CTL has lost connection\n");
LOGP(DL1D, LOGL_NOTICE, "L1CTL server has lost connection\n");
if (rc >= 0)
rc = -EIO;
l1ctl_link_close_conn(l1l);
l1ctl_client_conn_close(client);
return rc;
}
@ -97,7 +71,7 @@ static int l1ctl_link_read_cb(struct osmo_fd *bfd)
}
msg->l1h = msgb_put(msg, len);
rc = read(bfd->fd, msg->l1h, msgb_l1len(msg));
rc = read(ofd->fd, msg->l1h, msgb_l1len(msg));
if (rc != len) {
LOGP(DL1D, LOGL_ERROR, "Can not read data: len=%d < rc=%d: "
"%s\n", len, rc, strerror(errno));
@ -110,19 +84,19 @@ static int l1ctl_link_read_cb(struct osmo_fd *bfd)
osmo_hexdump(msg->data, msg->len));
/* Call L1CTL handler */
l1ctl_rx_cb(l1l, msg);
client->server->cfg->conn_read_cb(client, msg);
return 0;
}
static int l1ctl_link_write_cb(struct osmo_fd *bfd, struct msgb *msg)
static int l1ctl_client_write_cb(struct osmo_fd *ofd, struct msgb *msg)
{
int len;
if (bfd->fd <= 0)
if (ofd->fd <= 0)
return -EINVAL;
len = write(bfd->fd, msg->data, msg->len);
len = write(ofd->fd, msg->data, msg->len);
if (len != msg->len) {
LOGP(DL1D, LOGL_ERROR, "Failed to write data: "
"written (%d) < msg_len (%d)\n", len, msg->len);
@ -133,53 +107,64 @@ static int l1ctl_link_write_cb(struct osmo_fd *bfd, struct msgb *msg)
}
/* Connection handler */
static int l1ctl_link_accept(struct osmo_fd *bfd, unsigned int flags)
static int l1ctl_server_conn_cb(struct osmo_fd *sfd, unsigned int flags)
{
struct l1ctl_link *l1l = (struct l1ctl_link *) bfd->data;
struct trxcon_inst *trxcon = l1l->priv;
struct osmo_fd *conn_bfd = &l1l->wq.bfd;
struct sockaddr_un un_addr;
socklen_t len;
int cfd;
struct l1ctl_server *server = (struct l1ctl_server *)sfd->data;
struct l1ctl_client *client;
int rc, client_fd;
len = sizeof(un_addr);
cfd = accept(bfd->fd, (struct sockaddr *) &un_addr, &len);
if (cfd < 0) {
LOGP(DL1C, LOGL_ERROR, "Failed to accept a new connection\n");
return -1;
client_fd = accept(sfd->fd, NULL, NULL);
if (client_fd < 0) {
LOGP(DL1C, LOGL_ERROR, "Failed to accept() a new connection: "
"%s\n", strerror(errno));
return client_fd;
}
/* Check if we already have an active connection */
if (conn_bfd->fd != -1) {
LOGP(DL1C, LOGL_NOTICE, "A new connection rejected: "
"we already have another active\n");
close(cfd);
return 0;
if (server->cfg->num_clients_max > 0 /* 0 means unlimited */ &&
server->num_clients >= server->cfg->num_clients_max) {
LOGP(DL1C, LOGL_NOTICE, "L1CTL server cannot accept more "
"than %u connection(s)\n", server->cfg->num_clients_max);
close(client_fd);
return -ENOMEM;
}
osmo_wqueue_init(&l1l->wq, 100);
INIT_LLIST_HEAD(&conn_bfd->list);
l1l->wq.write_cb = l1ctl_link_write_cb;
l1l->wq.read_cb = l1ctl_link_read_cb;
osmo_fd_setup(conn_bfd, cfd, OSMO_FD_READ, osmo_wqueue_bfd_cb, l1l, 0);
if (osmo_fd_register(conn_bfd) != 0) {
LOGP(DL1C, LOGL_ERROR, "Failed to register new connection fd\n");
close(conn_bfd->fd);
conn_bfd->fd = -1;
return -1;
client = talloc_zero(server->cfg->talloc_ctx, struct l1ctl_client);
if (client == NULL) {
LOGP(DL1C, LOGL_ERROR, "Failed to allocate an L1CTL client\n");
close(client_fd);
return -ENOMEM;
}
osmo_fsm_inst_dispatch(trxcon->fi, L1CTL_EVENT_CONNECT, l1l);
osmo_fsm_inst_state_chg(l1l->fsm, L1CTL_STATE_CONNECTED, 0, 0);
/* Init the client's write queue */
osmo_wqueue_init(&client->wq, 100);
INIT_LLIST_HEAD(&client->wq.bfd.list);
LOGP(DL1C, LOGL_NOTICE, "L1CTL has a new connection\n");
client->wq.write_cb = &l1ctl_client_write_cb;
client->wq.read_cb = &l1ctl_client_read_cb;
osmo_fd_setup(&client->wq.bfd, client_fd, OSMO_FD_READ, &osmo_wqueue_bfd_cb, client, 0);
/* Register the client's write queue */
rc = osmo_fd_register(&client->wq.bfd);
if (rc != 0) {
LOGP(DL1C, LOGL_ERROR, "Failed to register a new connection fd\n");
close(client->wq.bfd.fd);
talloc_free(client);
return rc;
}
LOGP(DL1C, LOGL_NOTICE, "L1CTL server got a new connection\n");
llist_add_tail(&client->list, &server->clients);
client->server = server;
server->num_clients++;
if (client->server->cfg->conn_accept_cb != NULL)
client->server->cfg->conn_accept_cb(client);
return 0;
}
int l1ctl_link_send(struct l1ctl_link *l1l, struct msgb *msg)
int l1ctl_client_send(struct l1ctl_client *client, struct msgb *msg)
{
uint8_t *len;
@ -194,7 +179,7 @@ int l1ctl_link_send(struct l1ctl_link *l1l, struct msgb *msg)
len = msgb_push(msg, L1CTL_MSG_LEN_FIELD);
osmo_store16be(msg->len - L1CTL_MSG_LEN_FIELD, len);
if (osmo_wqueue_enqueue(&l1l->wq, msg) != 0) {
if (osmo_wqueue_enqueue(&client->wq, msg) != 0) {
LOGP(DL1D, LOGL_ERROR, "Failed to enqueue msg!\n");
msgb_free(msg);
return -EIO;
@ -203,105 +188,70 @@ int l1ctl_link_send(struct l1ctl_link *l1l, struct msgb *msg)
return 0;
}
int l1ctl_link_close_conn(struct l1ctl_link *l1l)
void l1ctl_client_conn_close(struct l1ctl_client *client)
{
struct osmo_fd *conn_bfd = &l1l->wq.bfd;
struct trxcon_inst *trxcon = l1l->priv;
if (conn_bfd->fd <= 0)
return -EINVAL;
if (client->server->cfg->conn_close_cb != NULL)
client->server->cfg->conn_close_cb(client);
/* Close connection socket */
osmo_fd_unregister(conn_bfd);
close(conn_bfd->fd);
conn_bfd->fd = -1;
osmo_fd_unregister(&client->wq.bfd);
close(client->wq.bfd.fd);
client->wq.bfd.fd = -1;
/* Clear pending messages */
osmo_wqueue_clear(&l1l->wq);
osmo_wqueue_clear(&client->wq);
osmo_fsm_inst_dispatch(trxcon->fi, L1CTL_EVENT_DISCONNECT, l1l);
osmo_fsm_inst_state_chg(l1l->fsm, L1CTL_STATE_IDLE, 0, 0);
client->server->num_clients--;
llist_del(&client->list);
talloc_free(client);
}
int l1ctl_server_start(struct l1ctl_server *server,
const struct l1ctl_server_cfg *cfg)
{
int rc;
LOGP(DL1C, LOGL_NOTICE, "Init L1CTL server (sock_path=%s)\n", cfg->sock_path);
*server = (struct l1ctl_server) {
.clients = LLIST_HEAD_INIT(server->clients),
.cfg = cfg,
};
/* conn_read_cb shall not be NULL */
OSMO_ASSERT(cfg->conn_read_cb != NULL);
/* Bind connection handler */
osmo_fd_setup(&server->ofd, -1, OSMO_FD_READ, &l1ctl_server_conn_cb, server, 0);
rc = osmo_sock_unix_init_ofd(&server->ofd, SOCK_STREAM, 0,
cfg->sock_path, OSMO_SOCK_F_BIND);
if (rc < 0) {
LOGP(DL1C, LOGL_ERROR, "Could not create UNIX socket: %s\n",
strerror(errno));
talloc_free(server);
return rc;
}
return 0;
}
struct l1ctl_link *l1ctl_link_init(void *tall_ctx, const char *sock_path)
void l1ctl_server_shutdown(struct l1ctl_server *server)
{
struct l1ctl_link *l1l;
struct osmo_fd *bfd;
int rc;
LOGP(DL1C, LOGL_NOTICE, "Shutdown L1CTL server\n");
LOGP(DL1C, LOGL_NOTICE, "Init L1CTL link (%s)\n", sock_path);
l1l = talloc_zero(tall_ctx, struct l1ctl_link);
if (!l1l) {
LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory\n");
return NULL;
/* Close all client connections */
while (!llist_empty(&server->clients)) {
struct l1ctl_client *client = llist_entry(server->clients.next,
struct l1ctl_client,
list);
l1ctl_client_conn_close(client);
}
/* Allocate a new dedicated state machine */
l1l->fsm = osmo_fsm_inst_alloc(&l1ctl_fsm, l1l,
NULL, LOGL_DEBUG, "l1ctl_link");
if (l1l->fsm == NULL) {
LOGP(DTRX, LOGL_ERROR, "Failed to allocate an instance "
"of FSM '%s'\n", l1ctl_fsm.name);
talloc_free(l1l);
return NULL;
}
/* Create a socket and bind handlers */
bfd = &l1l->listen_bfd;
/* Bind connection handler */
osmo_fd_setup(bfd, -1, OSMO_FD_READ, l1ctl_link_accept, l1l, 0);
rc = osmo_sock_unix_init_ofd(bfd, SOCK_STREAM, 0, sock_path,
OSMO_SOCK_F_BIND);
if (rc < 0) {
LOGP(DL1C, LOGL_ERROR, "Could not create UNIX socket: %s\n",
strerror(errno));
osmo_fsm_inst_free(l1l->fsm);
talloc_free(l1l);
return NULL;
}
/**
* To be able to accept first connection and
* drop others, it should be set to -1
*/
l1l->wq.bfd.fd = -1;
return l1l;
}
void l1ctl_link_shutdown(struct l1ctl_link *l1l)
{
struct osmo_fd *listen_bfd;
/* May be unallocated due to init error */
if (!l1l)
return;
LOGP(DL1C, LOGL_NOTICE, "Shutdown L1CTL link\n");
listen_bfd = &l1l->listen_bfd;
/* Check if we have an established connection */
if (l1l->wq.bfd.fd != -1)
l1ctl_link_close_conn(l1l);
/* Unbind listening socket */
if (listen_bfd->fd != -1) {
osmo_fd_unregister(listen_bfd);
close(listen_bfd->fd);
listen_bfd->fd = -1;
if (server->ofd.fd != -1) {
osmo_fd_unregister(&server->ofd);
close(server->ofd.fd);
server->ofd.fd = -1;
}
osmo_fsm_inst_free(l1l->fsm);
talloc_free(l1l);
}
static __attribute__((constructor)) void on_dso_load(void)
{
OSMO_ASSERT(osmo_fsm_register(&l1ctl_fsm) == 0);
}

View File

@ -387,7 +387,7 @@ static void trx_if_measure_rsp_cb(struct trx_instance *trx, char *resp)
}
/* Send L1CTL_PM_CONF */
l1ctl_tx_pm_conf(trxcon->l1l, band_arfcn, dbm,
l1ctl_tx_pm_conf(trxcon->l1c, band_arfcn, dbm,
band_arfcn == trx->pm_band_arfcn_stop);
/* Schedule a next measurement */

View File

@ -157,16 +157,16 @@ int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan,
switch (dt) {
case L1SCHED_DT_TRAFFIC:
case L1SCHED_DT_PACKET_DATA:
rc = l1ctl_tx_dt_ind(trxcon->l1l, &dl_hdr, data, data_len, true);
rc = l1ctl_tx_dt_ind(trxcon->l1c, &dl_hdr, data, data_len, true);
break;
case L1SCHED_DT_SIGNALING:
rc = l1ctl_tx_dt_ind(trxcon->l1l, &dl_hdr, data, data_len, false);
rc = l1ctl_tx_dt_ind(trxcon->l1c, &dl_hdr, data, data_len, false);
break;
case L1SCHED_DT_OTHER:
if (lchan->type == L1SCHED_SCH) {
if (trxcon->fbsb_conf_sent)
return 0;
rc = l1ctl_tx_fbsb_conf(trxcon->l1l, 0, &dl_hdr, sched->bsic);
rc = l1ctl_tx_fbsb_conf(trxcon->l1c, 0, &dl_hdr, sched->bsic);
break;
}
/* fall through */
@ -209,12 +209,12 @@ int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
switch (dt) {
case L1SCHED_DT_TRAFFIC:
case L1SCHED_DT_PACKET_DATA:
rc = l1ctl_tx_dt_conf(trxcon->l1l, &dl_hdr, true);
rc = l1ctl_tx_dt_conf(trxcon->l1c, &dl_hdr, true);
data_len = lchan->prim->payload_len;
data = lchan->prim->payload;
break;
case L1SCHED_DT_SIGNALING:
rc = l1ctl_tx_dt_conf(trxcon->l1l, &dl_hdr, false);
rc = l1ctl_tx_dt_conf(trxcon->l1c, &dl_hdr, false);
data_len = lchan->prim->payload_len;
data = lchan->prim->payload;
break;
@ -224,7 +224,7 @@ int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
rach = (struct l1sched_ts_prim_rach *)lchan->prim->payload;
rc = l1ctl_tx_rach_conf(trxcon->l1l, trxcon->trx->band_arfcn, fn);
rc = l1ctl_tx_rach_conf(trxcon->l1c, trxcon->trx->band_arfcn, fn);
if (lchan->prim->type == L1SCHED_PRIM_RACH11) {
ra_buf[0] = (uint8_t)(rach->ra >> 3);
ra_buf[1] = (uint8_t)(rach->ra & 0x07);
@ -331,13 +331,6 @@ struct trxcon_inst *trxcon_inst_alloc(void *ctx)
trxcon, LOGL_DEBUG, NULL);
OSMO_ASSERT(trxcon->fi != NULL);
/* Init L1CTL server */
trxcon->l1l = l1ctl_link_init(trxcon, app_data.bind_socket);
if (trxcon->l1l == NULL) {
trxcon_inst_free(trxcon);
return NULL;
}
/* Init transceiver interface */
trxcon->trx = trx_if_open(trxcon,
app_data.trx_bind_ip,
@ -348,8 +341,6 @@ struct trxcon_inst *trxcon_inst_alloc(void *ctx)
return NULL;
}
trxcon->l1l->priv = trxcon;
/* Init scheduler */
trxcon->sched = l1sched_alloc(trxcon, app_data.trx_fn_advance, trxcon);
if (trxcon->sched == NULL) {
@ -366,8 +357,8 @@ void trxcon_inst_free(struct trxcon_inst *trxcon)
if (trxcon->sched != NULL)
l1sched_free(trxcon->sched);
/* Close active connections */
if (trxcon->l1l != NULL)
l1ctl_link_shutdown(trxcon->l1l);
if (trxcon->l1c != NULL)
l1ctl_client_conn_close(trxcon->l1c);
if (trxcon->trx != NULL)
trx_if_close(trxcon->trx);
@ -379,6 +370,32 @@ void trxcon_inst_free(struct trxcon_inst *trxcon)
talloc_free(trxcon);
}
static void l1ctl_conn_accept_cb(struct l1ctl_client *l1c)
{
struct trxcon_inst *trxcon;
trxcon = trxcon_inst_alloc(l1c);
if (trxcon == NULL) {
l1ctl_client_conn_close(l1c);
return;
}
l1c->priv = trxcon;
trxcon->l1c = l1c;
}
static void l1ctl_conn_close_cb(struct l1ctl_client *l1c)
{
struct trxcon_inst *trxcon = l1c->priv;
if (trxcon == NULL)
return;
/* l1c is free()ed by the caller */
trxcon->l1c = NULL;
trxcon_inst_free(trxcon);
}
static void print_usage(const char *app)
{
printf("Usage: %s\n", app);
@ -489,7 +506,8 @@ static void signal_handler(int signum)
int main(int argc, char **argv)
{
struct trxcon_inst *trxcon = NULL;
struct l1ctl_server_cfg server_cfg;
struct l1ctl_server server;
int rc = 0;
printf("%s", COPYRIGHT);
@ -535,10 +553,20 @@ int main(int argc, char **argv)
/* Register the trxcon state machine */
OSMO_ASSERT(osmo_fsm_register(&trxcon_fsm_def) == 0);
/* Allocate the trxcon instance (only one for now) */
trxcon = trxcon_inst_alloc(tall_trxcon_ctx);
if (trxcon == NULL)
/* Start the L1CTL server */
server_cfg = (struct l1ctl_server_cfg) {
.sock_path = app_data.bind_socket,
.talloc_ctx = tall_trxcon_ctx,
.num_clients_max = 1, /* only one connection for now */
.conn_read_cb = &l1ctl_rx_cb,
.conn_accept_cb = &l1ctl_conn_accept_cb,
.conn_close_cb = &l1ctl_conn_close_cb,
};
if (l1ctl_server_start(&server, &server_cfg) != 0) {
rc = EXIT_FAILURE;
goto exit;
}
LOGP(DAPP, LOGL_NOTICE, "Init complete\n");
@ -557,9 +585,7 @@ int main(int argc, char **argv)
osmo_select_main(0);
exit:
/* Release the trxcon instance */
if (trxcon != NULL)
trxcon_inst_free(trxcon);
l1ctl_server_shutdown(&server);
/* Deinitialize logging */
log_fini();