osmo-bts/src/osmo-bts-bb/l1_if.c

322 lines
7.3 KiB
C

/* Interface to layer 1 of baseband */
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/lapdm.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/signal.h>
#include "l1ctl.h"
#include "l1_if.h"
#include "oml.h"
#include "settings.h"
extern int layout;
static struct msgb *osmo_l1if_alloc(uint8_t msg_type)
{
struct l1if_hdr *l1h;
struct msgb *msg = msgb_alloc_headroom(256, 16, "osmo_l1if");
if (!msg) {
LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory.\n");
return NULL;
}
msg->l1h = msgb_put(msg, sizeof(*l1h));
l1h = (struct l1if_hdr *) msg->l1h;
l1h->msg_type = msg_type;
return msg;
}
/* l1 confirms setup */
static int l1if_setup_conf(struct gsm_bts_trx *trx)
{
trx_init_complete(trx, 0);
LOGP(DL1C, LOGL_INFO, "L1 Setup confirm\n");
/* signal availability */
oml_mo_state_chg(&trx->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
oml_mo_tx_sw_act_rep(&trx->mo);
oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
return 0;
}
/* sending parameters to init L1's TRX */
int l1if_setup(struct gsm_bts_trx *trx)
{
uint16_t arfcn = trx->arfcn;
uint8_t bsic = trx->bts->bsic;
LOGP(DL1C, LOGL_INFO, "Setup TRX: arfcn=%d bsic=%d/%d\n",
arfcn, bsic / 8, bsic & 7);
l1if_setup_conf(trx);
return 0;
}
static int l1if_new_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type osmo_si)
{
char *name = "";
switch (osmo_si) {
case SYSINFO_TYPE_1:
name = "1";
break;
case SYSINFO_TYPE_2:
name = "2";
break;
case SYSINFO_TYPE_2bis:
name = "2bis";
break;
case SYSINFO_TYPE_2ter:
name = "2ter";
break;
case SYSINFO_TYPE_3:
name = "3";
break;
case SYSINFO_TYPE_4:
name = "4";
break;
case SYSINFO_TYPE_5:
name = "5";
break;
case SYSINFO_TYPE_5bis:
name = "5bis";
break;
case SYSINFO_TYPE_5ter:
name = "5ter";
break;
case SYSINFO_TYPE_6:
name = "6";
break;
case SYSINFO_TYPE_7:
case SYSINFO_TYPE_8:
case SYSINFO_TYPE_9:
case SYSINFO_TYPE_10:
case SYSINFO_TYPE_13:
case SYSINFO_TYPE_16:
case SYSINFO_TYPE_17:
case SYSINFO_TYPE_18:
case SYSINFO_TYPE_19:
case SYSINFO_TYPE_20:
case SYSINFO_TYPE_2quater:
case SYSINFO_TYPE_EMO:
case SYSINFO_TYPE_MEAS_INFO:
default:
LOGP(DL1C, LOGL_INFO, "Sysinfo (osmo_si %d) not supported.\n",
osmo_si);
return -ENOTSUP;
}
LOGP(DL1C, LOGL_INFO, "Providing Sysinfo %s to L1\n",
name);
return 0;
}
static int l1if_signal_cbfn(unsigned int subsys, unsigned int signal, void *hdlr_data,
void *signal_data)
{
if (subsys == SS_GLOBAL && signal == S_NEW_SYSINFO) {
struct osmo_signal_new_si *new_si = signal_data;
struct gsm_bts_trx *trx = new_si->trx;
return l1if_new_si(trx, new_si->osmo_si);
}
return 0;
}
int l1if_data_req_cb(struct osmo_prim_hdr *oph, void *ctx)
{
}
static int l1if_reset_cnf(struct osmo_l1ctl *l1ctl, struct msgb *msg)
{
int i = l1ctl->bb_role;
struct osmo_l1_if *l1if = l1ctl->l1_if;
struct gsm_bts_trx *trx = l1if->trx;
int on = 1; // FIXME: handle failure (wrong firmware)
LOGP(DL1C, LOGL_INFO, "Reset of baseband %d complete.\n", i + 1);
l1if->reset_cnf[i] = 1;
for (i = 0; i < l1if->num_phones; i++) {
if (!l1if->reset_cnf[i]) {
LOGP(DL1C, LOGL_INFO, "Waiting for more basebands.\n");
return 0;
}
}
LOGP(DL1C, LOGL_INFO, "All basebands answered to reset.\n");
if (on) {
int s;
/* signal availability */
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK);
oml_mo_tx_sw_act_rep(&trx->mo);
oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK);
oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
for (s = 0; s < ARRAY_SIZE(trx->ts); s++)
oml_mo_state_chg(&trx->ts[s].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
} else {
oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
}
return 0;
}
int l1if_reset(struct gsm_bts_trx *trx)
{
struct osmo_l1_if *l1if = trx_l1_if(trx);
struct msgb *msg;
struct l1ctl_reset *res;
uint8_t type = L1CTL_RES_T_FULL;
int i;
for (i = 0; i < l1if->num_phones; i++) {
msg = osmo_l1if_alloc(L1IF_RESET_REQ);
if (!msg)
return -1;
LOGP(DL1C, LOGL_INFO, "Tx Reset Req (%u) of baseband %d\n",
type, i + 1);
res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
res->type = type;
l1ctl_send(&l1if->l1ctl[i], msg);
}
return 0;
}
void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, uint8_t *rtp_pl,
unsigned int rtp_pl_len)
{
}
/* Receive incoming data from L1 using L1CTL format */
int l1if_recv(struct osmo_l1ctl *l1ctl, struct msgb *msg)
{
int rc = -EINVAL;
struct l1if_hdr *l1h;
struct l1ctl_info_dl *dl;
if (msgb_l2len(msg) < sizeof(*dl)) {
LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n",
msgb_l2len(msg));
msgb_free(msg);
return -1;
}
l1h = (struct l1if_hdr *) msg->l1h;
msg->l1h = l1h->data;
switch (l1h->msg_type) {
case L1IF_RESET_IND:
case L1IF_RESET_CNF:
rc = l1if_reset_cnf(l1ctl, msg);
msgb_free(msg);
break;
default:
LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
msgb_free(msg);
break;
}
return rc;
}
int l1if_open(struct gsm_bts_trx *trx, const char *socket_path)
{
struct osmo_l1_if *l1if;
char pathname[128];
int rc;
int i;
osmo_signal_register_handler(SS_GLOBAL, l1if_signal_cbfn, NULL);
l1if = talloc_zero(tall_bts_ctx, struct osmo_l1_if);
if (!l1if)
return -ENOMEM;
l1if->trx = trx;
l1if->num_phones = set_num_phones(layout);
for (i = 0; i < l1if->num_phones; i++) {
l1if->l1ctl[i].bb_role = i;
l1if->l1ctl[i].l1_if = l1if;
l1if->d_mask[i] = set_get_tx_mask(layout, i);
l1if->u_mask[i] = set_get_rx_mask(layout, i);
sprintf(pathname, "%s.%d", socket_path, i + 1);
LOGP(DL1C, LOGL_INFO, "Open connection to baseband %d.\n",
i + 1);
rc = l1socket_open(&l1if->l1ctl[i], pathname);
if (rc) {
while (i--)
l1socket_close(&l1if->l1ctl[i]);
talloc_free(l1if);
return rc;
}
}
trx->role_bts.l1h = l1if;
trx->nominal_power = 23;
return 0;
}
int l1if_close(struct gsm_bts_trx *trx)
{
struct osmo_l1_if *l1if = trx_l1_if(trx);
int i;
for (i = 0; i < l1if->num_phones; i++)
l1socket_close(&l1if->l1ctl[i]);
talloc_free(l1if);
osmo_signal_unregister_handler(SS_GLOBAL, l1if_signal_cbfn, NULL);
return 0;
}