summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-07-19 11:02:47 +0200
committerHarald Welte <laforge@gnumonks.org>2017-07-19 11:30:26 +0200
commitf5e0f6424b35751d54e82a08f8d6e6de22ddea9a (patch)
tree728156eaa75f1ad64fbf9ea486fa017e908600eb
parentef9ee6116ba145f8a09ecc614bb000004a302145 (diff)
VIRT-PHY: Major rewrite to deal with muliple L1CTL clients
-rw-r--r--src/host/virt_phy/include/virtphy/gsmtapl1_if.h6
-rw-r--r--src/host/virt_phy/include/virtphy/l1ctl_sap.h62
-rw-r--r--src/host/virt_phy/include/virtphy/l1ctl_sock.h32
-rw-r--r--src/host/virt_phy/include/virtphy/virt_l1_model.h11
-rw-r--r--src/host/virt_phy/include/virtphy/virt_l1_sched.h16
-rw-r--r--src/host/virt_phy/src/gsmtapl1_if.c158
-rw-r--r--src/host/virt_phy/src/l1ctl_sap.c157
-rw-r--r--src/host/virt_phy/src/l1ctl_sock.c87
-rw-r--r--src/host/virt_phy/src/virt_l1_model.c13
-rw-r--r--src/host/virt_phy/src/virt_l1_sched_simple.c56
-rw-r--r--src/host/virt_phy/src/virt_prim_data.c35
-rw-r--r--src/host/virt_phy/src/virt_prim_fbsb.c32
-rw-r--r--src/host/virt_phy/src/virt_prim_pm.c17
-rw-r--r--src/host/virt_phy/src/virt_prim_rach.c33
-rw-r--r--src/host/virt_phy/src/virt_prim_traffic.c40
-rw-r--r--src/host/virt_phy/src/virtphy.c53
16 files changed, 384 insertions, 424 deletions
diff --git a/src/host/virt_phy/include/virtphy/gsmtapl1_if.h b/src/host/virt_phy/include/virtphy/gsmtapl1_if.h
index d8a43671..125ec111 100644
--- a/src/host/virt_phy/include/virtphy/gsmtapl1_if.h
+++ b/src/host/virt_phy/include/virtphy/gsmtapl1_if.h
@@ -9,8 +9,4 @@
void gsmtapl1_init(struct l1_model_ms *model);
void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
struct msgb *msg);
-void gsmtapl1_rx_from_virt_um(struct msgb *msg);
-void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui, struct msgb *msg);
-void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg);
-void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
- uint8_t *link_id);
+void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, struct msgb *msg);
diff --git a/src/host/virt_phy/include/virtphy/l1ctl_sap.h b/src/host/virt_phy/include/virtphy/l1ctl_sap.h
index b84c3e9e..5903a02d 100644
--- a/src/host/virt_phy/include/virtphy/l1ctl_sap.h
+++ b/src/host/virt_phy/include/virtphy/l1ctl_sap.h
@@ -27,17 +27,11 @@
void l1ctl_sap_init(struct l1_model_ms *model);
-void prim_rach_init(struct l1_model_ms *model);
-void prim_data_init(struct l1_model_ms *model);
-void prim_traffic_init(struct l1_model_ms *model);
-void prim_fbsb_init(struct l1_model_ms *model);
void prim_pm_init(struct l1_model_ms *model);
-void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg);
-void l1ctl_sap_tx_to_l23(struct msgb *msg);
-void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi,
- struct msgb *msg);
+void l1ctl_sap_tx_to_l23_inst(struct l1_model_ms *model, struct msgb *msg);
+void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_client *lsc, struct msgb *msg);
void l1ctl_sap_rx_from_l23(struct msgb *msg);
-void l1ctl_sap_handler(struct msgb *msg);
+void l1ctl_sap_handler(struct l1_model_ms *ms, struct msgb *msg);
/* utility methods */
struct msgb *l1ctl_msgb_alloc(uint8_t msg_type);
@@ -45,39 +39,39 @@ struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
uint16_t arfcn);
/* receive routines */
-void l1ctl_rx_fbsb_req(struct msgb *msg);
-void l1ctl_rx_dm_est_req(struct msgb *msg);
-void l1ctl_rx_dm_rel_req(struct msgb *msg);
-void l1ctl_rx_param_req(struct msgb *msg);
-void l1ctl_rx_dm_freq_req(struct msgb *msg);
-void l1ctl_rx_crypto_req(struct msgb *msg);
-void l1ctl_rx_rach_req(struct msgb *msg);
-void l1ctl_rx_data_req(struct msgb *msg);
-void l1ctl_rx_pm_req(struct msgb *msg);
-void l1ctl_rx_reset_req(struct msgb *msg);
-void l1ctl_rx_ccch_mode_req(struct msgb *msg);
-void l1ctl_rx_tch_mode_req(struct msgb *msg);
-void l1ctl_rx_neigh_pm_req(struct msgb *msg);
-void l1ctl_rx_traffic_req(struct msgb *msg);
-void l1ctl_rx_sim_req(struct msgb *msg);
+void l1ctl_rx_fbsb_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_dm_est_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_dm_rel_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_param_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_dm_freq_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_crypto_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_rach_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_data_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_pm_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_reset_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_ccch_mode_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_tch_mode_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_neigh_pm_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_traffic_req(struct l1_model_ms *, struct msgb *msg);
+void l1ctl_rx_sim_req(struct l1_model_ms *, struct msgb *msg);
/* transmit routines */
-void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type);
-void l1ctl_tx_rach_conf(uint32_t fn, uint16_t arfcn);
-void l1ctl_tx_data_conf(uint32_t fn, uint16_t snr, uint16_t arfcn);
-void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
+void l1ctl_tx_reset(struct l1_model_ms *, uint8_t msg_type, uint8_t reset_type);
+void l1ctl_tx_rach_conf(struct l1_model_ms *, uint32_t fn, uint16_t arfcn);
+void l1ctl_tx_data_conf(struct l1_model_ms *, uint32_t fn, uint16_t snr, uint16_t arfcn);
+void l1ctl_tx_data_ind(struct l1_model_ms *, struct msgb *msg, uint16_t arfcn, uint8_t link_id,
uint8_t chan_nr, uint32_t fn, uint8_t snr,
uint8_t signal_dbm, uint8_t num_biterr,
uint8_t fire_crc);
-void l1ctl_tx_traffic_conf(uint32_t fn, uint16_t snr, uint16_t arfcn);
-void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
+void l1ctl_tx_traffic_conf(struct l1_model_ms *, uint32_t fn, uint16_t snr, uint16_t arfcn);
+void l1ctl_tx_traffic_ind(struct l1_model_ms *, struct msgb *msg, uint16_t arfcn, uint8_t link_id,
uint8_t chan_nr, uint32_t fn, uint8_t snr,
uint8_t signal_dbm, uint8_t num_biterr,
uint8_t fire_crc);
-void l1ctl_tx_pm_conf(struct l1ctl_pm_req *pm_req);
-void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn);
-void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode);
-void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode);
+void l1ctl_tx_pm_conf(struct l1_model_ms *, struct l1ctl_pm_req *pm_req);
+void l1ctl_tx_fbsb_conf(struct l1_model_ms *, uint8_t res, uint16_t arfcn);
+void l1ctl_tx_ccch_mode_conf(struct l1_model_ms *, uint8_t ccch_mode);
+void l1ctl_tx_tch_mode_conf(struct l1_model_ms *, uint8_t tch_mode, uint8_t audio_mode);
/* scheduler functions */
uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
diff --git a/src/host/virt_phy/include/virtphy/l1ctl_sock.h b/src/host/virt_phy/include/virtphy/l1ctl_sock.h
index 8c96dc89..82ee5caf 100644
--- a/src/host/virt_phy/include/virtphy/l1ctl_sock.h
+++ b/src/host/virt_phy/include/virtphy/l1ctl_sock.h
@@ -1,17 +1,33 @@
#pragma once
#include <osmocom/core/msgb.h>
+#include <osmocom/core/linuxlist.h>
#include <osmocom/core/select.h>
#define L1CTL_SOCK_PATH "/tmp/osmocom_l2"
+struct l1ctl_sock_inst;
+
+struct l1ctl_sock_client {
+ /* list head in l1ctl_sock_inst.clients */
+ struct llist_head list;
+ /* pointer back to the server socket that accepted us */
+ struct l1ctl_sock_inst *l1ctl_sock;
+ /* Osmo FD for the client socket */
+ struct osmo_fd ofd;
+ /* private data, can be set in accept_cb */
+ void *priv;
+};
+
/* L1CTL socket instance contains socket data. */
struct l1ctl_sock_inst {
void *priv; /* Will be appended after osmo-fd's data pointer. */
- struct osmo_fd connection; /* L1CTL connection to l2 app */
+ struct llist_head clients;
char* l1ctl_sock_path; /* Socket path used to connect to l23 */
struct osmo_fd ofd; /* Osmocom file descriptor to accept L1CTL connections. */
- void (*recv_cb)(struct l1ctl_sock_inst *vui, struct msgb *msg); /* Callback function called for incoming data from l2 app. */
+ void (*recv_cb)(struct l1ctl_sock_client *lsc, struct msgb *msg); /* Callback function called for incoming data from l2 app. */
+ /* Callback function called for new client after accept() */
+ int (*accept_cb)(struct l1ctl_sock_client *lsc);
};
/**
@@ -19,20 +35,16 @@ struct l1ctl_sock_inst {
*/
struct l1ctl_sock_inst *l1ctl_sock_init(
void *ctx,
- void (*recv_cb)(struct l1ctl_sock_inst *lsi, struct msgb *msg),
+ void (*recv_cb)(struct l1ctl_sock_client *lsc, struct msgb *msg),
+ int (*accept_cb)(struct l1ctl_sock_client *lsc),
char *path);
/**
* @brief Transmit message to l2.
*/
-int l1ctl_sock_write_msg(struct l1ctl_sock_inst *lsi, struct msgb *msg);
+int l1ctl_sock_write_msg(struct l1ctl_sock_client *lsc, struct msgb *msg);
/**
* @brief Destroy instance.
*/
-void l1ctl_sock_destroy();
-
-/**
- * @brief Disconnect current connection.
- */
-void l1ctl_sock_disconnect(struct l1ctl_sock_inst *lsi);
+void l1ctl_sock_destroy(struct l1ctl_sock_inst *lsi);
diff --git a/src/host/virt_phy/include/virtphy/virt_l1_model.h b/src/host/virt_phy/include/virtphy/virt_l1_model.h
index 61776ecf..0cb53815 100644
--- a/src/host/virt_phy/include/virtphy/virt_l1_model.h
+++ b/src/host/virt_phy/include/virtphy/virt_l1_model.h
@@ -45,6 +45,10 @@ struct l1_state_ms {
struct gsm_time downlink_time; /* current GSM time received on downlink */
struct gsm_time current_time; /* GSM time used internally for scheduling */
+ struct {
+ uint32_t last_exec_fn;
+ struct llist_head mframe_items;
+ } sched;
enum ms_state state;
@@ -89,13 +93,16 @@ struct l1_state_ms {
};
struct l1_model_ms {
- struct l1ctl_sock_inst *lsi;
+ /* pointer to the L1CTL socket client associated with this specific MS */
+ struct l1ctl_sock_client *lsc;
+ /* pointer to the (shared) GSMTAP/VirtUM socket to talk to BTS(s) */
struct virt_um_inst *vui;
+ /* actual per-MS state */
struct l1_state_ms state;
};
-struct l1_model_ms *l1_model_ms_init(void *ctx);
+struct l1_model_ms *l1_model_ms_init(void *ctx, struct l1ctl_sock_client *lsc, struct virt_um_inst *vui);
void l1_model_ms_destroy(struct l1_model_ms *model);
diff --git a/src/host/virt_phy/include/virtphy/virt_l1_sched.h b/src/host/virt_phy/include/virtphy/virt_l1_sched.h
index de085508..f3e9b849 100644
--- a/src/host/virt_phy/include/virtphy/virt_l1_sched.h
+++ b/src/host/virt_phy/include/virtphy/virt_l1_sched.h
@@ -5,7 +5,9 @@
#include <osmocom/gsm/gsm_utils.h>
#include <virtphy/virt_l1_sched.h>
-typedef void virt_l1_sched_cb(uint32_t fn, struct msgb * msg);
+struct l1_model_ms;
+
+typedef void virt_l1_sched_cb(struct l1_model_ms *ms, uint32_t fn, struct msgb * msg);
/* bucket containing items to be executed for a specific mframe number */
struct virt_l1_sched_mframe_item {
@@ -22,11 +24,9 @@ struct virt_l1_sched_tdma_item {
virt_l1_sched_cb * handler_cb; /* handler callback */
};
-void virt_l1_sched_init(struct l1_model_ms * model);
-int virt_l1_sched_start(struct gsm_time time);
-int virt_l1_sched_restart(struct gsm_time time);
-void virt_l1_sched_sync_time(struct gsm_time time, uint8_t hard_reset);
-void virt_l1_sched_stop();
-void virt_l1_sched_execute(uint32_t fn);
-void virt_l1_sched_schedule(struct msgb * msg, uint32_t fn, uint8_t ts,
+int virt_l1_sched_restart(struct l1_model_ms *ms, struct gsm_time time);
+void virt_l1_sched_sync_time(struct l1_model_ms *ms, struct gsm_time time, uint8_t hard_reset);
+void virt_l1_sched_stop(struct l1_model_ms *ms);
+void virt_l1_sched_execute(struct l1_model_ms *ms, uint32_t fn);
+void virt_l1_sched_schedule(struct l1_model_ms *ms, struct msgb *msg, uint32_t fn, uint8_t ts,
virt_l1_sched_cb * handler_cb);
diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index 18580b4c..dfcd5a84 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -1,6 +1,7 @@
/* GSMTAP layer1 is transmits gsmtap messages over a virtual layer 1.*/
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -38,24 +39,16 @@
#include <virtphy/logging.h>
#include <virtphy/virt_l1_sched.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-
-void gsmtapl1_init(struct l1_model_ms *model)
-{
- l1_model_ms = model;
-}
-
/**
* Replace l11 header of given msgb by a gsmtap header and send it over the virt um.
*/
-void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui,
- struct msgb *msg)
+void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct gsmtap_hdr *gh;
struct msgb *outmsg; /* msg to send with gsmtap header prepended */
- uint16_t arfcn = l1_model_ms->state.serving_cell.arfcn; /* arfcn of the cell we currently camp on */
+ uint16_t arfcn = ms->state.serving_cell.arfcn; /* arfcn of the cell we currently camp on */
uint8_t signal_dbm = 63; /* signal strength */
uint8_t snr = 63; /* signal noise ratio, 63 is best */
uint8_t *data = msgb_l2(msg); /* data to transmit (whole message without l1 header) */
@@ -76,7 +69,7 @@ void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui,
if (outmsg) {
outmsg->l1h = msgb_data(outmsg);
gh = msgb_l1(outmsg);
- if (virt_um_write_msg(l1_model_ms->vui, outmsg) == -1) {
+ if (virt_um_write_msg(ms->vui, outmsg) == -1) {
LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not send to virt um - "
"(arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
gh->arfcn, gh->type, gh->sub_type, gh->timeslot,
@@ -95,86 +88,44 @@ void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui,
}
/**
- * @see void gsmtapl1_tx_to_virt_um(struct virt_um_inst *vui, uint32_t fn, struct msgb *msg).
- */
-void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg)
-{
- gsmtapl1_tx_to_virt_um_inst(fn, l1_model_ms->vui, msg);
-}
-
-/**
* @see virt_prim_fbsb.c
*/
-extern void prim_fbsb_sync(struct msgb *msg);
+extern void prim_fbsb_sync(struct l1_model_ms *ms, struct msgb *msg);
/**
* @see virt_prim_pm.c
*/
-extern uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev);
+extern uint16_t prim_pm_set_sig_strength(struct l1_model_ms *ms, uint16_t arfcn, int16_t sig_lev);
-/**
- * Receive a gsmtap message from the virt um.
- *
- * As we do not have a downlink scheduler, but not all dl messages must be processed and thus forwarded to l2, this function also implements some message filtering.
- * E.g. we do not forward:
- * - uplink messages
- * - messages with a wrong arfcn
- * - if in MS_STATE_IDLE_SEARCHING
- */
-void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
- struct msgb *msg)
+static void l1ctl_from_virt_um(struct l1ctl_sock_client *lsc, struct msgb *msg, uint32_t fn,
+ uint16_t arfcn, uint8_t timeslot, uint8_t subslot,
+ uint8_t gsmtap_chantype, uint8_t chan_nr, uint8_t link_id,
+ uint8_t snr_db)
{
- if (!msg)
- return;
+ struct l1_model_ms *ms = lsc->priv;
+ uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(ms, arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); /* Power measurement with each received massage */
- struct gsmtap_hdr *gh = msgb_l1(msg);
- uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
- uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
- uint8_t gsmtap_chantype = gh->sub_type; /* gsmtap channel type */
- uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); /* Power measurement with each received massage */
- uint8_t snr = gh->snr_db; /* signal noise ratio */
- uint8_t subslot = gh->sub_slot; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
- uint8_t timeslot = gh->timeslot; /* tdma timeslot to send in (0-7) */
- uint8_t rsl_chantype; /* rsl chan type (8.58, 9.3.1) */
- uint8_t link_id; /* rsl link id tells if this is an ssociated or dedicated link */
- uint8_t chan_nr; /* encoded rsl channel type, timeslot and mf subslot */
+ gsm_fn2gsmtime(&ms->state.downlink_time, fn);
- /* generally ignore all uplink messages received */
- if (arfcn & GSMTAP_ARFCN_F_UPLINK) {
- LOGP(DVIRPHY, LOGL_NOTICE, "Ignoring gsmtap msg from virt um - uplink flag set!\n");
- goto freemsg;
- }
/* we do not forward messages to l23 if we are in network search state */
- if (l1_model_ms->state.state == MS_STATE_IDLE_SEARCHING)
- goto freemsg;
+ if (ms->state.state == MS_STATE_IDLE_SEARCHING)
+ return;
/* forward downlink msg to fbsb sync routine if we are in sync state */
- if (l1_model_ms->state.state == MS_STATE_IDLE_SYNCING) {
- prim_fbsb_sync(msg);
+ if (ms->state.state == MS_STATE_IDLE_SYNCING) {
+ prim_fbsb_sync(ms, msg);
return;
}
/* generally ignore all messages coming from another arfcn than the camped one */
- if (l1_model_ms->state.serving_cell.arfcn != arfcn) {
+ if (ms->state.serving_cell.arfcn != arfcn) {
LOGP(DVIRPHY, LOGL_NOTICE,
"Ignoring gsmtap msg from virt um - msg arfcn=%d not equal synced arfcn=%d!\n",
- arfcn, l1_model_ms->state.serving_cell.arfcn);
- goto freemsg;
+ arfcn, ms->state.serving_cell.arfcn);
+ return;
}
- msg->l2h = msgb_pull(msg, sizeof(*gh));
- chantype_gsmtap2rsl(gsmtap_chantype, &rsl_chantype, &link_id);
- /* see TS 08.58 -> 9.3.1 for channel number encoding */
- chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot);
-
- gsm_fn2gsmtime(&l1_model_ms->state.downlink_time, fn);
- virt_l1_sched_sync_time(l1_model_ms->state.downlink_time, 0);
- virt_l1_sched_execute(fn);
-
- DEBUGP(DVIRPHY, "Receiving gsmtap msg from virt um - "
- "(arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
- arfcn, fn, get_value_string(gsmtap_type_names, gh->type),
- get_value_string(gsmtap_gsm_channel_names, gsmtap_chantype), timeslot,
- subslot, rsl_chantype, link_id, chan_nr);
+ virt_l1_sched_sync_time(ms, ms->state.downlink_time, 0);
+ virt_l1_sched_execute(ms, fn);
/* switch case with removed ACCH flag */
switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
@@ -191,9 +142,9 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
case GSMTAP_CHANNEL_SDCCH8:
/* only forward messages on dedicated channels to l2, if
* the timeslot and subslot is fitting */
- if (l1_model_ms->state.dedicated.tn == timeslot
- && l1_model_ms->state.dedicated.subslot == subslot) {
- l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr, signal_dbm, 0, 0);
+ if (ms->state.dedicated.tn == timeslot
+ && ms->state.dedicated.subslot == subslot) {
+ l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, signal_dbm, 0, 0);
}
break;
case GSMTAP_CHANNEL_AGCH:
@@ -201,7 +152,7 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
case GSMTAP_CHANNEL_BCCH:
/* save to just forward here, as upper layer ignores messages that
* do not fit the current state (e.g. gsm48_rr.c:2159) */
- l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr, signal_dbm, 0, 0);
+ l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, signal_dbm, 0, 0);
break;
case GSMTAP_CHANNEL_RACH:
LOGP(DVIRPHY, LOGL_NOTICE,
@@ -222,15 +173,60 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
"Ignoring gsmtap msg from virt um - channel type unknown.\n");
break;
}
-
-freemsg:
- talloc_free(msg);
}
/**
- * @see void gsmtapl1_rx_from_virt_um_cb(struct virt_um_inst *vui, struct msgb msg).
+ * Receive a gsmtap message from the virt um.
+ *
+ * As we do not have a downlink scheduler, but not all dl messages must be processed and thus forwarded to l2, this function also implements some message filtering.
+ * E.g. we do not forward:
+ * - uplink messages
+ * - messages with a wrong arfcn
+ * - if in MS_STATE_IDLE_SEARCHING
*/
-void gsmtapl1_rx_from_virt_um(struct msgb *msg)
+void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
+ struct msgb *msg)
{
- gsmtapl1_rx_from_virt_um_inst_cb(l1_model_ms->vui, msg);
+ struct l1ctl_sock_inst *lsi = vui->priv;
+ struct l1ctl_sock_client *lsc;
+
+ if (!msg)
+ return;
+
+ struct gsmtap_hdr *gh = msgb_l1(msg);
+ uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
+ uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
+ uint8_t gsmtap_chantype = gh->sub_type; /* gsmtap channel type */
+ uint8_t snr = gh->snr_db; /* signal noise ratio */
+ uint8_t subslot = gh->sub_slot; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
+ uint8_t timeslot = gh->timeslot; /* tdma timeslot to send in (0-7) */
+ uint8_t rsl_chantype; /* rsl chan type (8.58, 9.3.1) */
+ uint8_t link_id; /* rsl link id tells if this is an ssociated or dedicated link */
+ uint8_t chan_nr; /* encoded rsl channel type, timeslot and mf subslot */
+
+ msg->l2h = msgb_pull(msg, sizeof(*gh));
+ chantype_gsmtap2rsl(gsmtap_chantype, &rsl_chantype, &link_id);
+ /* see TS 08.58 -> 9.3.1 for channel number encoding */
+ chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot);
+
+ /* generally ignore all uplink messages received */
+ if (arfcn & GSMTAP_ARFCN_F_UPLINK) {
+ LOGP(DVIRPHY, LOGL_NOTICE, "Ignoring gsmtap msg from virt um - uplink flag set!\n");
+ goto freemsg;
+ }
+
+ DEBUGP(DVIRPHY, "Receiving gsmtap msg from virt um - "
+ "(arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
+ arfcn, fn, get_value_string(gsmtap_type_names, gh->type),
+ get_value_string(gsmtap_gsm_channel_names, gsmtap_chantype), timeslot,
+ subslot, rsl_chantype, link_id, chan_nr);
+
+ /* dispatch the incoming DL message from GSMTAP to each of the registered L1CTL instances */
+ llist_for_each_entry(lsc, &lsi->clients, list) {
+ l1ctl_from_virt_um(lsc, msg, fn, arfcn, timeslot, subslot, gsmtap_chantype,
+ chan_nr, link_id, snr);
+ }
+
+freemsg:
+ talloc_free(msg);
}
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index 8965ac14..be5557d3 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -39,15 +39,13 @@
#include <virtphy/logging.h>
#include <virtphy/virt_l1_sched.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-
-static void l1_model_tch_mode_set(uint8_t tch_mode)
+static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode)
{
if (tch_mode == GSM48_CMODE_SPEECH_V1 || tch_mode == GSM48_CMODE_SPEECH_EFR)
- l1_model_ms->state.tch_mode = tch_mode;
+ ms->state.tch_mode = tch_mode;
else {
/* set default value if no proper mode was assigned by l23 */
- l1_model_ms->state.tch_mode = GSM48_CMODE_SIGN;
+ ms->state.tch_mode = GSM48_CMODE_SIGN;
}
}
@@ -56,11 +54,7 @@ static void l1_model_tch_mode_set(uint8_t tch_mode)
*/
void l1ctl_sap_init(struct l1_model_ms *model)
{
- l1_model_ms = model;
- prim_rach_init(model);
- prim_fbsb_init(model);
- prim_data_init(model);
- prim_traffic_init(model);
+ INIT_LLIST_HEAD(&model->state.sched.mframe_items);
prim_pm_init(model);
}
@@ -69,20 +63,15 @@ void l1ctl_sap_init(struct l1_model_ms *model)
*
* Enqueues the message into the rx queue.
*/
-void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg)
+void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_client *lsc, struct msgb *msg)
{
+ struct l1_model_ms *ms = lsc->priv;
/* check if the received msg is not empty */
- if (msg) {
- DEBUGP(DL1C, "Message incoming from layer 2: %s\n", osmo_hexdump(msg->data, msg->len));
- l1ctl_sap_handler(msg);
- }
-}
-/**
- * @see l1ctl_sap_rx_from_l23_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg).
- */
-void l1ctl_sap_rx_from_l23(struct msgb *msg)
-{
- l1ctl_sap_rx_from_l23_inst_cb(l1_model_ms->lsi, msg);
+ if (!msg)
+ return;
+
+ DEBUGP(DL1C, "Message incoming from layer 2: %s\n", osmo_hexdump(msg->data, msg->len));
+ l1ctl_sap_handler(ms, msg);
}
/**
@@ -90,19 +79,11 @@ void l1ctl_sap_rx_from_l23(struct msgb *msg)
*
* This will forward the message as it is to the upper layer.
*/
-void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg)
+void l1ctl_sap_tx_to_l23_inst(struct l1_model_ms *ms, struct msgb *msg)
{
/* prepend 16bit length before sending */
msgb_push_u16(msg, msg->len);
- l1ctl_sock_write_msg(lsi, msg);
-}
-
-/**
- * @see void l1ctl_sap_tx_to_l23(struct l1ctl_sock_inst *lsi, struct msgb *msg).
- */
-void l1ctl_sap_tx_to_l23(struct msgb *msg)
-{
- l1ctl_sap_tx_to_l23_inst(l1_model_ms->lsi, msg);
+ l1ctl_sock_write_msg(ms->lsc, msg);
}
/**
@@ -170,7 +151,7 @@ struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr, uint16
*
* This handler will call the specific routine dependent on the L1CTL message type.
*/
-void l1ctl_sap_handler(struct msgb *msg)
+void l1ctl_sap_handler(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h;
@@ -186,49 +167,49 @@ void l1ctl_sap_handler(struct msgb *msg)
switch (l1h->msg_type) {
case L1CTL_FBSB_REQ:
- l1ctl_rx_fbsb_req(msg);
+ l1ctl_rx_fbsb_req(ms, msg);
break;
case L1CTL_DM_EST_REQ:
- l1ctl_rx_dm_est_req(msg);
+ l1ctl_rx_dm_est_req(ms, msg);
break;
case L1CTL_DM_REL_REQ:
- l1ctl_rx_dm_rel_req(msg);
+ l1ctl_rx_dm_rel_req(ms, msg);
break;
case L1CTL_PARAM_REQ:
- l1ctl_rx_param_req(msg);
+ l1ctl_rx_param_req(ms, msg);
break;
case L1CTL_DM_FREQ_REQ:
- l1ctl_rx_dm_freq_req(msg);
+ l1ctl_rx_dm_freq_req(ms,msg);
break;
case L1CTL_CRYPTO_REQ:
- l1ctl_rx_crypto_req(msg);
+ l1ctl_rx_crypto_req(ms, msg);
break;
case L1CTL_RACH_REQ:
- l1ctl_rx_rach_req(msg);
+ l1ctl_rx_rach_req(ms, msg);
goto exit_nofree;
case L1CTL_DATA_REQ:
- l1ctl_rx_data_req(msg);
+ l1ctl_rx_data_req(ms, msg);
goto exit_nofree;
case L1CTL_PM_REQ:
- l1ctl_rx_pm_req(msg);
+ l1ctl_rx_pm_req(ms, msg);
break;
case L1CTL_RESET_REQ:
- l1ctl_rx_reset_req(msg);
+ l1ctl_rx_reset_req(ms, msg);
break;
case L1CTL_CCCH_MODE_REQ:
- l1ctl_rx_ccch_mode_req(msg);
+ l1ctl_rx_ccch_mode_req(ms, msg);
break;
case L1CTL_TCH_MODE_REQ:
- l1ctl_rx_tch_mode_req(msg);
+ l1ctl_rx_tch_mode_req(ms, msg);
break;
case L1CTL_NEIGH_PM_REQ:
- l1ctl_rx_neigh_pm_req(msg);
+ l1ctl_rx_neigh_pm_req(ms, msg);
break;
case L1CTL_TRAFFIC_REQ:
- l1ctl_rx_traffic_req(msg);
+ l1ctl_rx_traffic_req(ms, msg);
goto exit_nofree;
case L1CTL_SIM_REQ:
- l1ctl_rx_sim_req(msg);
+ l1ctl_rx_sim_req(ms, msg);
break;
}
@@ -255,7 +236,7 @@ exit_nofree:
* Handle state change from idle to dedicated mode.
*
*/
-void l1ctl_rx_dm_est_req(struct msgb *msg)
+void l1ctl_rx_dm_est_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
@@ -267,16 +248,16 @@ void l1ctl_rx_dm_est_req(struct msgb *msg)
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u, ss=%u)\n",
ul->chan_nr, timeslot, subslot);
- l1_model_ms->state.dedicated.chan_type = rsl_chantype;
- l1_model_ms->state.dedicated.tn = timeslot;
- l1_model_ms->state.dedicated.subslot = subslot;
- l1_model_ms->state.state = MS_STATE_DEDICATED;
+ ms->state.dedicated.chan_type = rsl_chantype;
+ ms->state.dedicated.tn = timeslot;
+ ms->state.dedicated.subslot = subslot;
+ ms->state.state = MS_STATE_DEDICATED;
/* TCH config */
if (rsl_chantype == RSL_CHAN_Bm_ACCHs || rsl_chantype == RSL_CHAN_Lm_ACCHs) {
- l1_model_ms->state.tch_mode = est_req->tch_mode;
- l1_model_tch_mode_set(est_req->tch_mode);
- l1_model_ms->state.audio_mode = est_req->audio_mode;
+ ms->state.tch_mode = est_req->tch_mode;
+ l1_model_tch_mode_set(ms, est_req->tch_mode);
+ ms->state.audio_mode = est_req->audio_mode;
/* TODO: configure audio hardware for encoding /
* decoding / recording / playing voice */
}
@@ -293,7 +274,7 @@ void l1ctl_rx_dm_est_req(struct msgb *msg)
*
* Note: Not needed for virtual physical layer as freqency hopping is generally disabled.
*/
-void l1ctl_rx_dm_freq_req(struct msgb *msg)
+void l1ctl_rx_dm_freq_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
@@ -317,7 +298,7 @@ void l1ctl_rx_dm_freq_req(struct msgb *msg)
* TODO: Implement cryptographic operations for virtual um!
* TODO: Implement this handler routine!
*/
-void l1ctl_rx_crypto_req(struct msgb *msg)
+void l1ctl_rx_crypto_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
@@ -332,8 +313,8 @@ void l1ctl_rx_crypto_req(struct msgb *msg)
return;
}
- l1_model_ms->state.crypto_inf.algo = cr->algo;
- memcpy(l1_model_ms->state.crypto_inf.key, cr->key, sizeof(uint8_t) * A5_KEY_LEN);
+ ms->state.crypto_inf.algo = cr->algo;
+ memcpy(ms->state.crypto_inf.key, cr->key, sizeof(uint8_t) * A5_KEY_LEN);
}
/**
@@ -346,15 +327,15 @@ void l1ctl_rx_crypto_req(struct msgb *msg)
* Handle state change from dedicated to idle mode. Flush message buffers of dedicated channel.
*
*/
-void l1ctl_rx_dm_rel_req(struct msgb *msg)
+void l1ctl_rx_dm_rel_req(struct l1_model_ms *ms, struct msgb *msg)
{
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_DM_REL_REQ\n");
- l1_model_ms->state.dedicated.chan_type = 0;
- l1_model_ms->state.dedicated.tn = 0;
- l1_model_ms->state.dedicated.subslot = 0;
- l1_model_ms->state.tch_mode = GSM48_CMODE_SIGN;
- l1_model_ms->state.state = MS_STATE_IDLE_CAMPING;
+ ms->state.dedicated.chan_type = 0;
+ ms->state.dedicated.tn = 0;
+ ms->state.dedicated.subslot = 0;
+ ms->state.tch_mode = GSM48_CMODE_SIGN;
+ ms->state.state = MS_STATE_IDLE_CAMPING;
/* TODO: disable ciphering */
/* TODO: disable audio recording / playing */
@@ -371,7 +352,7 @@ void l1ctl_rx_dm_rel_req(struct msgb *msg)
*
* Note: Not needed for virtual physical layer.
*/
-void l1ctl_rx_param_req(struct msgb *msg)
+void l1ctl_rx_param_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
@@ -394,7 +375,7 @@ void l1ctl_rx_param_req(struct msgb *msg)
* to just tell l2 that we are rdy.
*
*/
-void l1ctl_rx_reset_req(struct msgb *msg)
+void l1ctl_rx_reset_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_reset *reset_req = (struct l1ctl_reset *) l1h->data;
@@ -402,14 +383,14 @@ void l1ctl_rx_reset_req(struct msgb *msg)
switch (reset_req->type) {
case L1CTL_RES_T_FULL:
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
- l1_model_ms->state.state = MS_STATE_IDLE_SEARCHING;
- virt_l1_sched_stop();
- l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
+ ms->state.state = MS_STATE_IDLE_SEARCHING;
+ virt_l1_sched_stop(ms);
+ l1ctl_tx_reset(ms, L1CTL_RESET_CONF, reset_req->type);
break;
case L1CTL_RES_T_SCHED:
- virt_l1_sched_restart(l1_model_ms->state.downlink_time);
+ virt_l1_sched_restart(ms, ms->state.downlink_time);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
- l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
+ l1ctl_tx_reset(ms, L1CTL_RESET_CONF, reset_req->type);
break;
default:
LOGP(DL1C, LOGL_ERROR, "Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
@@ -430,7 +411,7 @@ void l1ctl_rx_reset_req(struct msgb *msg)
*
* TODO: Implement this handler routine!
*/
-void l1ctl_rx_ccch_mode_req(struct msgb *msg)
+void l1ctl_rx_ccch_mode_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_ccch_mode_req *ccch_mode_req = (struct l1ctl_ccch_mode_req *) l1h->data;
@@ -438,10 +419,10 @@ void l1ctl_rx_ccch_mode_req(struct msgb *msg)
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_CCCH_MODE_REQ\n");
- l1_model_ms->state.serving_cell.ccch_mode = ccch_mode;
+ ms->state.serving_cell.ccch_mode = ccch_mode;
/* check if more has to be done here */
- l1ctl_tx_ccch_mode_conf(ccch_mode);
+ l1ctl_tx_ccch_mode_conf(ms, ccch_mode);
}
/**
@@ -455,20 +436,20 @@ void l1ctl_rx_ccch_mode_req(struct msgb *msg)
*
* TODO: Implement this handler routine!
*/
-void l1ctl_rx_tch_mode_req(struct msgb *msg)
+void l1ctl_rx_tch_mode_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_tch_mode_req *tch_mode_req = (struct l1ctl_tch_mode_req *) l1h->data;
- l1_model_tch_mode_set(tch_mode_req->tch_mode);
- l1_model_ms->state.audio_mode = tch_mode_req->audio_mode;
+ l1_model_tch_mode_set(ms, tch_mode_req->tch_mode);
+ ms->state.audio_mode = tch_mode_req->audio_mode;
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
tch_mode_req->tch_mode, tch_mode_req->audio_mode);
/* TODO: configure audio hardware for encoding / decoding / recording / playing voice */
- l1ctl_tx_tch_mode_conf(l1_model_ms->state.tch_mode, l1_model_ms->state.audio_mode);
+ l1ctl_tx_tch_mode_conf(ms, ms->state.tch_mode, ms->state.audio_mode);
}
/**
@@ -484,7 +465,7 @@ void l1ctl_rx_tch_mode_req(struct msgb *msg)
*
* Note: Not needed for virtual physical layer as we dont maintain neigbors.
*/
-void l1ctl_rx_neigh_pm_req(struct msgb *msg)
+void l1ctl_rx_neigh_pm_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_neigh_pm_req *pm_req = (struct l1ctl_neigh_pm_req *) l1h->data;
@@ -512,7 +493,7 @@ void l1ctl_rx_neigh_pm_req(struct msgb *msg)
* ki comp128 <xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx>
* --------
*/
-void l1ctl_rx_sim_req(struct msgb *msg)
+void l1ctl_rx_sim_req(struct l1_model_ms *ms, struct msgb *msg)
{
uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
@@ -536,7 +517,7 @@ void l1ctl_rx_sim_req(struct msgb *msg)
* @param [in] msg_type L1CTL primitive message type.
* @param [in] reset_type reset type (full, boot or just scheduler reset).
*/
-void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
+void l1ctl_tx_reset(struct l1_model_ms *ms, uint8_t msg_type, uint8_t reset_type)
{
struct msgb *msg = l1ctl_msgb_alloc(msg_type);
struct l1ctl_reset *reset_resp = (struct l1ctl_reset *) msgb_put(msg, sizeof(*reset_resp));
@@ -544,7 +525,7 @@ void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
reset_resp->type = reset_type;
DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n", getL1ctlPrimName(msg_type), reset_type);
- l1ctl_sap_tx_to_l23(msg);
+ l1ctl_sap_tx_to_l23_inst(ms, msg);
}
/**
@@ -556,7 +537,7 @@ void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
*
* Called by layer 1 to inform layer 2 that the ccch mode was successfully changed.
*/
-void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
+void l1ctl_tx_ccch_mode_conf(struct l1_model_ms *ms, uint8_t ccch_mode)
{
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
struct l1ctl_ccch_mode_conf *mode_conf;
@@ -565,7 +546,7 @@ void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
mode_conf->ccch_mode = ccch_mode;
DEBUGP(DL1C, "Sending to l23 - L1CTL_CCCH_MODE_CONF (mode: %u)\n", ccch_mode);
- l1ctl_sap_tx_to_l23(msg);
+ l1ctl_sap_tx_to_l23_inst(ms, msg);
}
/**
@@ -578,7 +559,7 @@ void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
*
* Called by layer 1 to inform layer 23 that the traffic channel mode was successfully changed.
*/
-void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
+void l1ctl_tx_tch_mode_conf(struct l1_model_ms *ms, uint8_t tch_mode, uint8_t audio_mode)
{
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
struct l1ctl_tch_mode_conf *mode_conf;
@@ -589,7 +570,7 @@ void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
DEBUGP(DL1C, "Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n",
tch_mode, audio_mode);
- l1ctl_sap_tx_to_l23(msg);
+ l1ctl_sap_tx_to_l23_inst(ms, msg);
}
/**
diff --git a/src/host/virt_phy/src/l1ctl_sock.c b/src/host/virt_phy/src/l1ctl_sock.c
index 370d3f31..d654c211 100644
--- a/src/host/virt_phy/src/l1ctl_sock.c
+++ b/src/host/virt_phy/src/l1ctl_sock.c
@@ -1,6 +1,7 @@
/* Socket based Layer1 <-> Layer23 communication over L1CTL primitives. */
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -32,24 +33,25 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <arpa/inet.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/select.h>
-#include <osmocom/core/serial.h>
#include <osmocom/core/talloc.h>
-#include <osmocom/core/timer.h>
#include <osmocom/core/socket.h>
-#include <arpa/inet.h>
-
-#include <l1ctl_proto.h>
-
-#include <virtphy/virtual_um.h>
#include <virtphy/l1ctl_sock.h>
#include <virtphy/logging.h>
#define L1CTL_SOCK_MSGB_SIZE 256
+static void l1ctl_client_destroy(struct l1ctl_sock_client *lsc)
+{
+ osmo_fd_close(&lsc->ofd);
+ llist_del(&lsc->list);
+ talloc_free(lsc);
+}
+
/**
* @brief L1CTL socket file descriptor callback function.
*
@@ -60,7 +62,7 @@
*/
static int l1ctl_sock_data_cb(struct osmo_fd *ofd, unsigned int what)
{
- struct l1ctl_sock_inst *lsi = ofd->data;
+ struct l1ctl_sock_client *lsc = ofd->data;
struct l1ctl_hdr *l1h;
struct msgb *msg;
uint16_t len;
@@ -87,44 +89,67 @@ static int l1ctl_sock_data_cb(struct osmo_fd *ofd, unsigned int what)
msgb_put(msg, rc);
l1h = (void *) msgb_data(msg);
msg->l1h = (void *) l1h;
- lsi->recv_cb(lsi, msg);
+ lsc->l1ctl_sock->recv_cb(lsc, msg);
return 0;
}
err_close:
perror("Failed to receive msg from l2. Connection will be closed.\n");
- l1ctl_sock_disconnect(lsi);
+ l1ctl_client_destroy(lsc);
return 0;
}
+/* called for the master (listening) socket of the instance, allocates a new client */
static int l1ctl_sock_accept_cb(struct osmo_fd *ofd, unsigned int what)
{
struct l1ctl_sock_inst *lsi = ofd->data;
- int fd;
+ struct l1ctl_sock_client *lsc;
+ int fd, rc;
fd = accept(ofd->fd, NULL, NULL);
if (fd < 0) {
fprintf(stderr, "Failed to accept connection to l2.\n");
return -1;
}
+ printf("Accepted client (fd=%u) from server (fd=%u)\n", fd, ofd->fd);
- lsi->connection.fd = fd;
- lsi->connection.when = BSC_FD_READ;
- lsi->connection.cb = l1ctl_sock_data_cb;
- lsi->connection.data = lsi;
+ lsc = talloc_zero(lsi, struct l1ctl_sock_client);
+ if (!lsc) {
+ close(fd);
+ fprintf(stderr, "Failed to allocate L1CTL client\n");
+ return -1;
+ }
+
+ lsc->l1ctl_sock = lsi;
+ lsc->ofd.fd = fd;
+ lsc->ofd.when = BSC_FD_READ;
+ lsc->ofd.cb = l1ctl_sock_data_cb;
+ lsc->ofd.data = lsc;
+ if (lsi->accept_cb) {
+ rc = lsi->accept_cb(lsc);
+ if (rc < 0) {
+ talloc_free(lsc);
+ close(fd);
+ return rc;
+ }
+ }
- if (osmo_fd_register(&lsi->connection) != 0) {
+ printf("Accepted L1CTL connection, lsc=%p, lsc->priv=%p\n", lsc, lsc->priv);
+ if (osmo_fd_register(&lsc->ofd) != 0) {
fprintf(stderr, "Failed to register the l2 connection fd.\n");
+ talloc_free(lsc);
return -1;
}
+ llist_add_tail(&lsc->list, &lsi->clients);
return 0;
}
struct l1ctl_sock_inst *l1ctl_sock_init(
void *ctx,
- void (*recv_cb)(struct l1ctl_sock_inst *lsi, struct msgb *msg),
+ void (*recv_cb)(struct l1ctl_sock_client *lsc, struct msgb *msg),
+ int (*accept_cb)(struct l1ctl_sock_client *lsc),
char *path)
{
struct l1ctl_sock_inst *lsi;
@@ -146,40 +171,28 @@ struct l1ctl_sock_inst *l1ctl_sock_init(
}
lsi->recv_cb = recv_cb;
- /* no connection -> invalid filedescriptor and not 0 (==std_in) */
- lsi->connection.fd = -1;
+ lsi->accept_cb = accept_cb;
lsi->l1ctl_sock_path = path;
-
- osmo_fd_register(&lsi->ofd);
+ INIT_LLIST_HEAD(&lsi->clients);
return lsi;
}
void l1ctl_sock_destroy(struct l1ctl_sock_inst *lsi)
{
- struct osmo_fd *ofd = &lsi->ofd;
+ struct l1ctl_sock_client *lsc, *lsc2;
- osmo_fd_unregister(ofd);
- close(ofd->fd);
- ofd->fd = -1;
- ofd->when = 0;
+ llist_for_each_entry_safe(lsc, lsc2, &lsi->clients, list)
+ l1ctl_client_destroy(lsc);
+ osmo_fd_close(&lsi->ofd);
talloc_free(lsi);
}
-void l1ctl_sock_disconnect(struct l1ctl_sock_inst *lsi)
-{
- struct osmo_fd *ofd = &lsi->connection;
- osmo_fd_unregister(ofd);
- close(ofd->fd);
- ofd->fd = -1;
- ofd->when = 0;
-}
-
-int l1ctl_sock_write_msg(struct l1ctl_sock_inst *lsi, struct msgb *msg)
+int l1ctl_sock_write_msg(struct l1ctl_sock_client *lsc, struct msgb *msg)
{
int rc;
- rc = write(lsi->connection.fd, msgb_data(msg), msgb_length(msg));
+ rc = write(lsc->ofd.fd, msgb_data(msg), msgb_length(msg));
msgb_free(msg);
return rc;
}
diff --git a/src/host/virt_phy/src/virt_l1_model.c b/src/host/virt_phy/src/virt_l1_model.c
index 056c9eb0..da0c3147 100644
--- a/src/host/virt_phy/src/virt_l1_model.c
+++ b/src/host/virt_phy/src/virt_l1_model.c
@@ -19,17 +19,24 @@
*/
#include <virtphy/virt_l1_model.h>
+#include <virtphy/l1ctl_sap.h>
#include <talloc.h>
-struct l1_model_ms* l1_model_ms_init(void *ctx)
+struct l1_model_ms *l1_model_ms_init(void *ctx, struct l1ctl_sock_client *lsc, struct virt_um_inst *vui)
{
struct l1_model_ms *model = talloc_zero(ctx, struct l1_model_ms);
+ if (!model)
+ return NULL;
+
+ model->lsc = lsc;
+ model->vui = vui;
+
+ l1ctl_sap_init(model);
+
return model;
}
void l1_model_ms_destroy(struct l1_model_ms *model)
{
- virt_um_destroy(model->vui);
- l1ctl_sock_destroy(model->lsi);
talloc_free(model);
}
diff --git a/src/host/virt_phy/src/virt_l1_sched_simple.c b/src/host/virt_phy/src/virt_l1_sched_simple.c
index 20481df8..7d1cdd47 100644
--- a/src/host/virt_phy/src/virt_l1_sched_simple.c
+++ b/src/host/virt_phy/src/virt_l1_sched_simple.c
@@ -1,4 +1,5 @@
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -24,55 +25,41 @@
#include <time.h>
#include <talloc.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-
-static LLIST_HEAD(mframe_item_list);
-
-static uint32_t last_exec_fn = 0;
-
/**
- * @brief Initialize schedulers data structures.
+ * @brief Start scheduler thread based on current gsm time from model
*/
-void virt_l1_sched_init(struct l1_model_ms *model)
+static int virt_l1_sched_start(struct l1_model_ms *ms, struct gsm_time time)
{
- l1_model_ms = model;
+ virt_l1_sched_sync_time(ms, time, 1);
+ return 0;
}
/**
* @brief Clear scheduler queue and completely restart scheduler.
*/
-int virt_l1_sched_restart(struct gsm_time time)
-{
- virt_l1_sched_stop();
- return virt_l1_sched_start(time);
-}
-
-/**
- * @brief Start scheduler thread based on current gsm time from model
- */
-int virt_l1_sched_start(struct gsm_time time)
+int virt_l1_sched_restart(struct l1_model_ms *ms, struct gsm_time time)
{
- virt_l1_sched_sync_time(time, 1);
- return 0;
+ virt_l1_sched_stop(ms);
+ return virt_l1_sched_start(ms, time);
}
/**
* @brief Sync scheduler with given time.
*/
-void virt_l1_sched_sync_time(struct gsm_time time, uint8_t hard_reset)
+void virt_l1_sched_sync_time(struct l1_model_ms *ms, struct gsm_time time, uint8_t hard_reset)
{
- l1_model_ms->state.current_time = time;
+ ms->state.current_time = time;
}
/**
* @brief Stop the scheduler thread and cleanup mframe items queue
*/
-void virt_l1_sched_stop()
+void virt_l1_sched_stop(struct l1_model_ms *ms)
{
struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
/* Empty tdma and mframe sched items lists */
- llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
+ llist_for_each_entry_safe(mi_next, mi_tmp, &ms->state.sched.mframe_items, mframe_item_entry) {
struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry) {
@@ -87,14 +74,15 @@ void virt_l1_sched_stop()
/**
* @brief Handle all pending scheduled items for the current frame number.
*/
-void virt_l1_sched_execute(uint32_t fn)
+void virt_l1_sched_execute(struct l1_model_ms *ms, uint32_t fn)
{
+ struct l1_state_ms *l1s = &ms->state;
struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
- uint8_t hyperframe_restart = fn < last_exec_fn;
+ uint8_t hyperframe_restart = fn < l1s->sched.last_exec_fn;
- llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
+ llist_for_each_entry_safe(mi_next, mi_tmp, &l1s->sched.mframe_items, mframe_item_entry) {
/* execute all registered handler for current mf sched item */
- uint8_t exec_now = mi_next->fn <= fn || (hyperframe_restart && mi_next->fn > last_exec_fn);
+ uint8_t exec_now = mi_next->fn <= fn || (hyperframe_restart && mi_next->fn > l1s->sched.last_exec_fn);
/* break loop, as we have an ordered list in case the hyperframe had not been reset */
uint8_t break_now = mi_next->fn > fn && !hyperframe_restart;
@@ -106,7 +94,7 @@ void virt_l1_sched_execute(uint32_t fn)
/* exec tdma sched item's handler callback */
/* TODO: we do not have a TDMA scheduler currently and execute
* all scheduled tdma items here at once */
- ti_next->handler_cb(mi_next->fn, ti_next->msg);
+ ti_next->handler_cb(ms, mi_next->fn, ti_next->msg);
/* remove handled tdma sched item */
llist_del(&ti_next->tdma_item_entry);
}
@@ -118,19 +106,19 @@ void virt_l1_sched_execute(uint32_t fn)
if (break_now)
break;
}
- last_exec_fn = fn;
+ l1s->sched.last_exec_fn = fn;
}
/**
* @brief Schedule a msg to the given framenumber and timeslot.
*/
-void virt_l1_sched_schedule(struct msgb * msg, uint32_t fn, uint8_t ts,
- virt_l1_sched_cb * handler_cb)
+void virt_l1_sched_schedule(struct l1_model_ms *ms, struct msgb *msg, uint32_t fn, uint8_t ts,
+ virt_l1_sched_cb *handler_cb)
{
struct virt_l1_sched_mframe_item *mi_next = NULL, *mi_tmp = NULL, *mi_fn = NULL;
struct virt_l1_sched_tdma_item *ti_new = NULL;
- llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
+ llist_for_each_entry_safe(mi_next, mi_tmp, &ms->state.sched.mframe_items, mframe_item_entry) {
if (mi_next->fn == fn) {
mi_fn = mi_next;
break;
diff --git a/src/host/virt_phy/src/virt_prim_data.c b/src/host/virt_phy/src/virt_prim_data.c
index 72c58b7a..4b07ca66 100644
--- a/src/host/virt_phy/src/virt_prim_data.c
+++ b/src/host/virt_phy/src/virt_prim_data.c
@@ -1,7 +1,7 @@
/* Layer 1 normal data burst uplink handling and scheduling */
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010,2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
@@ -38,19 +38,16 @@
#include <l1ctl_proto.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg);
-
/**
* @brief Handler callback function for DATA request.
*
* @param [in] fn frame number
* @param [in] msg the msg to sent over virtual um.
*/
-static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
+static void virt_l1_sched_handler_cb(struct l1_model_ms *ms, uint32_t fn, struct msgb * msg)
{
- gsmtapl1_tx_to_virt_um(fn, msg);
- l1ctl_tx_data_conf(fn, 0, l1_model_ms->state.serving_cell.arfcn);
+ gsmtapl1_tx_to_virt_um_inst(ms, fn, msg);
+ l1ctl_tx_data_conf(ms, fn, 0, ms->state.serving_cell.arfcn);
}
/**
@@ -64,13 +61,13 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
*
* TODO: Check if a msg on FACCH needs special handling.
*/
-void l1ctl_rx_data_req(struct msgb *msg)
+void l1ctl_rx_data_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *)ul->payload;
uint8_t rsl_chantype, subslot, timeslot;
- uint32_t fn_sched = sched_fn_ul(l1_model_ms->state.current_time,
+ uint32_t fn_sched = sched_fn_ul(ms->state.current_time,
ul->chan_nr, ul->link_id);
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
@@ -81,10 +78,10 @@ void l1ctl_rx_data_req(struct msgb *msg)
msg->l2h = data_ind->data;
- virt_l1_sched_schedule(msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
+ virt_l1_sched_schedule(ms, msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
}
-void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
+void l1ctl_tx_data_ind(struct l1_model_ms *ms, struct msgb *msg, uint16_t arfcn, uint8_t link_id,
uint8_t chan_nr, uint32_t fn, uint8_t snr,
uint8_t signal_dbm, uint8_t num_biterr, uint8_t fire_crc)
{
@@ -111,7 +108,7 @@ void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
memcpy(l1di->data, msgb_data(msg), msgb_length(msg));
DEBUGP(DL1C, "Sending signaling-data to l23.\n");
- l1ctl_sap_tx_to_l23(l1ctl_msg);
+ l1ctl_sap_tx_to_l23_inst(ms, l1ctl_msg);
}
/**
@@ -122,20 +119,10 @@ void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
* @param [in] arfcn arfcn of the cell the message was send on
*
*/
-void l1ctl_tx_data_conf(uint32_t fn, uint16_t snr, uint16_t arfcn)
+void l1ctl_tx_data_conf(struct l1_model_ms *ms, uint32_t fn, uint16_t snr, uint16_t arfcn)
{
struct msgb * l1ctl_msg;
l1ctl_msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn, snr, arfcn);
/* send confirm to layer23 */
- l1ctl_sap_tx_to_l23(l1ctl_msg);
-}
-
-/**
- * @brief Initialize virtual prim data.
- *
- * @param [in] model the l1 model instance
- */
-void prim_data_init(struct l1_model_ms *model)
-{
- l1_model_ms = model;
+ l1ctl_sap_tx_to_l23_inst(ms, l1ctl_msg);
}
diff --git a/src/host/virt_phy/src/virt_prim_fbsb.c b/src/host/virt_phy/src/virt_prim_fbsb.c
index 7f998218..59fda353 100644
--- a/src/host/virt_phy/src/virt_prim_fbsb.c
+++ b/src/host/virt_phy/src/virt_prim_fbsb.c
@@ -1,6 +1,6 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010,2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
@@ -35,7 +35,6 @@
#include <virtphy/logging.h>
#include <l1ctl_proto.h>
-static struct l1_model_ms *l1_model_ms = NULL;
static uint16_t sync_count = 0;
/**
@@ -52,9 +51,9 @@ static uint16_t sync_count = 0;
* Note: virt bts does not broadcast freq and sync bursts.
*
*/
-void l1ctl_rx_fbsb_req(struct msgb *msg)
+void l1ctl_rx_fbsb_req(struct l1_model_ms *ms, struct msgb *msg)
{
- struct l1_state_ms *l1s = &l1_model_ms->state;
+ struct l1_state_ms *l1s = &ms->state;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
@@ -70,22 +69,21 @@ void l1ctl_rx_fbsb_req(struct msgb *msg)
*
* Note: for virtual layer 1 this can be a random downlink message, as we can parse the fn from the gsmtap header.
*/
-void prim_fbsb_sync(struct msgb *msg)
+void prim_fbsb_sync(struct l1_model_ms *ms, struct msgb *msg)
{
- struct l1_state_ms *l1s = &l1_model_ms->state;
+ struct l1_state_ms *l1s = &ms->state;
struct gsmtap_hdr *gh = msgb_l1(msg);
uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
/* ignore messages from other arfcns as the one requested to sync to by l23 */
if (l1s->fbsb.arfcn != arfcn) {
- talloc_free(msg);
/* cancel sync if we did not receive a msg on dl from
* the requested arfcn that we can sync to */
if (sync_count++ > 20) {
sync_count = 0;
l1s->state = MS_STATE_IDLE_SEARCHING;
- l1ctl_tx_fbsb_conf(1, (l1s->fbsb.arfcn));
+ l1ctl_tx_fbsb_conf(ms, 1, (l1s->fbsb.arfcn));
}
return;
}
@@ -98,9 +96,8 @@ void prim_fbsb_sync(struct msgb *msg)
/* Update current gsm time each time we receive a message on the virt um */
gsm_fn2gsmtime(&l1s->downlink_time, fn);
/* Restart scheduler */
- virt_l1_sched_restart(l1s->downlink_time);
- talloc_free(msg);
- l1ctl_tx_fbsb_conf(0, arfcn);
+ virt_l1_sched_restart(ms, l1s->downlink_time);
+ l1ctl_tx_fbsb_conf(ms, 0, arfcn);
}
/**
@@ -113,7 +110,7 @@ void prim_fbsb_sync(struct msgb *msg)
*
* No calculation needed for virtual pyh -> uses dummy values for a good link quality.
*/
-void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
+void l1ctl_tx_fbsb_conf(struct l1_model_ms *ms, uint8_t res, uint16_t arfcn)
{
struct msgb *msg;
struct l1ctl_fbsb_conf *resp;
@@ -131,14 +128,5 @@ void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n", getL1ctlPrimName(L1CTL_FBSB_CONF), res);
- l1ctl_sap_tx_to_l23(msg);
-}
-/**
- * @brief Initialize virtual prim pm.
- *
- * @param [in] model the l1 model instance
- */
-void prim_fbsb_init(struct l1_model_ms *model)
-{
- l1_model_ms = model;
+ l1ctl_sap_tx_to_l23_inst(ms, msg);
}
diff --git a/src/host/virt_phy/src/virt_prim_pm.c b/src/host/virt_phy/src/virt_prim_pm.c
index 6335c614..96b7f07c 100644
--- a/src/host/virt_phy/src/virt_prim_pm.c
+++ b/src/host/virt_phy/src/virt_prim_pm.c
@@ -1,6 +1,6 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010,2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
@@ -35,8 +35,6 @@
#include <virtphy/logging.h>
#include <l1ctl_proto.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-
/**
* @brief Change the signal strength for a given arfcn.
*
@@ -45,9 +43,9 @@ static struct l1_model_ms *l1_model_ms = NULL;
* @param [in] arfcn to change sig str for.
* @param [in] sig_lev the measured signal level value.
*/
-uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev)
+uint16_t prim_pm_set_sig_strength(struct l1_model_ms *ms, uint16_t arfcn, int16_t sig_lev)
{
- struct l1_state_ms *l1s = &l1_model_ms->state;
+ struct l1_state_ms *l1s = &ms->state;
if (l1s->pm.timeout_s > 0 || l1s->pm.timeout_us > 0) {
osmo_timer_schedule(&l1s->pm.meas.arfcn_sig_lev_timers[arfcn],
@@ -81,9 +79,9 @@ void prim_pm_timer_cb(void *data)
* Note: This should only be called after a certain time so some
* messages have already been received.
*/
-void l1ctl_rx_pm_req(struct msgb *msg)
+void l1ctl_rx_pm_req(struct l1_model_ms *ms, struct msgb *msg)
{
- struct l1_state_ms *l1s = &l1_model_ms->state;
+ struct l1_state_ms *l1s = &ms->state;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
struct msgb *resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
@@ -110,13 +108,13 @@ void l1ctl_rx_pm_req(struct msgb *msg)
}
/* no more space to hold mor pm info in msgb, flush to l23 */
if (msgb_tailroom(resp_msg) < sizeof(*pm_conf)) {
- l1ctl_sap_tx_to_l23(resp_msg);
+ l1ctl_sap_tx_to_l23_inst(ms, resp_msg);
resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
}
}
/* transmit the remaining part of pm response to l23 */
if (resp_msg)
- l1ctl_sap_tx_to_l23(resp_msg);
+ l1ctl_sap_tx_to_l23_inst(ms, resp_msg);
}
/**
@@ -129,7 +127,6 @@ void prim_pm_init(struct l1_model_ms *model)
struct l1_state_ms *l1s = &model->state;
int i;
- l1_model_ms = model;
/* init the signal level of all arfcns with the lowest value possible */
memset(l1s->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
/* init timers */
diff --git a/src/host/virt_phy/src/virt_prim_rach.c b/src/host/virt_phy/src/virt_prim_rach.c
index bff777d0..88e82064 100644
--- a/src/host/virt_phy/src/virt_prim_rach.c
+++ b/src/host/virt_phy/src/virt_prim_rach.c
@@ -1,7 +1,7 @@
/* Layer 1 Random Access Channel Burst */
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010,2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
@@ -38,9 +38,6 @@
#include <l1ctl_proto.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg);
-
/* use if we have a combined uplink (RACH, SDCCH, ...) (see
* http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html)
* if we have no combined channel config, uplink consists of only RACH * */
@@ -59,10 +56,10 @@ static const uint8_t rach_to_t3_comb[27] = {
*
* @param [in] msg the msg to sent over virtual um.
*/
-static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb *msg)
+static void virt_l1_sched_handler_cb(struct l1_model_ms *ms, uint32_t fn, struct msgb *msg)
{
- gsmtapl1_tx_to_virt_um(fn, msg);
- l1ctl_tx_rach_conf(fn, l1_model_ms->state.serving_cell.arfcn);
+ gsmtapl1_tx_to_virt_um_inst(ms, fn, msg);
+ l1ctl_tx_rach_conf(ms, fn, ms->state.serving_cell.arfcn);
}
/**
@@ -75,9 +72,9 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb *msg)
* Transmit RACH request on RACH. Refer to 04.08 - 9.1.8 - Channel request.
*
*/
-void l1ctl_rx_rach_req(struct msgb *msg)
+void l1ctl_rx_rach_req(struct l1_model_ms *ms, struct msgb *msg)
{
- struct l1_state_ms *l1s = &l1_model_ms->state;
+ struct l1_state_ms *l1s = &ms->state;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
@@ -111,7 +108,7 @@ void l1ctl_rx_rach_req(struct msgb *msg)
} else
fn_sched = l1s->current_time.fn + offset;
- virt_l1_sched_schedule(msg, fn_sched, ts, &virt_l1_sched_handler_cb);
+ virt_l1_sched_schedule(ms, msg, fn_sched, ts, &virt_l1_sched_handler_cb);
}
/**
@@ -122,21 +119,11 @@ void l1ctl_rx_rach_req(struct msgb *msg)
* @param [in] fn the fn on which the rach was sent
* @param [in] arfcn arfcn on which the rach was sent
*/
-void l1ctl_tx_rach_conf(uint32_t fn, uint16_t arfcn)
+void l1ctl_tx_rach_conf(struct l1_model_ms *ms, uint32_t fn, uint16_t arfcn)
{
- struct msgb * msg = l1ctl_create_l2_msg(L1CTL_RACH_CONF, fn, 0, arfcn);
+ struct msgb *msg = l1ctl_create_l2_msg(L1CTL_RACH_CONF, fn, 0, arfcn);
DEBUGP(DL1C, "Sending to l23 - %s (fn: %u, arfcn: %u)\n",
getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn);
- l1ctl_sap_tx_to_l23(msg);
-}
-
-/**
- * @brief Initialize virtual prim rach.
- *
- * @param [in] model the l1 model instance
- */
-void prim_rach_init(struct l1_model_ms *model)
-{
- l1_model_ms = model;
+ l1ctl_sap_tx_to_l23_inst(ms, msg);
}
diff --git a/src/host/virt_phy/src/virt_prim_traffic.c b/src/host/virt_phy/src/virt_prim_traffic.c
index acfd493e..9e87db9a 100644
--- a/src/host/virt_phy/src/virt_prim_traffic.c
+++ b/src/host/virt_phy/src/virt_prim_traffic.c
@@ -1,7 +1,7 @@
/* Layer 1 normal data burst tx handling */
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010,2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
@@ -38,19 +38,16 @@
#include <l1ctl_proto.h>
-static struct l1_model_ms *l1_model_ms = NULL;
-static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg);
-
/**
* @brief Handler callback function for TRAFFIC request.
*
* @param [in] fn frame number
* @param [in] msg the msg to sent over virtual um.
*/
-static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
+static void virt_l1_sched_handler_cb(struct l1_model_ms *ms, uint32_t fn, struct msgb * msg)
{
- gsmtapl1_tx_to_virt_um(fn, msg);
- l1ctl_tx_traffic_conf(fn, 0, l1_model_ms->state.serving_cell.arfcn);
+ gsmtapl1_tx_to_virt_um_inst(ms, fn, msg);
+ l1ctl_tx_traffic_conf(ms, fn, 0, ms->state.serving_cell.arfcn);
}
/**
@@ -63,26 +60,25 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
* Enqueue the message (traffic frame) to the L1 state machine's transmit queue. In virtual layer1 just submit it to the virt um.
*
*/
-void l1ctl_rx_traffic_req(struct msgb *msg)
+void l1ctl_rx_traffic_req(struct l1_model_ms *ms, struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *) ul->payload;
uint8_t rsl_chantype, subslot, timeslot;
- uint32_t fn_sched = sched_fn_ul(l1_model_ms->state.current_time, ul->chan_nr, ul->link_id);
+ uint32_t fn_sched = sched_fn_ul(ms->state.current_time, ul->chan_nr, ul->link_id);
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n");
msg->l2h = tr->data;
- virt_l1_sched_schedule(msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
+ virt_l1_sched_schedule(ms, msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
}
-void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
- uint8_t chan_nr, uint32_t fn, uint8_t snr,
- uint8_t signal_dbm, uint8_t num_biterr,
- uint8_t fire_crc)
+void l1ctl_tx_traffic_ind(struct l1_model_ms *ms, struct msgb *msg, uint16_t arfcn, uint8_t link_id,
+ uint8_t chan_nr, uint32_t fn, uint8_t snr, uint8_t signal_dbm,
+ uint8_t num_biterr, uint8_t fire_crc)
{
struct msgb *l1ctl_msg = NULL;
struct l1ctl_traffic_ind * l1ti;
@@ -107,7 +103,7 @@ void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
memcpy(l1ti->data, msgb_data(msg), msgb_length(msg));
DEBUGP(DL1C, "Sending to l23 - L1CTL_TRAFFIC_IND\n");
- l1ctl_sap_tx_to_l23(l1ctl_msg);
+ l1ctl_sap_tx_to_l23_inst(ms, l1ctl_msg);
}
/**
@@ -118,20 +114,10 @@ void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
* @param [in] arfcn arfcn of the cell the message was send on
*
*/
-void l1ctl_tx_traffic_conf(uint32_t fn, uint16_t snr, uint16_t arfcn)
+void l1ctl_tx_traffic_conf(struct l1_model_ms *ms, uint32_t fn, uint16_t snr, uint16_t arfcn)
{
struct msgb * l1ctl_msg;
l1ctl_msg = l1ctl_create_l2_msg(L1CTL_TRAFFIC_CONF, fn, snr, arfcn);
/* send confirm to layer23 */
- l1ctl_sap_tx_to_l23(l1ctl_msg);
-}
-
-/**
- * @brief Initialize virtual prim traffic.
- *
- * @param [in] model the l1 model instance
- */
-void prim_traffic_init(struct l1_model_ms *model)
-{
- l1_model_ms = model;
+ l1ctl_sap_tx_to_l23_inst(ms, l1ctl_msg);
}
diff --git a/src/host/virt_phy/src/virtphy.c b/src/host/virt_phy/src/virtphy.c
index 28dd685b..c7e11ca6 100644
--- a/src/host/virt_phy/src/virtphy.c
+++ b/src/host/virt_phy/src/virtphy.c
@@ -1,6 +1,7 @@
/* osmocom includes */
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -27,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
+#include <errno.h>
#include <virtphy/virtual_um.h>
#include <virtphy/l1ctl_sock.h>
#include <virtphy/virt_l1_model.h>
@@ -37,6 +39,17 @@
#define DEFAULT_LOG_MASK "DL1C,1:DVIRPHY,1"
+/* this exists once in the program, and contains the state that we
+ * only keep once: L1CTL server socket, GSMTAP/VirtUM socket */
+struct virtphy_context {
+ /* L1CTL socket server */
+ struct l1ctl_sock_inst *l1ctl_sock;
+ /* Virtual Um layer based on GSMTAP multicast */
+ struct virt_um_inst *virt_um;
+};
+
+static struct virtphy_context g_vphy;
+
static char *dl_rx_grp = DEFAULT_MS_MCAST_GROUP;
static char *ul_tx_grp = DEFAULT_BTS_MCAST_GROUP;
static int port = GSMTAP_UDP_PORT;
@@ -132,31 +145,38 @@ void parse_arfcn_sig_lev_red(struct l1_model_ms *model, char * arfcn_sig_lev_red
} while ((token = strtok(NULL, ":")));
}
+/* create a new l1_model_ms instance when L1CTL socket accept()s new connection */
+static int l1ctl_accept_cb(struct l1ctl_sock_client *lsc)
+{
+ struct l1_model_ms *ms = l1_model_ms_init(lsc, lsc, g_vphy.virt_um);
+
+ if (!ms)
+ return -ENOMEM;
+
+ /* apply timeout and arfcn reduction value config to model */
+ parse_pm_timeout(ms, pm_timeout);
+ parse_arfcn_sig_lev_red(ms, arfcn_sig_lev_red_mask);
+
+ lsc->priv = ms;
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
/* init loginfo */
- static struct l1_model_ms *model;
-
handle_options(argc, argv);
ms_log_init(log_mask);
LOGP(DVIRPHY, LOGL_INFO, "Virtual physical layer starting up...\n");
- model = l1_model_ms_init(NULL);
+ g_vphy.virt_um = virt_um_init(NULL, ul_tx_grp, port, dl_rx_grp, port,
+ gsmtapl1_rx_from_virt_um_inst_cb);
- model->vui = virt_um_init(NULL, ul_tx_grp, port, dl_rx_grp, port,
- gsmtapl1_rx_from_virt_um_inst_cb);
- model->lsi = l1ctl_sock_init(NULL, l1ctl_sap_rx_from_l23_inst_cb,
- l1ctl_sock_path);
-
- gsmtapl1_init(model);
- l1ctl_sap_init(model);
- virt_l1_sched_init(model);
-
- /* apply timeout and arfcn reduction value config to model */
- parse_pm_timeout(model, pm_timeout);
- parse_arfcn_sig_lev_red(model, arfcn_sig_lev_red_mask);
+ g_vphy.l1ctl_sock = l1ctl_sock_init(NULL, l1ctl_sap_rx_from_l23_inst_cb,
+ l1ctl_accept_cb, l1ctl_sock_path);
+ g_vphy.virt_um->priv = g_vphy.l1ctl_sock;
LOGP(DVIRPHY, LOGL_INFO,
"Virtual physical layer ready...\n \
@@ -168,7 +188,8 @@ int main(int argc, char *argv[])
osmo_select_main(0);
}
- l1_model_ms_destroy(model);
+ l1ctl_sock_destroy(g_vphy.l1ctl_sock);
+ virt_um_destroy(g_vphy.virt_um);
/* not reached */
return EXIT_FAILURE;