From f5e0f6424b35751d54e82a08f8d6e6de22ddea9a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 19 Jul 2017 11:02:47 +0200 Subject: VIRT-PHY: Major rewrite to deal with muliple L1CTL clients Change-Id: Ibfb2a93f8b45a95215c01368b1a52d92283474e6 --- src/host/virt_phy/src/gsmtapl1_if.c | 158 +++++++++++++-------------- src/host/virt_phy/src/l1ctl_sap.c | 157 ++++++++++++-------------- src/host/virt_phy/src/l1ctl_sock.c | 87 ++++++++------- src/host/virt_phy/src/virt_l1_model.c | 13 ++- src/host/virt_phy/src/virt_l1_sched_simple.c | 56 ++++------ src/host/virt_phy/src/virt_prim_data.c | 35 ++---- src/host/virt_phy/src/virt_prim_fbsb.c | 32 ++---- src/host/virt_phy/src/virt_prim_pm.c | 17 ++- src/host/virt_phy/src/virt_prim_rach.c | 33 ++---- src/host/virt_phy/src/virt_prim_traffic.c | 40 +++---- src/host/virt_phy/src/virtphy.c | 53 ++++++--- 11 files changed, 316 insertions(+), 365 deletions(-) (limited to 'src/host/virt_phy/src') 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 + * (C) 2017 by Harald Welte * * All Rights Reserved * @@ -38,24 +39,16 @@ #include #include -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, @@ -94,87 +87,45 @@ void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui, msgb_free(msg); } -/** - * @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 #include -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 * -------- */ -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 + * (C) 2017 by Harald Welte * * All Rights Reserved * @@ -32,24 +33,25 @@ #include #include #include +#include #include #include -#include #include -#include #include -#include - -#include - -#include #include #include #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 +#include #include -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 + * (C) 2017 by Harald Welte * * All Rights Reserved * @@ -24,55 +25,41 @@ #include #include -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 - * (C) 2010 by Harald Welte + * (C) 2010,2017 by Harald Welte * (C) 2016 by Sebastian Stumpf * * All Rights Reserved @@ -38,19 +38,16 @@ #include -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, ×lot); @@ -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 - * (C) 2010 by Harald Welte + * (C) 2010,2017 by Harald Welte * (C) 2016 by Sebastian Stumpf * * All Rights Reserved @@ -35,7 +35,6 @@ #include #include -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 - * (C) 2010 by Harald Welte + * (C) 2010,2017 by Harald Welte * (C) 2016 by Sebastian Stumpf * * All Rights Reserved @@ -35,8 +35,6 @@ #include #include -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 - * (C) 2010 by Harald Welte + * (C) 2010,2017 by Harald Welte * (C) 2016 by Sebastian Stumpf * * All Rights Reserved @@ -38,9 +38,6 @@ #include -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 - * (C) 2010 by Harald Welte + * (C) 2010,2017 by Harald Welte * (C) 2016 by Sebastian Stumpf * * All Rights Reserved @@ -38,19 +38,16 @@ #include -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, ×lot); 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 + * (C) 2017 by Harald Welte * * All Rights Reserved * @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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; -- cgit v1.2.3