diff options
Diffstat (limited to 'src/host/virt_phy/src')
-rw-r--r-- | src/host/virt_phy/src/Makefile.am | 31 | ||||
-rw-r--r-- | src/host/virt_phy/src/gsmtapl1_if.c | 213 | ||||
-rw-r--r-- | src/host/virt_phy/src/l1ctl_sap.c | 193 | ||||
-rw-r--r-- | src/host/virt_phy/src/l1ctl_sock.c | 15 | ||||
l--------- | src/host/virt_phy/src/l1gprs.c | 1 | ||||
-rw-r--r-- | src/host/virt_phy/src/logging.c | 120 | ||||
-rw-r--r-- | src/host/virt_phy/src/shared/osmo_mcast_sock.c | 12 | ||||
-rw-r--r-- | src/host/virt_phy/src/shared/virtual_um.c | 83 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_l1_model.c | 7 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_l1_sched_simple.c | 19 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_prim_data.c | 29 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_prim_fbsb.c | 13 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_prim_pdch.c | 108 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_prim_pm.c | 56 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_prim_rach.c | 40 | ||||
-rw-r--r-- | src/host/virt_phy/src/virt_prim_traffic.c | 39 | ||||
-rw-r--r-- | src/host/virt_phy/src/virtphy.c | 52 |
17 files changed, 531 insertions, 500 deletions
diff --git a/src/host/virt_phy/src/Makefile.am b/src/host/virt_phy/src/Makefile.am index bfd0dfaa..f10639f5 100644 --- a/src/host/virt_phy/src/Makefile.am +++ b/src/host/virt_phy/src/Makefile.am @@ -1,11 +1,28 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_srcdir)/../layer23/include +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include bin_PROGRAMS = virtphy -virtphy_SOURCES = virtphy.c l1ctl_sock.c gsmtapl1_if.c l1ctl_sap.c virt_prim_pm.c virt_prim_fbsb.c virt_prim_rach.c virt_prim_data.c virt_prim_traffic.c virt_l1_sched_simple.c logging.c virt_l1_model.c shared/virtual_um.c shared/osmo_mcast_sock.c -virtphy_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -virtphy_LDFLAGS = -pthread -# debug output -all: - $(info $$AM_CPPFLAGS is [${AM_CPPFLAGS}]) +virtphy_SOURCES = \ + virtphy.c \ + l1gprs.c \ + logging.c \ + gsmtapl1_if.c \ + l1ctl_sock.c \ + l1ctl_sap.c \ + virt_prim_pm.c \ + virt_prim_fbsb.c \ + virt_prim_rach.c \ + virt_prim_data.c \ + virt_prim_pdch.c \ + virt_prim_traffic.c \ + virt_l1_sched_simple.c \ + virt_l1_model.c \ + shared/virtual_um.c \ + shared/osmo_mcast_sock.c \ + $(NULL) + +virtphy_LDADD = \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(NULL) diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c index 2cf9d2dc..ef8d6840 100644 --- a/src/host/virt_phy/src/gsmtapl1_if.c +++ b/src/host/virt_phy/src/gsmtapl1_if.c @@ -20,25 +20,28 @@ * */ +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + #include <osmocom/core/gsmtap.h> #include <osmocom/core/gsmtap_util.h> #include <osmocom/core/utils.h> #include <osmocom/gsm/rsl.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/protocol/gsm_08_58.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/core/msgb.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <l1ctl_proto.h> -#include <virtphy/virtual_um.h> -#include <virtphy/l1ctl_sock.h> -#include <virtphy/virt_l1_model.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/gsmtapl1_if.h> -#include <virtphy/logging.h> -#include <virtphy/virt_l1_sched.h> + +#include <osmocom/bb/virtphy/virtual_um.h> +#include <osmocom/bb/virtphy/l1ctl_sock.h> +#include <osmocom/bb/virtphy/virt_l1_model.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/l1ctl_proto.h> static char *pseudo_lchan_name(uint16_t arfcn, uint8_t ts, uint8_t ss, uint8_t sub_type) { @@ -48,6 +51,29 @@ static char *pseudo_lchan_name(uint16_t arfcn, uint8_t ts, uint8_t ss, uint8_t s return lname; } +/* Return gsmtap_um_voice_type or -1 on error */ +static int get_um_voice_type(enum gsm48_chan_mode tch_mode, uint8_t rsl_chantype) +{ + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: + switch (rsl_chantype) { + case RSL_CHAN_Bm_ACCHs: + return GSMTAP_UM_VOICE_FR; + case RSL_CHAN_Lm_ACCHs: + return GSMTAP_UM_VOICE_HR; + default: + return -1; + } + break; + case GSM48_CMODE_SPEECH_EFR: + return GSMTAP_UM_VOICE_EFR; + case GSM48_CMODE_SPEECH_AMR: + return GSMTAP_UM_VOICE_AMR; + default: + return -1; + } +} + /** * Replace l11 header of given msgb by a gsmtap header and send it over the virt um. */ @@ -57,8 +83,8 @@ void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, uint8_t tn struct l1ctl_info_ul *ul; struct gsmtap_hdr *gh; struct msgb *outmsg; /* msg to send with gsmtap header prepended */ - uint16_t arfcn = ms->state.serving_cell.arfcn; /* arfcn of the cell we currently camp on */ - uint8_t signal_dbm = 63; /* signal strength */ + uint16_t arfcn; + uint8_t signal_dbm = rxlev2dbm(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) */ uint8_t data_len = msgb_l2len(msg); /* length of data */ @@ -68,18 +94,34 @@ void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, uint8_t tn uint8_t timeslot; /* tdma timeslot to send in (0-7) */ uint8_t gsmtap_chan; /* the gsmtap channel */ + if (ms->state.state == MS_STATE_DEDICATED) + arfcn = ms->state.dedicated.band_arfcn; + else + arfcn = ms->state.serving_cell.arfcn; + switch (l1h->msg_type) { - case L1CTL_DATA_TBF_REQ: - ul = NULL; - rsl_chantype = RSL_CHAN_OSMO_PDCH; + case L1CTL_GPRS_UL_BLOCK_REQ: + gsmtap_chan = GSMTAP_CHANNEL_PDCH; timeslot = tn; subslot = 0; - gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, 0); + break; + case L1CTL_TRAFFIC_REQ: + ul = (struct l1ctl_info_ul *)l1h->data; + rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot); + gsmtap_chan = chantype_rsl2gsmtap2(rsl_chantype, 0, true); + /* the first byte indicates the type of voice codec (gsmtap_um_voice_type); + * let's first strip any data in front of the l2 header, then push this extra + * byte to the front and finally adjust the l2h pointer */ + msgb_pull_to_l2(msg); + msgb_push_u8(msg, get_um_voice_type(ms->state.tch_mode, rsl_chantype)); + msg->l2h = msg->data; + data = msgb_l2(msg); + data_len = msgb_l2len(msg); break; default: ul = (struct l1ctl_info_ul *)l1h->data; rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot); - gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, ul->link_id); + gsmtap_chan = chantype_rsl2gsmtap2(rsl_chantype, ul->link_id, false); break; } @@ -116,100 +158,34 @@ extern void prim_fbsb_sync(struct l1_model_ms *ms, struct msgb *msg); */ extern uint16_t prim_pm_set_sig_strength(struct l1_model_ms *ms, uint16_t arfcn, int16_t sig_lev); -/* determine if a received Downlink RLC/MAC block matches the current MS configuration */ -static bool gprs_dl_block_matches_ms(struct l1_model_ms *ms, struct msgb *msg, uint8_t timeslot) -{ - uint8_t payload_type; - uint8_t tfi; - - if (msgb_length(msg) < 1) - return false; - - /* FIXME: Ensure this will also work for EGPRS! */ - payload_type = msg->data[0] >> 6; - switch (payload_type) { - case 0: /* RLC Data Block */ - /* forward all RLD Data Blocks destined for TFI of MS */ - tfi = (msg->data[1] >> 1) & 0x1f; - if (ms->state.state == MS_STATE_TBF && ms->state.tbf.dl.tfi[timeslot] == tfi) - return true; - break; - case 1: /* RLC/MAC Control without optional octets */ - /* forward all RLC/MAC control blocks without optional octets, i.e. not adressed - * to a specific TFI */ - return true; - case 2: /* RLC/MAC with optional control octets */ - /* forward all RLD Control Blocks destined for TFI of MS */ - tfi = (msg->data[2] >> 1) & 0x1f; - if (ms->state.state == MS_STATE_TBF && ms->state.tbf.dl.tfi[timeslot] == tfi) - return true; - break; - default: - break; - } - return false; -} - -/* determine if given USF at given timeslot is relevant to given MS or not */ -static bool usf_matches_ms(struct l1_model_ms *ms, uint8_t usf, uint8_t timeslot) -{ - if (ms->state.state == MS_STATE_TBF && ms->state.tbf.ul.usf[timeslot] == usf) - return true; - - return false; -} - -/* extract USF from (E)GPRS RLC/MAC block */ -static uint8_t get_usf_from_block(struct msgb *msg) -{ - /* FIXME: Ensure this will also work for EGPRS! */ - return msg->data[0] & 0x7; -} - -/* MS is authorized to transmit a block in uplink for given USF on timeslot+arfcn at FN */ -static void ms_ul_tbf_may_transmit(struct l1_model_ms *ms, uint16_t arfcn, uint8_t timeslot, - uint32_t fn, uint8_t usf) -{ - struct msgb *msg; - - /* If USF is not for us, bail out */ - if (!usf_matches_ms(ms, usf, timeslot)) - return; - - /* attempt to de-queue pending msgb for this UL TBF and transmit it */ - msg = msgb_dequeue(&ms->state.tbf.ul.tx_queue); - if (!msg) { - printf("FN=%u, TN=%u, USF=%u: empty tx_queue, not transmitting\n", fn, timeslot, usf); - /* FIXME: send some dummy control frame? */ - } else { - printf("FN=%u, TN=%u, USF=%u: transmitting queued msg\n", fn, timeslot, usf); - gsmtapl1_tx_to_virt_um_inst(ms, fn, timeslot, 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) { 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 */ - uint8_t usf; + uint8_t rxlev = dbm2rxlev(prim_pm_set_sig_strength(ms, arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); gsm_fn2gsmtime(&ms->state.downlink_time, fn); - /* we do not forward messages to l23 if we are in network search state */ - if (ms->state.state == MS_STATE_IDLE_SEARCHING) + switch (ms->state.state) { + case MS_STATE_IDLE_SEARCHING: + /* we do not forward messages to l23 if we are in network search state */ return; - - /* forward downlink msg to fbsb sync routine if we are in sync state */ - if (ms->state.state == MS_STATE_IDLE_SYNCING) { + case MS_STATE_IDLE_SYNCING: + /* forward downlink msg to fbsb sync routine if we are in sync state */ prim_fbsb_sync(ms, msg); return; - } - /* generally ignore all messages coming from another arfcn than the camped one */ - if (ms->state.serving_cell.arfcn != arfcn) { - return; + case MS_STATE_DEDICATED: + /* generally ignore all messages coming from another arfcn than the camped one */ + if (arfcn != ms->state.dedicated.band_arfcn) + return; + break; + default: + /* generally ignore all messages coming from another arfcn than the camped one */ + if (arfcn != ms->state.serving_cell.arfcn) + return; + break; } virt_l1_sched_sync_time(ms, ms->state.downlink_time, 0); @@ -219,44 +195,49 @@ static void l1ctl_from_virt_um(struct l1ctl_sock_client *lsc, struct msgb *msg, switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) { case GSMTAP_CHANNEL_TCH_H: case GSMTAP_CHANNEL_TCH_F: -#if 0 - /* TODO: handle voice */ - if (!facch && !tch_acch) { - l1ctl_tx_traffic_ind(msg, arfcn, link_id, chan_nr, fn, - snr, signal_dbm, 0, 0); - } -#endif + /* This is TCH signalling, for voice frames see GSMTAP_CHANNEL_VOICE */ case GSMTAP_CHANNEL_SDCCH4: case GSMTAP_CHANNEL_SDCCH8: /* only forward messages on dedicated channels to l2, if * the timeslot and subslot is fitting */ 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); + l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, rxlev, 0, 0); } break; + case GSMTAP_CHANNEL_VOICE_F: + case GSMTAP_CHANNEL_VOICE_H: + /* only forward messages on dedicated channels to l2, if + * the timeslot and subslot is fitting */ + if (ms->state.dedicated.tn == timeslot + && ms->state.dedicated.subslot == subslot) { + l1ctl_tx_traffic_ind(ms, msg, arfcn, link_id, chan_nr, fn, + snr_db, rxlev, 0, 0); + } + break; + case GSMTAP_CHANNEL_CBCH51: + /* only pass CBCH data if the user application actually indicated that a CBCH + * is present */ + if (ms->state.serving_cell.ccch_mode != CCCH_MODE_COMBINED_CBCH) + break; case GSMTAP_CHANNEL_AGCH: case GSMTAP_CHANNEL_PCH: case GSMTAP_CHANNEL_BCCH: - case GSMTAP_CHANNEL_CBCH51: case GSMTAP_CHANNEL_CBCH52: /* 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(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, signal_dbm, 0, 0); + l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, rxlev, 0, 0); break; case GSMTAP_CHANNEL_RACH: LOGPMS(DVIRPHY, LOGL_NOTICE, ms, "Ignoring unexpected RACH in downlink ?!?\n"); break; + case GSMTAP_CHANNEL_PTCCH: case GSMTAP_CHANNEL_PACCH: case GSMTAP_CHANNEL_PDCH: - if (gprs_dl_block_matches_ms(ms, msg, timeslot)) - l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, signal_dbm, 0, 0); - usf = get_usf_from_block(msg); - ms_ul_tbf_may_transmit(ms, arfcn, timeslot, fn, usf); + l1ctl_tx_gprs_dl_block_ind(ms, msg, fn, timeslot, rxlev); break; case GSMTAP_CHANNEL_SDCCH: case GSMTAP_CHANNEL_CCCH: - case GSMTAP_CHANNEL_PTCCH: LOGPMS(DVIRPHY, LOGL_NOTICE, ms, "Ignoring unsupported channel type %s\n", get_value_string(gsmtap_gsm_channel_names, gsmtap_chantype)); break; diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c index f95a4caf..7e4540df 100644 --- a/src/host/virt_phy/src/l1ctl_sap.c +++ b/src/host/virt_phy/src/l1ctl_sap.c @@ -19,6 +19,9 @@ * */ +#include <stdio.h> +#include <string.h> +#include <netinet/in.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/msgb.h> @@ -27,21 +30,16 @@ #include <osmocom/gsm/protocol/gsm_08_58.h> #include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/gsm/rsl.h> -#include <osmocom/gprs/gprs_rlc.h> -#include <stdio.h> -#include <l1ctl_proto.h> -#include <netinet/in.h> -#include <string.h> -#include <virtphy/virtual_um.h> -#include <virtphy/l1ctl_sock.h> -#include <virtphy/virt_l1_model.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/gsmtapl1_if.h> -#include <virtphy/logging.h> -#include <virtphy/virt_l1_sched.h> -static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg); -static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg); +#include <osmocom/bb/virtphy/virtual_um.h> +#include <osmocom/bb/virtphy/l1ctl_sock.h> +#include <osmocom/bb/virtphy/virt_l1_model.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/l1ctl_proto.h> +#include <osmocom/bb/l1gprs.h> static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode) { @@ -59,7 +57,6 @@ static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode) void l1ctl_sap_init(struct l1_model_ms *model) { INIT_LLIST_HEAD(&model->state.sched.mframe_items); - INIT_LLIST_HEAD(&model->state.tbf.ul.tx_queue); prim_pm_init(model); } @@ -162,8 +159,8 @@ static bool is_l1ctl_control(uint8_t msg_type) switch (msg_type) { case L1CTL_DATA_REQ: case L1CTL_DATA_CONF: - case L1CTL_DATA_TBF_REQ: - case L1CTL_DATA_TBF_CONF: + case L1CTL_GPRS_UL_BLOCK_REQ: + case L1CTL_GPRS_DL_BLOCK_IND: case L1CTL_TRAFFIC_REQ: case L1CTL_TRAFFIC_CONF: case L1CTL_TRAFFIC_IND: @@ -246,11 +243,12 @@ void l1ctl_sap_handler(struct l1_model_ms *ms, struct msgb *msg) case L1CTL_SIM_REQ: l1ctl_rx_sim_req(ms, msg); break; - case L1CTL_TBF_CFG_REQ: - l1ctl_rx_tbf_cfg_req(ms, msg); + case L1CTL_GPRS_UL_TBF_CFG_REQ: + case L1CTL_GPRS_DL_TBF_CFG_REQ: + l1ctl_rx_gprs_uldl_tbf_cfg_req(ms, msg); break; - case L1CTL_DATA_TBF_REQ: - l1ctl_rx_data_tbf_req(ms, msg); + case L1CTL_GPRS_UL_BLOCK_REQ: + l1ctl_rx_gprs_ul_block_req(ms, msg); goto exit_nofree; } @@ -286,14 +284,22 @@ void l1ctl_rx_dm_est_req(struct l1_model_ms *ms, struct msgb *msg) rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot); - LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u, ss=%u)\n", - ul->chan_nr, timeslot, subslot); + LOGPMS(DL1C, LOGL_DEBUG, ms, "Rx L1CTL_DM_EST_REQ (chan_nr=0x%02x, arfcn=%u, tn=%u, ss=%u)\n", + ul->chan_nr, ntohs(est_req->h0.band_arfcn), timeslot, subslot); + OSMO_ASSERT(est_req->h == 0); /* we don't do hopping */ + ms->state.dedicated.band_arfcn = ntohs(est_req->h0.band_arfcn); ms->state.dedicated.chan_type = rsl_chantype; ms->state.dedicated.tn = timeslot; ms->state.dedicated.subslot = subslot; ms->state.state = MS_STATE_DEDICATED; + if (rsl_chantype == RSL_CHAN_OSMO_PDCH) { + OSMO_ASSERT(ms->gprs == NULL); + ms->gprs = l1gprs_state_alloc(ms, NULL, ms); + OSMO_ASSERT(ms->gprs != NULL); + } + /* TCH config */ if (rsl_chantype == RSL_CHAN_Bm_ACCHs || rsl_chantype == RSL_CHAN_Lm_ACCHs) { ms->state.tch_mode = est_req->tch_mode; @@ -313,7 +319,7 @@ void l1ctl_rx_dm_est_req(struct l1_model_ms *ms, struct msgb *msg) * * Handle frequency change in dedicated mode. E.g. used for frequency hopping. * - * Note: Not needed for virtual physical layer as freqency hopping is generally disabled. + * Note: Not needed for virtual physical layer as frequency hopping is generally disabled. */ void l1ctl_rx_dm_freq_req(struct l1_model_ms *ms, struct msgb *msg) { @@ -378,6 +384,9 @@ void l1ctl_rx_dm_rel_req(struct l1_model_ms *ms, struct msgb *msg) ms->state.tch_mode = GSM48_CMODE_SIGN; ms->state.state = MS_STATE_IDLE_CAMPING; + l1gprs_state_free(ms->gprs); + ms->gprs = NULL; + /* TODO: disable ciphering */ /* TODO: disable audio recording / playing */ } @@ -426,6 +435,8 @@ void l1ctl_rx_reset_req(struct l1_model_ms *ms, struct msgb *msg) DEBUGPMS(DL1C, ms, "Rx L1CTL_RESET_REQ (type=FULL)\n"); ms->state.state = MS_STATE_IDLE_SEARCHING; virt_l1_sched_stop(ms); + l1gprs_state_free(ms->gprs); + ms->gprs = NULL; l1ctl_tx_reset(ms, L1CTL_RESET_CONF, reset_req->type); break; case L1CTL_RES_T_SCHED: @@ -484,6 +495,7 @@ void l1ctl_rx_tch_mode_req(struct l1_model_ms *ms, struct msgb *msg) l1_model_tch_mode_set(ms, tch_mode_req->tch_mode); ms->state.audio_mode = tch_mode_req->audio_mode; + /* TODO: Handle AMR codecs from tch_mode_req if tch_mode_req->tch_mode==GSM48_CMODE_SPEECH_AMR */ LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n", tch_mode_req->tch_mode, tch_mode_req->audio_mode); @@ -504,7 +516,7 @@ void l1ctl_rx_tch_mode_req(struct l1_model_ms *ms, struct msgb *msg) * The neighbor cell description is one of the info messages sent by the BTS on BCCH. * This method will also enable neighbor measurement in the multiframe scheduler. * - * Note: Not needed for virtual physical layer as we dont maintain neigbors. + * Note: Not needed for virtual physical layer as we don't maintain neighbors. */ void l1ctl_rx_neigh_pm_req(struct l1_model_ms *ms, struct msgb *msg) { @@ -543,143 +555,12 @@ void l1ctl_rx_sim_req(struct l1_model_ms *ms, struct msgb *msg) } -static void l1ctl_tx_tbf_cfg_conf(struct l1_model_ms *ms, const struct l1ctl_tbf_cfg_req *in); - -static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg) -{ - struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data; - struct l1ctl_tbf_cfg_req *cfg_req = (struct l1ctl_tbf_cfg_req *) l1h->data; - unsigned int i; - - LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_TBF_CFG_REQ (tbf_id=%u, dir=%s, " - "usf=[%d,%d,%d,%d,%d,%d,%d,%d]\n", cfg_req->tbf_nr, - cfg_req->is_uplink ? "UL" : "DL", cfg_req->usf[0], cfg_req->usf[1], - cfg_req->usf[2], cfg_req->usf[3], cfg_req->usf[4], cfg_req->usf[5], - cfg_req->usf[6], cfg_req->usf[7]); - - if (cfg_req->tbf_nr != 0) { - LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n"); - return; - } - - if (ms->state.state == MS_STATE_DEDICATED) - LOGPMS(DL1C, LOGL_NOTICE, ms, "Hard termination of DEDICATED mode, fix L23!\n"); - - if (cfg_req->is_uplink) { - for (i = 0; i < 8; i++) - ms->state.tbf.ul.usf[i] = cfg_req->usf[i]; - } else { - for (i = 0; i < 8; i++) - ms->state.tbf.dl.tfi[i] = cfg_req->usf[i]; - } - ms->state.state = MS_STATE_TBF; - - l1ctl_tx_tbf_cfg_conf(ms, cfg_req); -} - -static const enum osmo_gprs_cs osmo_cs_by_l1ctl[] = { - [L1CTL_CS_NONE] = OSMO_GPRS_CS_NONE, - [L1CTL_CS1] = OSMO_GPRS_CS1, - [L1CTL_CS2] = OSMO_GPRS_CS2, - [L1CTL_CS3] = OSMO_GPRS_CS3, - [L1CTL_CS4] = OSMO_GPRS_CS4, - [L1CTL_MCS1] = OSMO_GPRS_MCS1, - [L1CTL_MCS2] = OSMO_GPRS_MCS2, - [L1CTL_MCS3] = OSMO_GPRS_MCS3, - [L1CTL_MCS4] = OSMO_GPRS_MCS4, - [L1CTL_MCS5] = OSMO_GPRS_MCS5, - [L1CTL_MCS6] = OSMO_GPRS_MCS6, - [L1CTL_MCS7] = OSMO_GPRS_MCS7, - [L1CTL_MCS8] = OSMO_GPRS_MCS8, - [L1CTL_MCS9] = OSMO_GPRS_MCS9, -}; - -static int get_osmo_cs_by_l1ctl(enum l1ctl_coding_scheme l1) -{ - if (l1 >= ARRAY_SIZE(osmo_cs_by_l1ctl)) - return -1; - return osmo_cs_by_l1ctl[l1]; -} - -static const enum l1ctl_coding_scheme l1ctl_cs_by_osmo[] = { - [OSMO_GPRS_CS_NONE] = L1CTL_CS_NONE, - [OSMO_GPRS_CS1] = L1CTL_CS1, - [OSMO_GPRS_CS2] = L1CTL_CS2, - [OSMO_GPRS_CS3] = L1CTL_CS3, - [OSMO_GPRS_CS4] = L1CTL_CS4, - [OSMO_GPRS_MCS1] = L1CTL_MCS1, - [OSMO_GPRS_MCS2] = L1CTL_MCS2, - [OSMO_GPRS_MCS3] = L1CTL_MCS3, - [OSMO_GPRS_MCS4] = L1CTL_MCS4, - [OSMO_GPRS_MCS5] = L1CTL_MCS5, - [OSMO_GPRS_MCS6] = L1CTL_MCS6, - [OSMO_GPRS_MCS7] = L1CTL_MCS7, - [OSMO_GPRS_MCS8] = L1CTL_MCS8, - [OSMO_GPRS_MCS9] = L1CTL_MCS9, -}; - -static int get_l1ctl_cs_by_osmo(enum osmo_gprs_cs in) -{ - if (in >= ARRAY_SIZE(l1ctl_cs_by_osmo)) - return -1; - return l1ctl_cs_by_osmo[in]; -} - -static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg) -{ - struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data; - struct l1ctl_info_ul_tbf *udt = (struct l1ctl_info_ul_tbf *) l1h->data; - enum osmo_gprs_cs osmo_cs; - int block_size; - - msg->l2h = udt->payload; - - LOGPMS(DL1P, LOGL_ERROR, ms, "Rx L1CTL_DATA_TBF_REQ (tbf_id=%d, data=%s)\n", - udt->tbf_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg))); - if (udt->tbf_nr != 0) { - LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n"); - return; - } - - if (ms->state.state != MS_STATE_TBF) { - LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_TBF_REQ in state != TBF\n"); - return; - } - - osmo_cs = get_l1ctl_cs_by_osmo(udt->coding_scheme); - if (osmo_cs < 0) { - LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_RBF_REQ with invalid CS\n"); - return; - } - block_size = osmo_gprs_ul_block_size_bytes(osmo_cs); - - if (msgb_l2len(msg) < block_size) { - int pad_len = block_size - msgb_l2len(msg); - uint8_t *pad = msgb_put(msg, pad_len); - memset(pad, GSM_MACBLOCK_PADDING, pad_len); - } - - msgb_enqueue(&ms->state.tbf.ul.tx_queue, msg); -} - /*************************************************************** * L1CTL TX ROUTINES ******************************************* * For more routines check the respective handler classes ****** * like virt_prim_rach.c *************************************** ***************************************************************/ -static void l1ctl_tx_tbf_cfg_conf(struct l1_model_ms *ms, const struct l1ctl_tbf_cfg_req *in) -{ - struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TBF_CFG_CONF); - struct l1ctl_tbf_cfg_req *out; - - /* copy over the data from the request */ - out = (struct l1ctl_tbf_cfg_req *) msgb_put(msg, sizeof(*out)); - *out = *in; - - l1ctl_sap_tx_to_l23_inst(ms, msg); -} - /** * @brief Transmit L1CTL_RESET_IND or L1CTL_RESET_CONF to layer 23. * diff --git a/src/host/virt_phy/src/l1ctl_sock.c b/src/host/virt_phy/src/l1ctl_sock.c index bf28895f..089d9caf 100644 --- a/src/host/virt_phy/src/l1ctl_sock.c +++ b/src/host/virt_phy/src/l1ctl_sock.c @@ -40,8 +40,8 @@ #include <osmocom/core/talloc.h> #include <osmocom/core/socket.h> -#include <virtphy/l1ctl_sock.h> -#include <virtphy/logging.h> +#include <osmocom/bb/virtphy/l1ctl_sock.h> +#include <osmocom/bb/virtphy/logging.h> #define L1CTL_SOCK_MSGB_SIZE 256 @@ -72,7 +72,7 @@ static int l1ctl_sock_data_cb(struct osmo_fd *ofd, unsigned int what) int rc; /* Check if request is really read request */ - if (!(what & BSC_FD_READ)) + if (!(what & OSMO_FD_READ)) return 0; msg = msgb_alloc(L1CTL_SOCK_MSGB_SIZE, "L1CTL sock rx"); @@ -125,10 +125,7 @@ static int l1ctl_sock_accept_cb(struct osmo_fd *ofd, unsigned int what) } 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; + osmo_fd_setup(&lsc->ofd, fd, OSMO_FD_READ, l1ctl_sock_data_cb, lsc, 0); if (lsi->accept_cb) { rc = lsi->accept_cb(lsc); if (rc < 0) { @@ -163,9 +160,7 @@ struct l1ctl_sock_inst *l1ctl_sock_init( lsi = talloc_zero(ctx, struct l1ctl_sock_inst); lsi->priv = NULL; - lsi->ofd.data = lsi; - lsi->ofd.when = BSC_FD_READ; - lsi->ofd.cb = l1ctl_sock_accept_cb; + osmo_fd_setup(&lsi->ofd, -1, OSMO_FD_READ, l1ctl_sock_accept_cb, lsi, 0); rc = osmo_sock_unix_init_ofd(&lsi->ofd, SOCK_STREAM, 0, path, OSMO_SOCK_F_BIND); if (rc < 0) { diff --git a/src/host/virt_phy/src/l1gprs.c b/src/host/virt_phy/src/l1gprs.c new file mode 120000 index 00000000..0185f68b --- /dev/null +++ b/src/host/virt_phy/src/l1gprs.c @@ -0,0 +1 @@ +../../../shared/l1gprs.c
\ No newline at end of file diff --git a/src/host/virt_phy/src/logging.c b/src/host/virt_phy/src/logging.c index 7e4e79b1..fc37205f 100644 --- a/src/host/virt_phy/src/logging.c +++ b/src/host/virt_phy/src/logging.c @@ -15,53 +15,49 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <osmocom/core/utils.h> #include <osmocom/core/application.h> -#include <virtphy/logging.h> +#include <osmocom/bb/virtphy/logging.h> static const char* l1ctlPrimNames[] = { - "_L1CTL_NONE", - "L1CTL_FBSB_REQ", - "L1CTL_FBSB_CONF", - "L1CTL_DATA_IND", - "L1CTL_RACH_REQ", - "L1CTL_DM_EST_REQ", - "L1CTL_DATA_REQ", - "L1CTL_RESET_IND", - "L1CTL_PM_REQ", - "L1CTL_PM_CONF", - "L1CTL_ECHO_REQ", - "L1CTL_ECHO_CONF", - "L1CTL_RACH_CONF", - "L1CTL_RESET_REQ", - "L1CTL_RESET_CONF", - "L1CTL_DATA_CONF", - "L1CTL_CCCH_MODE_REQ", - "L1CTL_CCCH_MODE_CONF", - "L1CTL_DM_REL_REQ", - "L1CTL_PARAM_REQ", - "L1CTL_DM_FREQ_REQ", - "L1CTL_CRYPTO_REQ", - "L1CTL_SIM_REQ", - "L1CTL_SIM_CONF", - "L1CTL_TCH_MODE_REQ", - "L1CTL_TCH_MODE_CONF", - "L1CTL_NEIGH_PM_REQ", - "L1CTL_NEIGH_PM_IND", - "L1CTL_TRAFFIC_REQ", - "L1CTL_TRAFFIC_CONF", - "L1CTL_TRAFFIC_IND", - "L1CTL_BURST_IND", - "L1CTL_TBF_CFG_REQ", - "L1CTL_TBF_CFG_CONF", - "L1CTL_DATA_TBF_REQ", - "L1CTL_DATA_TBF_CONF" + "_L1CTL_NONE", + "L1CTL_FBSB_REQ", + "L1CTL_FBSB_CONF", + "L1CTL_DATA_IND", + "L1CTL_RACH_REQ", + "L1CTL_DM_EST_REQ", + "L1CTL_DATA_REQ", + "L1CTL_RESET_IND", + "L1CTL_PM_REQ", + "L1CTL_PM_CONF", + "L1CTL_ECHO_REQ", + "L1CTL_ECHO_CONF", + "L1CTL_RACH_CONF", + "L1CTL_RESET_REQ", + "L1CTL_RESET_CONF", + "L1CTL_DATA_CONF", + "L1CTL_CCCH_MODE_REQ", + "L1CTL_CCCH_MODE_CONF", + "L1CTL_DM_REL_REQ", + "L1CTL_PARAM_REQ", + "L1CTL_DM_FREQ_REQ", + "L1CTL_CRYPTO_REQ", + "L1CTL_SIM_REQ", + "L1CTL_SIM_CONF", + "L1CTL_TCH_MODE_REQ", + "L1CTL_TCH_MODE_CONF", + "L1CTL_NEIGH_PM_REQ", + "L1CTL_NEIGH_PM_IND", + "L1CTL_TRAFFIC_REQ", + "L1CTL_TRAFFIC_CONF", + "L1CTL_TRAFFIC_IND", + "L1CTL_BURST_IND", + "L1CTL_GPRS_UL_TBF_CFG_REQ", + "L1CTL_GPRS_DL_TBF_CFG_REQ", + "L1CTL_GPRS_UL_BLOCK_REQ", + "L1CTL_GPRS_DL_BLOCK_IND", }; static const struct log_info_cat default_categories[] = { @@ -70,28 +66,35 @@ static const struct log_info_cat default_categories[] = { .description = "Layer 1 Control", .color = "\033[1;31m", .enabled = 1, - .loglevel = LOGL_DEBUG, + .loglevel = LOGL_NOTICE, }, [DL1P] = { .name = "DL1P", .description = "Layer 1 Data", .color = "\033[1;31m", .enabled = 1, - .loglevel = LOGL_DEBUG, + .loglevel = LOGL_NOTICE, }, [DVIRPHY] = { .name = "DVIRPHY", .description = "Virtual Layer 1 Interface", .color = "\033[1;31m", .enabled = 1, - .loglevel = LOGL_DEBUG, + .loglevel = LOGL_NOTICE, + }, + [DGPRS] = { + .name = "DGPRS", + .description = "L1 GPRS (MAC leyer)", + .color = "\033[1;31m", + .enabled = 1, + .loglevel = LOGL_NOTICE, }, [DMAIN] = { .name = "DMAIN", .description = "Main Program / Data Structures", .color = "\033[1;32m", .enabled = 1, - .loglevel = LOGL_DEBUG, + .loglevel = LOGL_NOTICE, }, }; @@ -104,24 +107,21 @@ const struct log_info ms_log_info = { /** * Initialize the logging system for the virtual physical layer. */ -int ms_log_init(char *cat_mask) +int ms_log_init(void *ctx, const char *cat_mask) { - struct log_target *stderr_target; + int rc; - log_init(&ms_log_info, NULL); - stderr_target = log_target_create_stderr(); - if (!stderr) - return -1; + rc = osmo_init_logging2(ctx, &ms_log_info); + OSMO_ASSERT(rc == 0); - log_add_target(stderr_target); - log_set_all_filter(stderr_target, 1); - //log_set_log_level(stderr_target, 1); - log_set_print_filename(stderr_target, 1); - log_set_use_color(stderr_target, 0); - log_set_print_timestamp(stderr_target, 1); - log_set_print_category(stderr_target, 1); + //log_set_log_level(osmo_stderr_target, 1); + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_PATH); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_timestamp(osmo_stderr_target, 1); + log_set_print_category_hex(osmo_stderr_target, 0); + log_set_print_category(osmo_stderr_target, 1); if (cat_mask) - log_parse_category_mask(stderr_target, cat_mask); + log_parse_category_mask(osmo_stderr_target, cat_mask); return 0; } @@ -131,5 +131,5 @@ const char *getL1ctlPrimName(uint8_t type) if (type < ARRAY_SIZE(l1ctlPrimNames)) return l1ctlPrimNames[type]; else - return "Unknwon Primitive"; + return "Unknown Primitive"; } diff --git a/src/host/virt_phy/src/shared/osmo_mcast_sock.c b/src/host/virt_phy/src/shared/osmo_mcast_sock.c index 9a713fcf..d3ae4fe9 100644 --- a/src/host/virt_phy/src/shared/osmo_mcast_sock.c +++ b/src/host/virt_phy/src/shared/osmo_mcast_sock.c @@ -1,14 +1,16 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> -#include <osmocom/core/socket.h> -#include <osmocom/core/select.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <talloc.h> #include <unistd.h> -#include <virtphy/osmo_mcast_sock.h> + +#include <osmocom/core/socket.h> +#include <osmocom/core/select.h> + +#include <osmocom/bb/virtphy/osmo_mcast_sock.h> /* server socket is what we use for transmission. It is not subscribed * to a multicast group or locally bound, but it is just a normal UDP @@ -43,9 +45,7 @@ int mcast_client_sock_setup(struct osmo_fd *ofd, const char *mcast_group, uint16 int rc; unsigned int flags = OSMO_SOCK_F_BIND | OSMO_SOCK_F_NO_MCAST_ALL | OSMO_SOCK_F_UDP_REUSEADDR; - ofd->cb = fd_rx_cb; - ofd->when = BSC_FD_READ; - ofd->data = osmo_fd_data; + osmo_fd_setup(ofd, -1, OSMO_FD_READ, fd_rx_cb, osmo_fd_data, 0); /* Create mcast client socket */ rc = osmo_sock_init_ofd(ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, diff --git a/src/host/virt_phy/src/shared/virtual_um.c b/src/host/virt_phy/src/shared/virtual_um.c index 9415bfbb..e55bb034 100644 --- a/src/host/virt_phy/src/shared/virtual_um.c +++ b/src/host/virt_phy/src/shared/virtual_um.c @@ -19,15 +19,18 @@ * */ +#include <unistd.h> +#include <errno.h> + #include <osmocom/core/select.h> #include <osmocom/core/utils.h> #include <osmocom/core/socket.h> #include <osmocom/core/gsmtap.h> #include <osmocom/core/msgb.h> #include <osmocom/core/talloc.h> -#include <virtphy/osmo_mcast_sock.h> -#include <virtphy/virtual_um.h> -#include <unistd.h> + +#include <osmocom/bb/virtphy/osmo_mcast_sock.h> +#include <osmocom/bb/virtphy/virtual_um.h> /** * Virtual UM interface file descriptor callback. @@ -37,49 +40,71 @@ static int virt_um_fd_cb(struct osmo_fd *ofd, unsigned int what) { struct virt_um_inst *vui = ofd->data; - // check if the read flag is set - if (what & BSC_FD_READ) { - // allocate message buffer of specified size - struct msgb *msg = msgb_alloc(VIRT_UM_MSGB_SIZE, - "Virtual UM Rx"); + if (what & OSMO_FD_READ) { + struct msgb *msg = msgb_alloc(VIRT_UM_MSGB_SIZE, "Virtual UM Rx"); int rc; - // read message from fd in message buffer - rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), - msgb_tailroom(msg)); - // rc is number of bytes actually read + /* read message from fd into message buffer */ + rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), msgb_tailroom(msg)); if (rc > 0) { msgb_put(msg, rc); msg->l1h = msgb_data(msg); - // call the l1 callback function for a received msg + /* call the l1 callback function for a received msg */ vui->recv_cb(vui, msg); - } else { - // TODO: this kind of error handling might be a bit harsh + } else if (rc == 0) { vui->recv_cb(vui, NULL); - // Unregister fd from select loop - osmo_fd_unregister(ofd); - close(ofd->fd); - ofd->fd = -1; - ofd->when = 0; - } + osmo_fd_close(ofd); + } else + perror("Read from multicast socket"); + } return 0; } -struct virt_um_inst *virt_um_init( - void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port, - char *rx_mcast_group, uint16_t rx_mcast_port, - void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg)) +struct virt_um_inst *virt_um_init(void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port, + char *rx_mcast_group, uint16_t rx_mcast_port, int ttl, const char *dev_name, + void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg)) { struct virt_um_inst *vui = talloc_zero(ctx, struct virt_um_inst); - vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, - tx_mcast_port, rx_mcast_group, rx_mcast_port, 1, - virt_um_fd_cb, vui); + int rc; + + vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, tx_mcast_port, + rx_mcast_group, rx_mcast_port, 1, virt_um_fd_cb, vui); + if (!vui->mcast_sock) { + perror("Unable to create VirtualUm multicast socket"); + talloc_free(vui); + return NULL; + } vui->recv_cb = recv_cb; + if (ttl >= 0) { + rc = osmo_sock_mcast_ttl_set(vui->mcast_sock->tx_ofd.fd, ttl); + if (rc < 0) { + perror("Cannot set TTL of Virtual Um transmit socket"); + goto out_close; + } + } + + if (dev_name) { + rc = osmo_sock_mcast_iface_set(vui->mcast_sock->tx_ofd.fd, dev_name); + if (rc < 0) { + perror("Cannot bind multicast tx to given device"); + goto out_close; + } + rc = osmo_sock_mcast_iface_set(vui->mcast_sock->rx_ofd.fd, dev_name); + if (rc < 0) { + perror("Cannot bind multicast rx to given device"); + goto out_close; + } + } + return vui; +out_close: + mcast_bidir_sock_close(vui->mcast_sock); + talloc_free(vui); + return NULL; } void virt_um_destroy(struct virt_um_inst *vui) @@ -97,6 +122,8 @@ int virt_um_write_msg(struct virt_um_inst *vui, struct msgb *msg) rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg), msgb_length(msg)); + if (rc < 0) + rc = -errno; 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 5738bed6..704a54cd 100644 --- a/src/host/virt_phy/src/virt_l1_model.c +++ b/src/host/virt_phy/src/virt_l1_model.c @@ -19,11 +19,12 @@ * */ -#include <virtphy/virt_l1_model.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/logging.h> #include <talloc.h> +#include <osmocom/bb/virtphy/virt_l1_model.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/logging.h> + static uint32_t next_ms_nr; struct l1_model_ms *l1_model_ms_init(void *ctx, struct l1ctl_sock_client *lsc, struct virt_um_inst *vui) 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 4737135c..3cad2ce0 100644 --- a/src/host/virt_phy/src/virt_l1_sched_simple.c +++ b/src/host/virt_phy/src/virt_l1_sched_simple.c @@ -18,13 +18,15 @@ * */ -#include <virtphy/virt_l1_sched.h> -#include <osmocom/core/linuxlist.h> -#include <virtphy/virt_l1_model.h> -#include <virtphy/logging.h> #include <time.h> #include <talloc.h> +#include <osmocom/core/linuxlist.h> + +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/virt_l1_model.h> +#include <osmocom/bb/virtphy/logging.h> + /** * @brief Start scheduler thread based on current gsm time from model */ @@ -97,6 +99,7 @@ void virt_l1_sched_execute(struct l1_model_ms *ms, uint32_t fn) ti_next->handler_cb(ms, mi_next->fn, ti_next->ts, ti_next->msg); /* remove handled tdma sched item */ llist_del(&ti_next->tdma_item_entry); + talloc_free(ti_next); } /* remove handled mframe sched item */ llist_del(&mi_next->mframe_item_entry); @@ -129,12 +132,8 @@ void virt_l1_sched_schedule(struct l1_model_ms *ms, struct msgb *msg, uint32_t f /* list did not contain mframe item with needed fn */ mi_fn = talloc_zero(ms, struct virt_l1_sched_mframe_item); mi_fn->fn = fn; - /* need to manually init the struct content.... no so happy */ - mi_fn->tdma_item_list.prev = &mi_fn->tdma_item_list; - mi_fn->tdma_item_list.next = &mi_fn->tdma_item_list; - - /* TODO: check if we get an error if list is empty... */ - llist_add(&mi_fn->mframe_item_entry, mi_next->mframe_item_entry.prev); + INIT_LLIST_HEAD(&mi_fn->tdma_item_list); + llist_add_tail(&mi_fn->mframe_item_entry, &mi_next->mframe_item_entry); } ti_new = talloc_zero(mi_fn, struct virt_l1_sched_tdma_item); diff --git a/src/host/virt_phy/src/virt_prim_data.c b/src/host/virt_phy/src/virt_prim_data.c index 96534aab..d8897915 100644 --- a/src/host/virt_phy/src/virt_prim_data.c +++ b/src/host/virt_phy/src/virt_prim_data.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -31,12 +27,12 @@ #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/protocol/gsm_08_58.h> #include <osmocom/core/msgb.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/virt_l1_sched.h> -#include <virtphy/logging.h> -#include <virtphy/gsmtapl1_if.h> -#include <l1ctl_proto.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/l1ctl_proto.h> /** * @brief Handler callback function for DATA request. @@ -47,7 +43,8 @@ static void virt_l1_sched_handler_cb(struct l1_model_ms *ms, uint32_t fn, uint8_t tn, struct msgb * msg) { gsmtapl1_tx_to_virt_um_inst(ms, fn, tn, msg); - l1ctl_tx_data_conf(ms, fn, 0, ms->state.serving_cell.arfcn); + /* FIXME: get ARFCN from msg payload */ + l1ctl_tx_data_conf(ms, fn, 0, ms->state.dedicated.band_arfcn); } /** @@ -73,15 +70,15 @@ void l1ctl_rx_data_req(struct l1_model_ms *ms, struct msgb *msg) rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot); msg->l2h = data_ind->data; - LOGPMS(DL1P, LOGL_INFO, ms, "Rx L1CTL_DATA_REQ (chan_nr=0x%02x, link_id=0x%02x) %s\n", + LOGPMS(DL1P, LOGL_DEBUG, ms, "Rx L1CTL_DATA_REQ (chan_nr=0x%02x, link_id=0x%02x) %s\n", ul->chan_nr, ul->link_id, osmo_hexdump(msg->l2h, msgb_l2len(msg))); virt_l1_sched_schedule(ms, msg, fn_sched, timeslot, &virt_l1_sched_handler_cb); } 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) + uint8_t chan_nr, uint32_t fn, uint8_t snr, + uint8_t rxlev, uint8_t num_biterr, uint8_t fire_crc) { struct msgb *l1ctl_msg = NULL; struct l1ctl_data_ind * l1di; @@ -97,7 +94,7 @@ void l1ctl_tx_data_ind(struct l1_model_ms *ms, struct msgb *msg, uint16_t arfcn, l1dl->chan_nr = chan_nr; l1dl->frame_nr = htonl(fn); l1dl->snr = snr; - l1dl->rx_level = signal_dbm; + l1dl->rx_level = rxlev; l1dl->num_biterr = 0; /* no biterrors */ l1dl->fire_crc = 0; @@ -105,7 +102,7 @@ void l1ctl_tx_data_ind(struct l1_model_ms *ms, struct msgb *msg, uint16_t arfcn, memcpy(l1di->data, msgb_data(msg), msgb_length(msg)); - LOGPMS(DL1P, LOGL_INFO, ms, "TX L1CTL_DATA_IND (link_id=0x%02x) %s\n", link_id, + LOGPMS(DL1P, LOGL_DEBUG, ms, "TX L1CTL_DATA_IND (link_id=0x%02x) %s\n", link_id, osmo_hexdump(msgb_data(msg), msgb_length(msg))); l1ctl_sap_tx_to_l23_inst(ms, l1ctl_msg); } @@ -123,6 +120,6 @@ void l1ctl_tx_data_conf(struct l1_model_ms *ms, uint32_t fn, uint16_t snr, uint1 struct msgb * l1ctl_msg; l1ctl_msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn, snr, arfcn); /* send confirm to layer23 */ - LOGPMS(DL1P, LOGL_INFO, ms, "Tx L1CTL_DATA_CONF\n"); + LOGPMS(DL1P, LOGL_DEBUG, ms, "Tx L1CTL_DATA_CONF\n"); 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 c14a4485..d012036f 100644 --- a/src/host/virt_phy/src/virt_prim_fbsb.c +++ b/src/host/virt_phy/src/virt_prim_fbsb.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -29,11 +25,12 @@ #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/protocol/gsm_08_58.h> #include <osmocom/core/msgb.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/virt_l1_sched.h> #include <osmocom/core/gsmtap.h> -#include <virtphy/logging.h> -#include <l1ctl_proto.h> + +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/l1ctl_proto.h> static uint16_t sync_count = 0; diff --git a/src/host/virt_phy/src/virt_prim_pdch.c b/src/host/virt_phy/src/virt_prim_pdch.c new file mode 100644 index 00000000..3fa7977b --- /dev/null +++ b/src/host/virt_phy/src/virt_prim_pdch.c @@ -0,0 +1,108 @@ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <stdint.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/utils.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/protocol/gsm_08_58.h> +#include <osmocom/gsm/gsm0502.h> + +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/virtphy/logging.h> + +#include <osmocom/bb/l1ctl_proto.h> +#include <osmocom/bb/l1gprs.h> + +void l1ctl_rx_gprs_uldl_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg) +{ + const struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data; + + if (OSMO_UNLIKELY(ms->gprs == NULL)) { + LOGPMS(DL1C, LOGL_ERROR, ms, "l1gprs is not initialized\n"); + return; + } + + msg->l1h = msgb_pull(msg, sizeof(*l1h)); + + if (l1h->msg_type == L1CTL_GPRS_UL_TBF_CFG_REQ) + l1gprs_handle_ul_tbf_cfg_req(ms->gprs, msg); + else + l1gprs_handle_dl_tbf_cfg_req(ms->gprs, msg); +} + +void l1ctl_rx_gprs_ul_block_req(struct l1_model_ms *ms, struct msgb *msg) +{ + const struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data; + struct l1gprs_prim_ul_block_req req; + + if (OSMO_UNLIKELY(ms->gprs == NULL)) { + LOGPMS(DL1P, LOGL_ERROR, ms, "l1gprs is not initialized\n"); + msgb_free(msg); + return; + } + + msg->l1h = (void *)l1h->data; + if (l1gprs_handle_ul_block_req(ms->gprs, &req, msg) != 0) { + msgb_free(msg); + return; + } + msg->l2h = (void *)&req.data[0]; + + virt_l1_sched_schedule(ms, msg, req.hdr.fn, req.hdr.tn, + &gsmtapl1_tx_to_virt_um_inst); +} + +void l1ctl_tx_gprs_dl_block_ind(struct l1_model_ms *ms, const struct msgb *msg, + uint32_t fn, uint8_t tn, uint8_t rxlev) +{ + struct l1gprs_prim_dl_block_ind ind; + struct msgb *nmsg; + uint8_t usf = 0xff; + + if (ms->gprs == NULL) + return; + + ind = (struct l1gprs_prim_dl_block_ind) { + .hdr = { + .fn = fn, + .tn = tn, + }, + .meas = { + .ber10k = 0, /* perfect Um, no errors */ + .ci_cb = 180, /* 18 dB */ + .rx_lev = rxlev, + }, + .data = msgb_data(msg), + .data_len = msgb_length(msg), + }; + + nmsg = l1gprs_handle_dl_block_ind(ms->gprs, &ind, &usf); + if (nmsg != NULL) + l1ctl_sap_tx_to_l23_inst(ms, nmsg); + /* Every fn % 13 == 12 we have either a PTCCH or an IDLE slot, thus + * every fn % 13 == 8 we add 5 frames, or 4 frames othrwise. The + * resulting value is first fn of the next block. */ + const uint32_t rts_fn = GSM_TDMA_FN_SUM(fn, (fn % 13 == 8) ? 5 : 4); + nmsg = l1gprs_handle_rts_ind(ms->gprs, rts_fn, tn, usf); + if (nmsg != NULL) + l1ctl_sap_tx_to_l23_inst(ms, nmsg); +} diff --git a/src/host/virt_phy/src/virt_prim_pm.c b/src/host/virt_phy/src/virt_prim_pm.c index 46370138..5883bbbe 100644 --- a/src/host/virt_phy/src/virt_prim_pm.c +++ b/src/host/virt_phy/src/virt_prim_pm.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -26,14 +22,15 @@ #include <string.h> #include <stdlib.h> -#include <osmocom/gsm/gsm_utils.h> -#include <osmocom/gsm/protocol/gsm_08_58.h> #include <osmocom/core/msgb.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/virt_l1_sched.h> #include <osmocom/core/gsmtap.h> -#include <virtphy/logging.h> -#include <l1ctl_proto.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/protocol/gsm_08_58.h> + +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/l1ctl_proto.h> /** * @brief Change the signal strength for a given arfcn. @@ -84,38 +81,49 @@ void l1ctl_rx_pm_req(struct l1_model_ms *ms, struct msgb *msg) 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); - uint16_t arfcn_next; - /* convert to host order */ - pm_req->range.band_arfcn_from = ntohs(pm_req->range.band_arfcn_from); - pm_req->range.band_arfcn_to = ntohs(pm_req->range.band_arfcn_to); + /* just parse the data from the request here */ + l1s->pm.req.band_arfcn_from = ntohs(pm_req->range.band_arfcn_from); + l1s->pm.req.band_arfcn_to = ntohs(pm_req->range.band_arfcn_to); - LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n", - pm_req->type, pm_req->range.band_arfcn_from, pm_req->range.band_arfcn_to); + LOGPMS(DL1C, LOGL_DEBUG, ms, "Rx L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n", + pm_req->type, l1s->pm.req.band_arfcn_from, l1s->pm.req.band_arfcn_to); + + /* generating the response will happen delayed in a timer, as otherwise + * we will respond too fast, and 'mobile' will run havoc in a busy loop issuing + * endless PM_REQ until a cell eventually isfound */ + osmo_timer_schedule(&l1s->pm.req.timer, 0, 300000); +} + +static void pm_conf_timer_cb(void *data) +{ + struct l1_model_ms *ms = data; + struct l1_state_ms *l1s = &ms->state; + struct msgb *resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF); + uint16_t arfcn_next; - for (arfcn_next = pm_req->range.band_arfcn_from; - arfcn_next <= pm_req->range.band_arfcn_to; ++arfcn_next) { + for (arfcn_next = l1s->pm.req.band_arfcn_from; + arfcn_next <= l1s->pm.req.band_arfcn_to; ++arfcn_next) { struct l1ctl_pm_conf *pm_conf = (struct l1ctl_pm_conf *) msgb_put(resp_msg, sizeof(*pm_conf)); pm_conf->band_arfcn = htons(arfcn_next); /* set min and max to the value calculated for that * arfcn (IGNORE UPLINKK AND PCS AND OTHER FLAGS) */ pm_conf->pm[0] = dbm2rxlev(l1s->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]); pm_conf->pm[1] = dbm2rxlev(l1s->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]); - if (arfcn_next == pm_req->range.band_arfcn_to) { + if (arfcn_next == l1s->pm.req.band_arfcn_to) { struct l1ctl_hdr *resp_l1h = msgb_l1(resp_msg); resp_l1h->flags |= L1CTL_F_DONE; } - /* no more space to hold mor pm info in msgb, flush to l23 */ + /* no more space to hold more pm info in msgb, flush to l23 */ if (msgb_tailroom(resp_msg) < sizeof(*pm_conf)) { - LOGPMS(DL1C, LOGL_INFO, ms, "Tx L1CTL_PM_CONF\n"); + LOGPMS(DL1C, LOGL_DEBUG, ms, "Tx L1CTL_PM_CONF\n"); 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) { - LOGPMS(DL1C, LOGL_INFO, ms, "Tx L1CTL_PM_CONF\n"); + LOGPMS(DL1C, LOGL_DEBUG, ms, "Tx L1CTL_PM_CONF\n"); l1ctl_sap_tx_to_l23_inst(ms, resp_msg); } } @@ -137,6 +145,7 @@ void prim_pm_init(struct l1_model_ms *model) l1s->pm.meas.arfcn_sig_lev_timers[i].cb = prim_pm_timer_cb; l1s->pm.meas.arfcn_sig_lev_timers[i].data = &l1s->pm.meas.arfcn_sig_lev_dbm[i]; } + osmo_timer_setup(&l1s->pm.req.timer, pm_conf_timer_cb, model); } void prim_pm_exit(struct l1_model_ms *model) @@ -146,4 +155,5 @@ void prim_pm_exit(struct l1_model_ms *model) for (i = 0; i < 1024; ++i) osmo_timer_del(&l1s->pm.meas.arfcn_sig_lev_timers[i]); + osmo_timer_del(&l1s->pm.req.timer); } diff --git a/src/host/virt_phy/src/virt_prim_rach.c b/src/host/virt_phy/src/virt_prim_rach.c index 94076cf9..d12e63c6 100644 --- a/src/host/virt_phy/src/virt_prim_rach.c +++ b/src/host/virt_phy/src/virt_prim_rach.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -27,16 +23,17 @@ #include <string.h> #include <stdlib.h> +#include <osmocom/core/msgb.h> #include <osmocom/gsm/rsl.h> #include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/gsm0502.h> #include <osmocom/gsm/protocol/gsm_08_58.h> -#include <osmocom/core/msgb.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/virt_l1_sched.h> -#include <virtphy/logging.h> -#include <virtphy/gsmtapl1_if.h> -#include <l1ctl_proto.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/l1ctl_proto.h> /* use if we have a combined uplink (RACH, SDCCH, ...) (see * http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html) @@ -79,36 +76,37 @@ void l1ctl_rx_rach_req(struct l1_model_ms *ms, struct msgb *msg) struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data; struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload; uint32_t fn_sched; - uint8_t ts = 1; /* FIXME mostly, ts 1 is used for rach, where can i get that info? System info? */ uint16_t offset = ntohs(rach_req->offset); LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n", rach_req->ra, offset, rach_req->combined); - if (rach_req->ra == 0x03) - fn_sched = 42; - /* set ra data to msg (8bits, the 11bit option is not used for GSM) */ msg->l2h = msgb_put(msg, sizeof(uint8_t)); *msg->l2h = rach_req->ra; - /* chan_nr need to be encoded here, as it is not set by l23 for - * the rach request, but needed by virt um */ - ul->chan_nr = rsl_enc_chan_nr(RSL_CHAN_RACH, 0, ts); - ul->link_id = LID_DEDIC; + /* use the indicated RSL chan_nr/link_id, if provided */ + if (ul->chan_nr == 0x00) { + LOGPMS(DL1C, LOGL_NOTICE, ms, + "The UL info header is empty, assuming RACH is on TS0\n"); + ul->chan_nr = RSL_CHAN_RACH; + ul->link_id = LID_DEDIC; + } /* sched fn calculation if we have a combined ccch channel configuration */ if (rach_req->combined) { /* add elapsed RACH slots to offset */ offset += t3_to_rach_comb[l1s->current_time.t3]; /* offset is the number of RACH slots in the future */ - fn_sched = l1s->current_time.fn - l1s->current_time.t3; + fn_sched = GSM_TDMA_FN_SUB(l1s->current_time.fn, l1s->current_time.t3); fn_sched += offset / 27 * 51; fn_sched += rach_to_t3_comb[offset % 27]; + fn_sched %= GSM_TDMA_HYPERFRAME; } else - fn_sched = l1s->current_time.fn + offset; + fn_sched = GSM_TDMA_FN_SUM(l1s->current_time.fn, offset); - virt_l1_sched_schedule(ms, msg, fn_sched, ts, &virt_l1_sched_handler_cb); + virt_l1_sched_schedule(ms, msg, fn_sched, ul->chan_nr & 0x07, + &virt_l1_sched_handler_cb); } /** diff --git a/src/host/virt_phy/src/virt_prim_traffic.c b/src/host/virt_phy/src/virt_prim_traffic.c index 5f6b273b..778d67a3 100644 --- a/src/host/virt_phy/src/virt_prim_traffic.c +++ b/src/host/virt_phy/src/virt_prim_traffic.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -27,16 +23,16 @@ #include <string.h> #include <stdlib.h> +#include <osmocom/core/msgb.h> #include <osmocom/gsm/rsl.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/protocol/gsm_08_58.h> -#include <osmocom/core/msgb.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/virt_l1_sched.h> -#include <virtphy/logging.h> -#include <virtphy/gsmtapl1_if.h> -#include <l1ctl_proto.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/l1ctl_proto.h> /** * @brief Handler callback function for TRAFFIC request. @@ -47,7 +43,8 @@ static void virt_l1_sched_handler_cb(struct l1_model_ms *ms, uint32_t fn, uint8_t tn, struct msgb * msg) { gsmtapl1_tx_to_virt_um_inst(ms, fn, tn, msg); - l1ctl_tx_traffic_conf(ms, fn, 0, ms->state.serving_cell.arfcn); + /* FIXME: get ARFCN from msg payload */ + l1ctl_tx_traffic_conf(ms, fn, 0, ms->state.dedicated.band_arfcn); } /** @@ -78,13 +75,14 @@ void l1ctl_rx_traffic_req(struct l1_model_ms *ms, struct msgb *msg) } 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 chan_nr, uint32_t fn, uint8_t snr, uint8_t rxlev, uint8_t num_biterr, uint8_t fire_crc) { struct msgb *l1ctl_msg = NULL; struct l1ctl_traffic_ind * l1ti; struct l1ctl_info_dl * l1dl; - uint8_t *frame, frame_len; + uint8_t *frame; + int frame_len; uint8_t rsl_chan_type, subchan, timeslot; l1ctl_msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND); l1dl = (struct l1ctl_info_dl *) msgb_put(l1ctl_msg, sizeof(*l1dl)); @@ -97,15 +95,20 @@ void l1ctl_tx_traffic_ind(struct l1_model_ms *ms, struct msgb *msg, uint16_t arf l1dl->chan_nr = chan_nr; l1dl->frame_nr = htonl(fn); l1dl->snr = snr; - l1dl->rx_level = signal_dbm; + l1dl->rx_level = rxlev; l1dl->num_biterr = 0; /* no biterrors */ l1dl->fire_crc = 0; - /* TODO: traffic decoding and decryption */ - - frame_len = msgb_length(msg); + /* The first byte indicates the type of voice frame (enum gsmtap_um_voice_type), + * which we simply ignore here and pass on the frame without that byte. + * TODO: Check for consistency with ms->state.tch_mode ? */ + frame_len = msgb_length(msg) - 1; + if (frame_len < 0) { + msgb_free(l1ctl_msg); + return; + } frame = (uint8_t *) msgb_put(l1ctl_msg, frame_len); - memcpy(frame, msgb_data(msg), frame_len); + memcpy(frame, msgb_data(msg)+1, frame_len); DEBUGPMS(DL1P, ms, "Tx L1CTL_TRAFFIC_IND (chan_nr=0x%02x, link_id=0x%02x)\n", chan_nr, link_id); 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 d0a2ddbf..0aa21adc 100644 --- a/src/host/virt_phy/src/virtphy.c +++ b/src/host/virt_phy/src/virtphy.c @@ -20,10 +20,6 @@ * */ -#include <osmocom/core/msgb.h> -#include <osmocom/core/select.h> -#include <osmocom/core/gsmtap.h> -#include <osmocom/core/application.h> #include <stdint.h> #include <string.h> #include <stdio.h> @@ -31,15 +27,22 @@ #include <getopt.h> #include <errno.h> #include <signal.h> -#include <virtphy/virtual_um.h> -#include <virtphy/l1ctl_sock.h> -#include <virtphy/virt_l1_model.h> -#include <virtphy/l1ctl_sap.h> -#include <virtphy/gsmtapl1_if.h> -#include <virtphy/logging.h> -#include <virtphy/virt_l1_sched.h> -#define DEFAULT_LOG_MASK "DL1C,2:DL1P,2:DVIRPHY,2:DMAIN,1" +#include <osmocom/core/msgb.h> +#include <osmocom/core/select.h> +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/application.h> + +#include <osmocom/bb/virtphy/virtual_um.h> +#include <osmocom/bb/virtphy/l1ctl_sock.h> +#include <osmocom/bb/virtphy/virt_l1_model.h> +#include <osmocom/bb/virtphy/l1ctl_sap.h> +#include <osmocom/bb/virtphy/gsmtapl1_if.h> +#include <osmocom/bb/virtphy/logging.h> +#include <osmocom/bb/virtphy/virt_l1_sched.h> +#include <osmocom/bb/l1gprs.h> + +#define DEFAULT_LOG_MASK "DL1C,2:DL1P,2:DVIRPHY,2:DGPRS,1:DMAIN,1" /* this exists once in the program, and contains the state that we * only keep once: L1CTL server socket, GSMTAP/VirtUM socket */ @@ -59,13 +62,15 @@ static char *log_mask = DEFAULT_LOG_MASK; static char *l1ctl_sock_path = L1CTL_SOCK_PATH; static char *arfcn_sig_lev_red_mask = NULL; static char *pm_timeout = NULL; +static char *mcast_netdev = NULL; +static int mcast_ttl = -1; -static void print_usage() +static void print_usage(void) { printf("Usage: virtphy\n"); } -static void print_help() +static void print_help(void) { printf(" Some useful help...\n"); printf(" -h --help This text.\n"); @@ -76,6 +81,8 @@ static void print_help() printf(" -s --l1ctl-sock l1ctl socket path path.\n"); printf(" -r --arfcn-sig-lev-red reduce signal level (e.g. 666,12:888,43:176,22).\n"); printf(" -t --pm-timeout power management timeout.\n"); + printf(" -T --mcast-ttl TTL set TTL of Virtual Um GSMTAP multicast frames\n"); + printf(" -D --mcast-deav NETDEV bind to given network device for Virtual Um\n"); } static void handle_options(int argc, char **argv) @@ -91,9 +98,11 @@ static void handle_options(int argc, char **argv) {"l1ctl-sock", required_argument, 0, 's'}, {"arfcn-sig-lev-red", required_argument, 0, 'r'}, {"pm-timeout", required_argument, 0, 't'}, + {"mcast-ttl", required_argument, 0, 'T'}, + {"mcast-dev", required_argument, 0, 'D'}, {0, 0, 0, 0}, }; - c = getopt_long(argc, argv, "hz:y:x:d:s:r:t:", long_options, + c = getopt_long(argc, argv, "hz:y:x:d:s:r:t:T:D:", long_options, &option_index); if (c == -1) break; @@ -124,6 +133,12 @@ static void handle_options(int argc, char **argv) case 't': pm_timeout = optarg; break; + case 'T': + mcast_ttl = atoi(optarg); + break; + case 'D': + mcast_netdev = optarg; + break; default: break; } @@ -227,12 +242,13 @@ int main(int argc, char *argv[]) /* init loginfo */ handle_options(argc, argv); - ms_log_init(log_mask); + ms_log_init(tall_vphy_ctx, log_mask); + l1gprs_logging_init(DGPRS); LOGP(DVIRPHY, LOGL_INFO, "Virtual physical layer starting up...\n"); - g_vphy.virt_um = virt_um_init(tall_vphy_ctx, ul_tx_grp, port, dl_rx_grp, port, - gsmtapl1_rx_from_virt_um_inst_cb); + g_vphy.virt_um = virt_um_init(tall_vphy_ctx, ul_tx_grp, port, dl_rx_grp, port, mcast_ttl, + mcast_netdev, gsmtapl1_rx_from_virt_um_inst_cb); g_vphy.l1ctl_sock = l1ctl_sock_init(tall_vphy_ctx, l1ctl_sap_rx_from_l23_inst_cb, l1ctl_accept_cb, l1ctl_close_cb, l1ctl_sock_path); |