aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-octphy/l1_if.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2016-01-09 13:13:37 +0100
committerHarald Welte <laforge@gnumonks.org>2016-02-15 14:18:59 +0100
commitd784e50747b8cf0ce505489e1451f75be5ccbd4b (patch)
treeb143bbf2162bea0959ba9b80cc5d1573de7d62ee /src/osmo-bts-octphy/l1_if.c
parentf58542899a91d1db0bbe9966ae98ccdf449f45d0 (diff)
Introduce new phy_link and phy_instance abstraction
This way we can model a flexible mapping between any number of PHYs, each having multiple instances, and then map BTSs with TRXx on top of those PHYs.
Diffstat (limited to 'src/osmo-bts-octphy/l1_if.c')
-rw-r--r--src/osmo-bts-octphy/l1_if.c170
1 files changed, 124 insertions, 46 deletions
diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c
index db6e032c..3215aa19 100644
--- a/src/osmo-bts-octphy/l1_if.c
+++ b/src/osmo-bts-octphy/l1_if.c
@@ -38,6 +38,7 @@
#include <osmocom/core/socket.h>
#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_model.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/l1sap.h>
@@ -109,6 +110,17 @@ osmocom_to_octphy_band(enum gsm_band osmo_band, unsigned int arfcn)
}
};
+struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id)
+{
+ struct phy_instance *pinst;
+
+ pinst = phy_instance_by_num(fl1h->phy_link, trx_id);
+ if (!pinst)
+ return NULL;
+
+ return pinst->trx;
+}
+
struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx,
tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id)
{
@@ -282,10 +294,9 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg,
}
/* For OctPHY, this only about sending state changes to BSC */
-int l1if_activate_rf(struct octphy_hdl *fl1h, int on)
+int l1if_activate_rf(struct gsm_bts_trx *trx, int on)
{
int i;
- struct gsm_bts_trx *trx = fl1h->priv;
if (on) {
/* signal availability */
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
@@ -422,7 +433,8 @@ static void empty_req_from_rts_ind(tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_E
static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
struct osmo_phsap_prim *l1sap)
{
- struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct msgb *l1msg = l1p_msgb_alloc();
uint32_t u32Fn;
uint8_t u8Tn, subCh, sapi = 0;
@@ -489,7 +501,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&data_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID);
- data_req->TrxId.byTrxId = trx->nr;
+ data_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
data_req->LchId.byTimeslotNb = u8Tn;
data_req->LchId.bySAPI = sapi;
data_req->LchId.bySubChannelNb = subCh;
@@ -508,7 +520,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&empty_frame_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID);
- empty_frame_req->TrxId.byTrxId = trx->nr;
+ empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
empty_frame_req->LchId.byTimeslotNb = u8Tn;
empty_frame_req->LchId.bySAPI = sapi;
empty_frame_req->LchId.bySubChannelNb = subCh;
@@ -527,7 +539,8 @@ done:
static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
struct osmo_phsap_prim *l1sap)
{
- struct octphy_hdl *fl1h = trx_octphy_hdl(trx);
+ struct phy_instance *pinst = trx_phy_instance(trx);
+ struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl;
struct gsm_lchan *lchan;
uint32_t u32Fn;
uint8_t u8Tn, subCh, sapi, ss;
@@ -565,7 +578,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&data_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID);
- data_req->TrxId.byTrxId = trx->nr;
+ data_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
data_req->LchId.byTimeslotNb = u8Tn;
data_req->LchId.bySAPI = sapi;
data_req->LchId.bySubChannelNb = subCh;
@@ -590,7 +603,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
l1if_fill_msg_hdr(&empty_frame_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID);
- empty_frame_req->TrxId.byTrxId = trx->nr;
+ empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id;
empty_frame_req->LchId.byTimeslotNb = u8Tn;
empty_frame_req->LchId.bySAPI = sapi;
empty_frame_req->LchId.bySubChannelNb = subCh;
@@ -686,32 +699,78 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
return rc;
}
+static int trx_close_all_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data)
+{
+ tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car =
+ (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h;
+
+ /* in a completion call-back, we take msgb ownership and must
+ * release it before returning */
+
+ mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP_SWAP(car);
+
+ /* we now know that the PHY link is connected */
+ phy_link_state_set(fl1->phy_link, PHY_LINK_CONNECTED);
+
+ msgb_free(resp);
+
+ return 0;
+}
+
+static int phy_link_trx_close_all(struct phy_link *plink)
+{
+ struct octphy_hdl *fl1h = plink->u.octphy.hdl;
+ struct msgb *msg = l1p_msgb_alloc();
+ tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac;
+
+ cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *)
+ msgb_put(msg, sizeof(*cac));
+ l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
+ cOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CID);
+
+ mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD_SWAP(cac);
+
+ return l1if_req_compl(fl1h, msg, trx_close_all_cb, NULL);
+}
+
+int bts_model_phy_link_open(struct phy_link *plink)
+{
+ if (plink->u.octphy.hdl)
+ l1if_close(plink->u.octphy.hdl);
+
+ phy_link_state_set(plink, PHY_LINK_CONNECTING);
+
+ plink->u.octphy.hdl = l1if_open(plink);
+ if (!plink->u.octphy.hdl) {
+ phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
+ return -1;
+ }
+
+ /* do we need to iterate over the list of instances and do some
+ * instance-specific initialization? */
+
+ /* close all TRXs that might still exist in this link from
+ * previous execitions / sessions */
+ phy_link_trx_close_all(plink);
+
+ /* in the call-back to the above we will set the link state to
+ * connected */
+
+ return 0;
+}
+
int bts_model_init(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb;
- struct octphy_hdl *fl1h;
LOGP(DL1C, LOGL_NOTICE, "model_init()\n");
btsb = bts_role_bts(bts);
btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
- fl1h = talloc_zero(bts, struct octphy_hdl);
- if (!fl1h)
- return -ENOMEM;
-
- INIT_LLIST_HEAD(&fl1h->wlc_list);
- INIT_LLIST_HEAD(&fl1h->wlc_postponed);
- fl1h->priv = bts->c0;
- bts->c0->role_bts.l1h = fl1h;
/* FIXME: what is the nominal transmit power of the PHY/board? */
bts->c0->nominal_power = 15;
- /* configure some reasonable defaults, to be overridden by VTY */
- fl1h->config.rf_port_index = 0;
- fl1h->config.rx_gain_db = 70;
- fl1h->config.tx_atten_db = 0;
-
bts_model_vty_init(bts);
return 0;
@@ -750,23 +809,15 @@ static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m)
static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn)
{
- struct gsm_bts_trx *trx = fl1->priv;
- struct gsm_bts *bts = trx->bts;
+ struct gsm_bts_trx *trx = trx_by_l1h(fl1, trx_id);
struct osmo_phsap_prim l1sap;
/* increment the primitive count for the alive timer */
fl1->alive_prim_cnt++;
/* ignore every time indication, except for c0 */
- if (trx != bts->c0)
- return 0;
-
- if (trx_id != trx->nr) {
- LOGP(DL1C, LOGL_FATAL,
- "TRX id %d from response does not match the L1 context trx %d\n",
- trx_id, trx->nr);
+ if (trx != trx->bts->c0)
return 0;
- }
memset(&l1sap, 0, sizeof(l1sap));
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
@@ -783,7 +834,7 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_READY_TO_SEND_INDICATION_EVT *evt,
struct msgb *l1p_msg)
{
- struct gsm_bts_trx *trx = fl1->priv;
+ struct gsm_bts_trx *trx = trx_by_l1h(fl1, evt->TrxId.byTrxId);
struct gsm_bts *bts = trx->bts;
struct osmo_phsap_prim *l1sap;
struct gsm_time g_time;
@@ -908,7 +959,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT *data_ind,
struct msgb *l1p_msg)
{
- struct gsm_bts_trx *trx = fl1->priv;
+ struct gsm_bts_trx *trx = trx_by_l1h(fl1, data_ind->TrxId.byTrxId);
uint8_t chan_nr, link_id;
struct osmo_phsap_prim *l1sap;
uint32_t fn;
@@ -992,7 +1043,7 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1,
tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_RACH_INDICATION_EVT *ra_ind,
struct msgb *l1p_msg)
{
- struct gsm_bts_trx *trx = fl1->priv;
+ struct gsm_bts_trx *trx = trx_by_l1h(fl1, ra_ind->TrxId.byTrxId);
struct gsm_bts *bts = trx->bts;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
struct gsm_lchan *lchan;
@@ -1131,7 +1182,7 @@ static int rx_octvc1_resp(struct msgb *msg, uint32_t msg_id, uint32_t trans_id)
if (wlc->cb) {
/* call-back function must take msgb
* ownership. */
- rc = wlc->cb(fl1h->priv, msg, wlc->cb_data);
+ rc = wlc->cb(fl1h, msg, wlc->cb_data);
} else {
rc = 0;
msgb_free(msg);
@@ -1485,6 +1536,18 @@ static int rx_octphy_msg(struct msgb *msg)
return rc;
}
+void bts_model_phy_link_set_defaults(struct phy_link *plink)
+{
+ /* configure some reasonable defaults, to be overridden by VTY */
+ plink->u.octphy.rf_port_index = 0;
+ plink->u.octphy.rx_gain_db = 70;
+ plink->u.octphy.tx_atten_db = 0;
+}
+
+void bts_model_phy_instance_set_defaults(struct phy_instance *pinst)
+{
+}
+
/***********************************************************************
* octphy socket / main loop integration
***********************************************************************/
@@ -1534,15 +1597,25 @@ static int octphy_write_cb(struct osmo_fd *fd, struct msgb *msg)
return rc;
}
-int l1if_open(struct octphy_hdl *fl1h)
+struct octphy_hdl *l1if_open(struct phy_link *plink)
{
+ struct octphy_hdl *fl1h;
struct ifreq ifr;
int sfd, rc;
- char *phy_dev = fl1h->netdev_name;
+ char *phy_dev = plink->u.octphy.netdev_name;
+
+ fl1h = talloc_zero(plink, struct octphy_hdl);
+ if (!fl1h)
+ return NULL;
+
+ INIT_LLIST_HEAD(&fl1h->wlc_list);
+ INIT_LLIST_HEAD(&fl1h->wlc_postponed);
+ fl1h->phy_link = plink;
if (!phy_dev) {
LOGP(DL1C, LOGL_ERROR, "You have to specify a phy-netdev\n");
- return -EINVAL;
+ talloc_free(fl1h);
+ return NULL;
}
LOGP(DL1C, LOGL_NOTICE, "Opening L1 interface for OctPHY (%s)\n",
@@ -1553,7 +1626,8 @@ int l1if_open(struct octphy_hdl *fl1h)
if (sfd < 0) {
LOGP(DL1C, LOGL_FATAL, "Error opening PHY socket: %s\n",
strerror(errno));
- return -EIO;
+ talloc_free(fl1h);
+ return NULL;
}
/* resolve the string device name to an ifindex */
@@ -1564,18 +1638,21 @@ int l1if_open(struct octphy_hdl *fl1h)
LOGP(DL1C, LOGL_FATAL, "Error using network device %s: %s\n",
phy_dev, strerror(errno));
close(sfd);
- return -EIO;
+ talloc_free(fl1h);
+ return NULL;
}
fl1h->session_id = rand();
- /* set fl1h->phy_addr, which we use as sendto() destionation */
+ /* set fl1h->phy_addr, which we use as sendto() destination */
fl1h->phy_addr.sll_family = AF_PACKET;
fl1h->phy_addr.sll_protocol = htons(cOCTPKT_HDR_ETHERTYPE);
fl1h->phy_addr.sll_ifindex = ifr.ifr_ifindex;
fl1h->phy_addr.sll_hatype = ARPHRD_ETHER;
- fl1h->phy_addr.sll_halen = 6;
- /* sll_addr is filled by bts_model_vty code */
+ fl1h->phy_addr.sll_halen = ETH_ALEN;
+ /* plink->phy_addr.sll_addr is filled by bts_model_vty code */
+ memcpy(fl1h->phy_addr.sll_addr, plink->u.octphy.phy_addr.sll_addr,
+ ETH_ALEN);
/* Write queue / osmo_fd registration */
osmo_wqueue_init(&fl1h->phy_wq, 10);
@@ -1588,10 +1665,11 @@ int l1if_open(struct octphy_hdl *fl1h)
rc = osmo_fd_register(&fl1h->phy_wq.bfd);
if (rc < 0) {
close(sfd);
- return -EIO;
+ talloc_free(fl1h);
+ return NULL;
}
- return 0;
+ return fl1h;
}
int l1if_close(struct octphy_hdl *fl1h)