aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-virtual/l1_if.c
diff options
context:
space:
mode:
authorSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-08 16:31:50 +0100
committerSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-08 16:31:50 +0100
commita8b7c8aa05bf7292c6ed289f22f961d9ec397fc1 (patch)
tree6b1d32a5de81a1c731d96e0c299343cdf384771b /src/osmo-bts-virtual/l1_if.c
parent17eb1a45b446d631449143a52b503978e6661637 (diff)
VIRT-PHY: Added functionality to cooperate with osmocom-bb virt-phy.
This patch improves the virtual physical layer designed to replace the air interface. The purpose is to get rid of the hardware requirements and be able to start testing and implementing layer 2 communication functionality on one machine. Multicast sockets are used to enable bidirectional communication between the BTS and the MS process. The GSMTAP protocol designed for wireshark capturing is used to encapsulate the payload on the virtual physical layer. * Working mcast socket communication and extraction of its functionality. * Fixed OML and RSL startup sequences. * Icludes tests for mcast socket and virtual UM. * Ecapsulation and parsing methods to and from GSMTAP messages. * Basic handlers for file descriptor callbacks from incoming mcast messages. * Multiplexing to different channels based on GSMTAP header channel type.
Diffstat (limited to 'src/osmo-bts-virtual/l1_if.c')
-rw-r--r--src/osmo-bts-virtual/l1_if.c199
1 files changed, 142 insertions, 57 deletions
diff --git a/src/osmo-bts-virtual/l1_if.c b/src/osmo-bts-virtual/l1_if.c
index 0e407bba..cc9e6712 100644
--- a/src/osmo-bts-virtual/l1_if.c
+++ b/src/osmo-bts-virtual/l1_if.c
@@ -26,6 +26,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/gsmtap.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
@@ -40,11 +41,73 @@
#include "virtual_um.h"
+/**
+ * Callback to handle incoming messages from the MS.
+ * The incoming message should be GSM_TAP encapsulated.
+ * TODO: implement all channels
+ */
static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
{
- /* FIXME: Handle msg from MS */
-}
+ struct osmo_phsap_prim l1sap;
+ struct gsmtap_hdr *gh = (struct gsmtap_hdr *)msg->l1h;
+ struct phy_link *plink = (struct phy_link *)vui->priv;
+ // TODO: is there more than one physical instance? Where do i get the corresponding pinst number? Maybe gsmtap_hdr->antenna?
+ struct phy_instance *pinst = phy_instance_by_num(plink, 0);
+
+ memset(&l1sap, 0, sizeof(l1sap));
+
+ switch (gh->sub_type) {
+ case GSMTAP_CHANNEL_RACH:
+ // generate primitive for upper layer
+ osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH,
+ PRIM_OP_INDICATION,
+ NULL);
+ l1sap.u.rach_ind.chan_nr = 0; // TODO: fill with proper value
+ l1sap.u.rach_ind.ra = 0; // TODO: fill with proper value
+ l1sap.u.rach_ind.fn = gh->frame_number;
+ // todo: schedule the uplink burst
+ //trx_sched_ul_burst(&l1h->l1s, tn, fn, bits, rssi, toa);
+ break;
+ case GSMTAP_CHANNEL_SDCCH:
+ case GSMTAP_CHANNEL_SDCCH4:
+ case GSMTAP_CHANNEL_SDCCH8:
+ // TODO: implement channel handling
+ break;
+ case GSMTAP_CHANNEL_TCH_F:
+ // TODO: implement channel handling
+ break;
+ case GSMTAP_CHANNEL_TCH_H:
+ // TODO: implement channel handling
+ break;
+ case GSMTAP_CHANNEL_AGCH:
+ case GSMTAP_CHANNEL_PCH:
+ case GSMTAP_CHANNEL_BCCH:
+ LOGP(LOGL_NOTICE, DL1P,
+ "Ignore incoming msg - channel type downlink only!");
+ goto nomessage;
+ case GSMTAP_CHANNEL_CCCH:
+ case GSMTAP_CHANNEL_PACCH:
+ case GSMTAP_CHANNEL_PDCH:
+ case GSMTAP_CHANNEL_PTCCH:
+ case GSMTAP_CHANNEL_CBCH51:
+ case GSMTAP_CHANNEL_CBCH52:
+ LOGP(LOGL_NOTICE, DL1P,
+ "Ignore incoming msg - channel type not supported!");
+ goto nomessage;
+ default:
+ LOGP(LOGL_NOTICE, DL1P,
+ "Ignore incoming msg - channel type unknown.");
+ goto nomessage;
+ }
+ /* forward primitive */
+ l1sap_up(pinst->trx, &l1sap);
+ DEBUGP(DL1P, "Message forwarded to layer 2.");
+ return;
+
+ // handle memory deallocation
+ nomessage: free(msg);
+}
/* called by common part once OML link is established */
int bts_model_oml_estab(struct gsm_bts *bts)
@@ -52,6 +115,7 @@ int bts_model_oml_estab(struct gsm_bts *bts)
return 0;
}
+/* called by bts_main to initialize physical link */
int bts_model_phy_link_open(struct phy_link *plink)
{
struct phy_instance *pinst;
@@ -63,10 +127,24 @@ int bts_model_phy_link_open(struct phy_link *plink)
phy_link_state_set(plink, PHY_LINK_CONNECTING);
- plink->u.virt.virt_um = virt_um_init(plink, plink->u.virt.mcast_group,
- plink->u.virt.mcast_port,
- plink->u.virt.mcast_dev, plink,
- virt_um_rcv_cb);
+ if (!plink->u.virt.bts_mcast_group) {
+ plink->u.virt.bts_mcast_group = DEFAULT_BTS_MCAST_GROUP;
+ }
+ if (!plink->u.virt.bts_mcast_port) {
+ plink->u.virt.bts_mcast_port = DEFAULT_BTS_MCAST_PORT;
+ }
+ if (!plink->u.virt.ms_mcast_group) {
+ plink->u.virt.ms_mcast_group = DEFAULT_MS_MCAST_GROUP;
+ }
+ if (!plink->u.virt.ms_mcast_port) {
+ plink->u.virt.ms_mcast_port = DEFAULT_MS_MCAST_PORT;
+ }
+
+ plink->u.virt.virt_um = virt_um_init(plink,
+ plink->u.virt.ms_mcast_group,
+ plink->u.virt.ms_mcast_port,
+ plink->u.virt.bts_mcast_group,
+ plink->u.virt.bts_mcast_port, virt_um_rcv_cb);
if (!plink->u.virt.virt_um) {
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return -1;
@@ -74,8 +152,11 @@ int bts_model_phy_link_open(struct phy_link *plink)
/* iterate over list of PHY instances and initialize the
* scheduler */
- llist_for_each_entry(pinst, &plink->instances, list) {
+ llist_for_each_entry(pinst, &plink->instances, list)
+ {
trx_sched_init(&pinst->u.virt.sched, pinst->trx);
+ /* TODO: why only start scheduler for CCCH */
+ /* Only start the scheduler for the transceiver on c0. CCCH is on C0 */
if (pinst->trx == pinst->trx->bts->c0)
vbts_sched_start(pinst->trx->bts);
}
@@ -87,13 +168,13 @@ int bts_model_phy_link_open(struct phy_link *plink)
return 0;
}
-
/*
* primitive handling
*/
/* enable ciphering */
-static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int downlink)
+static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr,
+ int downlink)
{
struct gsm_bts_trx *trx = lchan->ts->trx;
struct phy_instance *pinst = trx_phy_instance(trx);
@@ -106,17 +187,17 @@ static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int down
if (!downlink) {
/* set uplink */
trx_sched_set_cipher(sched, chan_nr, 0, lchan->encr.alg_id - 1,
- lchan->encr.key, lchan->encr.key_len);
+ lchan->encr.key, lchan->encr.key_len);
lchan->ciph_state = LCHAN_CIPH_RX_CONF;
} else {
/* set downlink and also set uplink, if not already */
if (lchan->ciph_state != LCHAN_CIPH_RX_CONF) {
trx_sched_set_cipher(sched, chan_nr, 0,
- lchan->encr.alg_id - 1, lchan->encr.key,
- lchan->encr.key_len);
+ lchan->encr.alg_id - 1, lchan->encr.key,
+ lchan->encr.key_len);
}
trx_sched_set_cipher(sched, chan_nr, 1, lchan->encr.alg_id - 1,
- lchan->encr.key, lchan->encr.key_len);
+ lchan->encr.key, lchan->encr.key_len);
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
}
@@ -124,13 +205,13 @@ static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int down
}
static int mph_info_chan_confirm(struct gsm_bts_trx *trx, uint8_t chan_nr,
- enum osmo_mph_info_type type, uint8_t cause)
+ enum osmo_mph_info_type type, uint8_t cause)
{
struct osmo_phsap_prim l1sap;
memset(&l1sap, 0, sizeof(l1sap));
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, PRIM_OP_CONFIRM,
- NULL);
+ NULL);
l1sap.u.info.type = type;
l1sap.u.info.u.act_cnf.chan_nr = chan_nr;
l1sap.u.info.u.act_cnf.cause = cause;
@@ -144,7 +225,7 @@ int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
memset(&l1sap, 0, sizeof(l1sap));
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
- PRIM_OP_INDICATION, NULL);
+ PRIM_OP_INDICATION, NULL);
l1sap.u.info.type = PRIM_INFO_TIME;
l1sap.u.info.u.time_ind.fn = fn;
@@ -154,40 +235,42 @@ int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
return l1sap_up(bts->c0, &l1sap);
}
-
-static void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr, float ta,
- float ber, float rssi)
+static void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr,
+ float ta, float ber, float rssi)
{
memset(l1sap, 0, sizeof(*l1sap));
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_MPH_INFO,
- PRIM_OP_INDICATION, NULL);
+ PRIM_OP_INDICATION, NULL);
l1sap->u.info.type = PRIM_INFO_MEAS;
l1sap->u.info.u.meas_ind.chan_nr = chan_nr;
- l1sap->u.info.u.meas_ind.ta_offs_qbits = (int16_t)(ta*4);
- l1sap->u.info.u.meas_ind.ber10k = (unsigned int) (ber * 10000);
- l1sap->u.info.u.meas_ind.inv_rssi = (uint8_t) (rssi * -1);
+ l1sap->u.info.u.meas_ind.ta_offs_qbits = (int16_t)(ta * 4);
+ l1sap->u.info.u.meas_ind.ber10k = (unsigned int)(ber * 10000);
+ l1sap->u.info.u.meas_ind.inv_rssi = (uint8_t)(rssi * -1);
}
-int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
- int n_errors, int n_bits_total, float rssi, float toa)
+int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn,
+ uint8_t chan_nr, int n_errors, int n_bits_total,
+ float rssi, float toa)
{
struct gsm_lchan *lchan = &trx->ts[tn].lchan[l1sap_chan2ss(chan_nr)];
struct osmo_phsap_prim l1sap;
/* 100% BER is n_bits_total is 0 */
- float ber = n_bits_total==0 ? 1.0 : (float)n_errors / (float)n_bits_total;
+ float ber = n_bits_total == 0 ?
+ 1.0 : (float)n_errors / (float)n_bits_total;
- LOGP(DMEAS, LOGL_DEBUG, "RX L1 frame %s fn=%u chan_nr=0x%02x MS pwr=%ddBm rssi=%.1f dBFS "
- "ber=%.2f%% (%d/%d bits) L1_ta=%d rqd_ta=%d toa=%.2f\n",
- gsm_lchan_name(lchan), fn, chan_nr, ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
- rssi, ber*100, n_errors, n_bits_total, lchan->meas.l1_info[1], lchan->rqd_ta, toa);
+ LOGP(DMEAS, LOGL_DEBUG,
+ "RX L1 frame %s fn=%u chan_nr=0x%02x MS pwr=%ddBm rssi=%.1f dBFS "
+ "ber=%.2f%% (%d/%d bits) L1_ta=%d rqd_ta=%d toa=%.2f\n",
+ gsm_lchan_name(lchan), fn, chan_nr,
+ ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
+ rssi, ber * 100, n_errors, n_bits_total,
+ lchan->meas.l1_info[1], lchan->rqd_ta, toa);
l1if_fill_meas_res(&l1sap, chan_nr, lchan->rqd_ta + toa, ber, rssi);
return l1sap_up(trx, &l1sap);
}
-
-
/* primitive from common part */
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
{
@@ -232,7 +315,8 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
if (l1sap->u.info.type == PRIM_INFO_ACTIVATE) {
if ((chan_nr & 0x80)) {
LOGP(DL1C, LOGL_ERROR, "Cannot activate"
- " chan_nr 0x%02x\n", chan_nr);
+ " chan_nr 0x%02x\n",
+ chan_nr);
break;
}
/* activate dedicated channel */
@@ -241,14 +325,15 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
trx_sched_set_lchan(sched, chan_nr, 0x40, 1);
/* set mode */
trx_sched_set_mode(sched, chan_nr,
- lchan->rsl_cmode, lchan->tch_mode,
- lchan->tch.amr_mr.num_modes,
- lchan->tch.amr_mr.bts_mode[0].mode,
- lchan->tch.amr_mr.bts_mode[1].mode,
- lchan->tch.amr_mr.bts_mode[2].mode,
- lchan->tch.amr_mr.bts_mode[3].mode,
- amr_get_initial_mode(lchan),
- (lchan->ho.active == 1));
+ lchan->rsl_cmode,
+ lchan->tch_mode,
+ lchan->tch.amr_mr.num_modes,
+ lchan->tch.amr_mr.bts_mode[0].mode,
+ lchan->tch.amr_mr.bts_mode[1].mode,
+ lchan->tch.amr_mr.bts_mode[2].mode,
+ lchan->tch.amr_mr.bts_mode[3].mode,
+ amr_get_initial_mode(lchan),
+ (lchan->ho.active == 1));
/* init lapdm */
lchan_init_lapdm(lchan);
/* set lchan active */
@@ -257,31 +342,32 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
l1if_set_ciphering(lchan, chan_nr, 0);
l1if_set_ciphering(lchan, chan_nr, 1);
if (lchan->encr.alg_id)
- lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
+ lchan->ciph_state =
+ LCHAN_CIPH_RXTX_CONF;
else
lchan->ciph_state = LCHAN_CIPH_NONE;
/* confirm */
mph_info_chan_confirm(trx, chan_nr,
- PRIM_INFO_ACTIVATE, 0);
+ PRIM_INFO_ACTIVATE, 0);
break;
}
if (l1sap->u.info.type == PRIM_INFO_MODIFY) {
/* change mode */
trx_sched_set_mode(sched, chan_nr,
- lchan->rsl_cmode, lchan->tch_mode,
- lchan->tch.amr_mr.num_modes,
- lchan->tch.amr_mr.bts_mode[0].mode,
- lchan->tch.amr_mr.bts_mode[1].mode,
- lchan->tch.amr_mr.bts_mode[2].mode,
- lchan->tch.amr_mr.bts_mode[3].mode,
- amr_get_initial_mode(lchan),
- 0);
+ lchan->rsl_cmode,
+ lchan->tch_mode,
+ lchan->tch.amr_mr.num_modes,
+ lchan->tch.amr_mr.bts_mode[0].mode,
+ lchan->tch.amr_mr.bts_mode[1].mode,
+ lchan->tch.amr_mr.bts_mode[2].mode,
+ lchan->tch.amr_mr.bts_mode[3].mode,
+ amr_get_initial_mode(lchan), 0);
break;
}
if ((chan_nr & 0x80)) {
LOGP(DL1C, LOGL_ERROR, "Cannot deactivate "
- "chan_nr 0x%02x\n", chan_nr);
+ "chan_nr 0x%02x\n", chan_nr);
break;
}
/* deactivate associated channel */
@@ -293,26 +379,25 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
trx_sched_set_lchan(sched, chan_nr, 0x00, 0);
/* confirm only on dedicated channel */
mph_info_chan_confirm(trx, chan_nr,
- PRIM_INFO_DEACTIVATE, 0);
+ PRIM_INFO_DEACTIVATE, 0);
lchan->ciph_state = 0; /* FIXME: do this in common/\*.c */
}
break;
default:
LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n",
- l1sap->u.info.type);
+ l1sap->u.info.type);
rc = -EINVAL;
goto done;
}
break;
default:
LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n",
- l1sap->oph.primitive, l1sap->oph.operation);
+ l1sap->oph.primitive, l1sap->oph.operation);
rc = -EINVAL;
goto done;
}
-done:
- if (msg)
+ done: if (msg)
msgb_free(msg);
return rc;
}