VIRT-PHY: coding style / API usage cleanup

This is the result of my manual clean-up of the many coding style issues
found in the stumpf/virt-phy branch of OsmocomBB.  Some may remain, but
it's much closer to what we're used to in the Osmocom world now.

Change-Id: I3aa95dbef75d7749d490aad0237d074528527e8b
This commit is contained in:
Harald Welte 2017-07-12 22:58:39 +02:00
parent 020186009c
commit 7e65a1483f
12 changed files with 564 additions and 486 deletions

View File

@ -1,12 +1,12 @@
/* GSMTAP layer1 is transmits gsmtap messages over a virtual layer 1.*/
/* (C) 2016 Sebastian Stumpf
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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
* 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,
@ -14,7 +14,7 @@
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
@ -40,47 +40,45 @@
static struct l1_model_ms *l1_model_ms = NULL;
// for debugging
static const struct value_string gsmtap_channels[22] = {
{GSMTAP_CHANNEL_UNKNOWN, "UNKNOWN"},
{GSMTAP_CHANNEL_BCCH, "BCCH"},
{GSMTAP_CHANNEL_CCCH, "CCCH"},
{GSMTAP_CHANNEL_RACH, "RACH"},
{GSMTAP_CHANNEL_AGCH, "AGCH"},
{GSMTAP_CHANNEL_PCH, "PCH"},
{GSMTAP_CHANNEL_SDCCH, "SDCCH"},
{GSMTAP_CHANNEL_SDCCH4, "SDCCH/4"},
{GSMTAP_CHANNEL_SDCCH8, "SDCCH/8"},
{GSMTAP_CHANNEL_TCH_F, "TCH/F/FACCH/F"},
{GSMTAP_CHANNEL_TCH_H, "TCH/H/FACCH/H"},
{GSMTAP_CHANNEL_PACCH, "PACCH"},
{GSMTAP_CHANNEL_CBCH52, "CBCH"},
{GSMTAP_CHANNEL_PDCH, "PDCH"},
{GSMTAP_CHANNEL_PTCCH, "PTTCH"},
{GSMTAP_CHANNEL_CBCH51, "CBCH"},
{GSMTAP_CHANNEL_ACCH |
GSMTAP_CHANNEL_SDCCH, "LSACCH"},
{GSMTAP_CHANNEL_ACCH |
GSMTAP_CHANNEL_SDCCH4, "SACCH/4"},
{GSMTAP_CHANNEL_ACCH |
GSMTAP_CHANNEL_SDCCH8, "SACCH/8"},
{GSMTAP_CHANNEL_ACCH |
GSMTAP_CHANNEL_TCH_F, "SACCH/F"},
{GSMTAP_CHANNEL_ACCH |
GSMTAP_CHANNEL_TCH_H, "SACCH/H"},
{0, NULL}, };
// for debugging
static const struct value_string gsmtap_types[10] = {{
GSMTAP_TYPE_UM,
"GSM Um (MS<->BTS)"}, {GSMTAP_TYPE_ABIS, "GSM Abis (BTS<->BSC)"}, {
GSMTAP_TYPE_UM_BURST,
"GSM Um burst (MS<->BTS)"}, {GSMTAP_TYPE_SIM, "SIM"}, {
GSMTAP_TYPE_TETRA_I1,
"TETRA V+D"}, {GSMTAP_TYPE_WMX_BURST, "WiMAX burst"}, {
GSMTAP_TYPE_GMR1_UM,
"GMR-1 air interfeace (MES-MS<->GTS)"}, {
GSMTAP_TYPE_UMTS_RLC_MAC,
"UMTS RLC/MAC"}, {GSMTAP_TYPE_UMTS_RRC, "UMTS RRC"}, {0, NULL}, };
/* for debugging */
static const struct value_string gsmtap_channels[] = {
{ GSMTAP_CHANNEL_UNKNOWN, "UNKNOWN" },
{ GSMTAP_CHANNEL_BCCH, "BCCH" },
{ GSMTAP_CHANNEL_CCCH, "CCCH" },
{ GSMTAP_CHANNEL_RACH, "RACH" },
{ GSMTAP_CHANNEL_AGCH, "AGCH" },
{ GSMTAP_CHANNEL_PCH, "PCH" },
{ GSMTAP_CHANNEL_SDCCH, "SDCCH" },
{ GSMTAP_CHANNEL_SDCCH4, "SDCCH/4" },
{ GSMTAP_CHANNEL_SDCCH8, "SDCCH/8" },
{ GSMTAP_CHANNEL_TCH_F, "TCH/F/FACCH/F" },
{ GSMTAP_CHANNEL_TCH_H, "TCH/H/FACCH/H" },
{ GSMTAP_CHANNEL_PACCH, "PACCH" },
{ GSMTAP_CHANNEL_CBCH52, "CBCH" },
{ GSMTAP_CHANNEL_PDCH, "PDCH" } ,
{ GSMTAP_CHANNEL_PTCCH, "PTTCH" },
{ GSMTAP_CHANNEL_CBCH51, "CBCH" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH, "LSACCH" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH4, "SACCH/4" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH8, "SACCH/8" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_TCH_F, "SACCH/F" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_TCH_H, "SACCH/H" },
{ 0, NULL }
};
/* for debugging */
static const struct value_string gsmtap_types[10] = {
{ GSMTAP_TYPE_UM, "GSM Um (MS<->BTS)" },
{ GSMTAP_TYPE_ABIS, "GSM Abis (BTS<->BSC)" },
{ GSMTAP_TYPE_UM_BURST, "GSM Um burst (MS<->BTS)" },
{ GSMTAP_TYPE_SIM, "SIM Card" },
{ GSMTAP_TYPE_TETRA_I1, "TETRA V+D" },
{ GSMTAP_TYPE_WMX_BURST, "WiMAX burst" },
{ GSMTAP_TYPE_GMR1_UM, "GMR-1 air interfeace (MES-MS<->GTS)"},
{ GSMTAP_TYPE_UMTS_RLC_MAC, "UMTS RLC/MAC" },
{ GSMTAP_TYPE_UMTS_RRC, "UMTS RRC" },
{ 0, NULL }
};
void gsmtapl1_init(struct l1_model_ms *model)
{
@ -91,48 +89,46 @@ void gsmtapl1_init(struct l1_model_ms *model)
* Replace l11 header of given msgb by a gsmtap header and send it over the virt um.
*/
void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui,
struct msgb *msg)
struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct gsmtap_hdr *gh;
struct msgb *outmsg; // msg to send with gsmtap header prepended
uint16_t arfcn = l1_model_ms->state->serving_cell.arfcn; // arfcn of the cell we currently camp on
uint8_t signal_dbm = 63; // signal strength, 63 is best
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
struct msgb *outmsg; /* msg to send with gsmtap header prepended */
uint16_t arfcn = l1_model_ms->state->serving_cell.arfcn; /* arfcn of the cell we currently camp on */
uint8_t signal_dbm = 63; /* signal strength */
uint8_t snr = 63; /* signal noise ratio, 63 is best */
uint8_t *data = msgb_l2(msg); /* data to transmit (whole message without l1 header) */
uint8_t data_len = msgb_l2len(msg); /* length of data */
uint8_t rsl_chantype; // rsl chan type (8.58, 9.3.1)
uint8_t subslot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
uint8_t timeslot; // tdma timeslot to send in (0-7)
uint8_t gsmtap_chan; // the gsmtap channel
uint8_t rsl_chantype; /* rsl chan type (8.58, 9.3.1) */
uint8_t subslot; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
uint8_t timeslot; /* tdma timeslot to send in (0-7) */
uint8_t gsmtap_chan; /* the gsmtap channel */
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, ul->link_id);
// arfcn needs to be flagged to be able to distinguish between uplink and downlink
/* arfcn needs to be flagged to be able to distinguish between uplink and downlink */
outmsg = gsmtap_makemsg(arfcn | GSMTAP_ARFCN_F_UPLINK, timeslot,
gsmtap_chan, subslot, fn, signal_dbm, snr, data,
data_len);
gsmtap_chan, subslot, fn, signal_dbm, snr, data,
data_len);
if (outmsg) {
outmsg->l1h = msgb_data(outmsg);
gh = msgb_l1(outmsg);
if (virt_um_write_msg(l1_model_ms->vui, outmsg) == -1) {
LOGP(DVIRPHY,
LOGL_ERROR,
"Gsmtap msg could not send to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not send to virt um - "
"(arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
gh->arfcn, gh->type, gh->sub_type, gh->timeslot,
gh->sub_slot);
} else {
DEBUGP(DVIRPHY,
"Sending gsmtap msg to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
DEBUGP(DVIRPHY, "Sending gsmtap msg to virt um - "
"(arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
gh->arfcn, gh->type, gh->sub_type, gh->timeslot,
gh->sub_slot);
}
} else {
} else
LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not be created!\n");
}
/* free message */
msgb_free(msg);
@ -166,96 +162,89 @@ extern uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev);
* - if in MS_STATE_IDLE_SEARCHING
*/
void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
struct msgb *msg)
struct msgb *msg)
{
if (!msg) {
if (!msg)
return;
}
struct gsmtap_hdr *gh = msgb_l1(msg);
uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the received msg
uint8_t gsmtap_chantype = gh->sub_type; // gsmtap channel type
uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); // Power measurement with each received massage
uint8_t snr = gh->snr_db; // signal noise ratio, 63 is best
uint8_t subslot = gh->sub_slot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
uint8_t timeslot = gh->timeslot; // tdma timeslot to send in (0-7)
uint8_t rsl_chantype; // rsl chan type (8.58, 9.3.1)
uint8_t link_id; // rsl link id tells if this is an ssociated or dedicated link
uint8_t chan_nr; // encoded rsl channel type, timeslot and mf subslot
uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
uint8_t gsmtap_chantype = gh->sub_type; /* gsmtap channel type */
uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); /* Power measurement with each received massage */
uint8_t snr = gh->snr_db; /* signal noise ratio */
uint8_t subslot = gh->sub_slot; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
uint8_t timeslot = gh->timeslot; /* tdma timeslot to send in (0-7) */
uint8_t rsl_chantype; /* rsl chan type (8.58, 9.3.1) */
uint8_t link_id; /* rsl link id tells if this is an ssociated or dedicated link */
uint8_t chan_nr; /* encoded rsl channel type, timeslot and mf subslot */
// generally ignore all uplink messages received
/* generally ignore all uplink messages received */
if (arfcn & GSMTAP_ARFCN_F_UPLINK) {
LOGP(DVIRPHY, LOGL_NOTICE,
"Ignoring gsmtap msg from virt um - uplink flag set!\n");
LOGP(DVIRPHY, LOGL_NOTICE, "Ignoring gsmtap msg from virt um - uplink flag set!\n");
goto freemsg;
}
// we do not forward messages to l23 if we are in network search state
if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING) {
/* we do not forward messages to l23 if we are in network search state */
if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING)
goto freemsg;
}
// forward downlink msg to fbsb sync routine if we are in sync state
/* forward downlink msg to fbsb sync routine if we are in sync state */
if (l1_model_ms->state->state == MS_STATE_IDLE_SYNCING) {
prim_fbsb_sync(msg);
return;
}
// generally ignore all messages coming from another arfcn than the camped one
/* generally ignore all messages coming from another arfcn than the camped one */
if (l1_model_ms->state->serving_cell.arfcn != arfcn) {
LOGP(DVIRPHY,
LOGL_NOTICE,
LOGP(DVIRPHY, LOGL_NOTICE,
"Ignoring gsmtap msg from virt um - msg arfcn=%d not equal synced arfcn=%d!\n",
arfcn,
l1_model_ms->state->serving_cell.arfcn);
arfcn, l1_model_ms->state->serving_cell.arfcn);
goto freemsg;
}
msg->l2h = msgb_pull(msg, sizeof(*gh));
chantype_gsmtap2rsl(gsmtap_chantype, &rsl_chantype, &link_id);
// see GSM 8.58 -> 9.3.1 for channel number encoding
/* see TS 08.58 -> 9.3.1 for channel number encoding */
chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot);
gsm_fn2gsmtime(&l1_model_ms->state->downlink_time, fn);
virt_l1_sched_sync_time(l1_model_ms->state->downlink_time, 0);
virt_l1_sched_execute(fn);
DEBUGP(DVIRPHY,
"Receiving gsmtap msg from virt um - (arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
DEBUGP(DVIRPHY, "Receiving gsmtap msg from virt um - "
"(arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
arfcn, fn, get_value_string(gsmtap_types, gh->type),
get_value_string(gsmtap_channels, gsmtap_chantype), timeslot,
subslot, rsl_chantype, link_id, chan_nr);
// switch case with removed acch flag
/* switch case with removed ACCH flag */
switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
case GSMTAP_CHANNEL_TCH_H:
case GSMTAP_CHANNEL_TCH_F:
#if(0)
// TODO: handle msgs on TCH that are neither FACCH nor TCH/ACCH
if(!facch && ! tch_acch) {
#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);
snr, signal_dbm, 0, 0);
}
#endif
case GSMTAP_CHANNEL_SDCCH4:
case GSMTAP_CHANNEL_SDCCH8:
// only forward messages on dedicated channels to l2, if the timeslot and subslot is fitting
if(l1_model_ms->state->dedicated.tn == timeslot && l1_model_ms->state->dedicated.subslot == subslot) {
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr,
signal_dbm, 0, 0);
/* only forward messages on dedicated channels to l2, if
* the timeslot and subslot is fitting */
if (l1_model_ms->state->dedicated.tn == timeslot
&& l1_model_ms->state->dedicated.subslot == subslot) {
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr, signal_dbm, 0, 0);
}
break;
case GSMTAP_CHANNEL_AGCH:
case GSMTAP_CHANNEL_PCH:
case GSMTAP_CHANNEL_BCCH:
// save to just forward here, as upper layer ignores messages that do not fit the current state (e.g. gsm48_rr.c:2159)
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr,
signal_dbm, 0, 0);
/* save to just forward here, as upper layer ignores messages that
* do not fit the current state (e.g. gsm48_rr.c:2159) */
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr, signal_dbm, 0, 0);
break;
case GSMTAP_CHANNEL_RACH:
LOGP(DVIRPHY,
LOGL_NOTICE,
LOGP(DVIRPHY, LOGL_NOTICE,
"Ignoring gsmtap msg from virt um - channel type is uplink only!\n");
break;
case GSMTAP_CHANNEL_SDCCH:
@ -265,19 +254,16 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
case GSMTAP_CHANNEL_PTCCH:
case GSMTAP_CHANNEL_CBCH51:
case GSMTAP_CHANNEL_CBCH52:
LOGP(DVIRPHY,
LOGL_NOTICE,
LOGP(DVIRPHY, LOGL_NOTICE,
"Ignoring gsmtap msg from virt um - channel type not supported!\n");
break;
default:
LOGP(DVIRPHY,
LOGL_NOTICE,
LOGP(DVIRPHY, LOGL_NOTICE,
"Ignoring gsmtap msg from virt um - channel type unknown.\n");
break;
}
freemsg:
// handle memory deallocation
freemsg:
talloc_free(msg);
}

View File

@ -1,5 +1,25 @@
/* L1CTL SAP implementation. */
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/utils.h>
@ -23,12 +43,10 @@ static struct l1_model_ms *l1_model_ms = NULL;
static void l1_model_tch_mode_set(uint8_t tch_mode)
{
if (tch_mode == GSM48_CMODE_SPEECH_V1
|| tch_mode == GSM48_CMODE_SPEECH_EFR) {
if (tch_mode == GSM48_CMODE_SPEECH_V1 || tch_mode == GSM48_CMODE_SPEECH_EFR)
l1_model_ms->state->tch_mode = tch_mode;
} else {
// set default value if no proper mode was assigned by l23
else {
/* set default value if no proper mode was assigned by l23 */
l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN;
}
}
@ -51,13 +69,11 @@ void l1ctl_sap_init(struct l1_model_ms *model)
*
* Enqueues the message into the rx queue.
*/
void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi,
struct msgb *msg)
void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg)
{
// check if the received msg is not empty
/* check if the received msg is not empty */
if (msg) {
DEBUGP(DL1C, "Message incoming from layer 2: %s\n",
osmo_hexdump(msg->data, msg->len));
DEBUGP(DL1C, "Message incoming from layer 2: %s\n", osmo_hexdump(msg->data, msg->len));
l1ctl_sap_handler(msg);
}
}
@ -76,10 +92,8 @@ void l1ctl_sap_rx_from_l23(struct msgb *msg)
*/
void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg)
{
uint16_t *len;
/* prepend 16bit length before sending */
len = (uint16_t *)msgb_push(msg, sizeof(*len));
*len = htons(msg->len - sizeof(*len));
msgb_push_u16(msg, msg->len);
l1ctl_sock_write_msg(lsi, msg);
}
@ -108,15 +122,11 @@ struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
{
struct msgb *msg;
struct l1ctl_hdr *l1h;
msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
if (!msg) {
while (1) {
puts("OOPS. Out of buffers...\n");
}
return NULL;
}
l1h = (struct l1ctl_hdr *)msgb_put(msg, sizeof(*l1h));
msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
OSMO_ASSERT(msg);
l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
l1h->msg_type = msg_type;
l1h->flags = 0;
@ -142,13 +152,12 @@ struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
* [l1ctl_info_dl] : initialized with params. msgb->data points here.
* [spare-bytes] : L3_MSG_DATA bytes reserved for data. msgb->tail points here.
*/
struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
uint16_t arfcn)
struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr, uint16_t arfcn)
{
struct l1ctl_info_dl *dl;
struct msgb *msg = l1ctl_msgb_alloc(msg_type);
dl = (struct l1ctl_info_dl *)msgb_put(msg, sizeof(*dl));
dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
dl->frame_nr = htonl(fn);
dl->snr = htons(snr);
dl->band_arfcn = htons(arfcn);
@ -160,21 +169,18 @@ struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
* @brief General handler for incoming L1CTL messages from layer 2/3.
*
* This handler will call the specific routine dependent on the L1CTL message type.
*
*/
void l1ctl_sap_handler(struct msgb *msg)
{
struct l1ctl_hdr *l1h;
if (!msg) {
if (!msg)
return;
}
l1h = (struct l1ctl_hdr *)msg->data;
l1h = (struct l1ctl_hdr *) msg->data;
if (sizeof(*l1h) > msg->len) {
LOGP(DL1C, LOGL_NOTICE, "Malformed message: too short. %u\n",
msg->len);
LOGP(DL1C, LOGL_NOTICE, "Malformed message: too short. %u\n", msg->len);
goto exit_msgbfree;
}
@ -226,8 +232,11 @@ void l1ctl_sap_handler(struct msgb *msg)
break;
}
exit_msgbfree: msgb_free(msg);
exit_nofree: return; /* msg is scheduled for uplink and mustn't be freed here */
exit_msgbfree:
msgb_free(msg);
exit_nofree:
return; /* msg is scheduled for uplink and mustn't be freed here */
}
/***************************************************************
@ -248,17 +257,15 @@ void l1ctl_sap_handler(struct msgb *msg)
*/
void l1ctl_rx_dm_est_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_dm_est_req *est_req =
(struct l1ctl_dm_est_req *)ul->payload;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
uint8_t rsl_chantype, subslot, timeslot;
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u, ss=%u)\n",
ul->chan_nr, timeslot, subslot);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u, ss=%u)\n",
ul->chan_nr, timeslot, subslot);
l1_model_ms->state->dedicated.chan_type = rsl_chantype;
l1_model_ms->state->dedicated.tn = timeslot;
@ -266,12 +273,12 @@ void l1ctl_rx_dm_est_req(struct msgb *msg)
l1_model_ms->state->state = MS_STATE_DEDICATED;
/* TCH config */
if (rsl_chantype == RSL_CHAN_Bm_ACCHs
|| rsl_chantype == RSL_CHAN_Lm_ACCHs) {
if (rsl_chantype == RSL_CHAN_Bm_ACCHs || rsl_chantype == RSL_CHAN_Lm_ACCHs) {
l1_model_ms->state->tch_mode = est_req->tch_mode;
l1_model_tch_mode_set(est_req->tch_mode);
l1_model_ms->state->audio_mode = est_req->audio_mode;
// TODO: configure audio hardware for encoding / decoding / recording / playing voice
/* TODO: configure audio hardware for encoding /
* decoding / recording / playing voice */
}
}
@ -288,15 +295,12 @@ void l1ctl_rx_dm_est_req(struct msgb *msg)
*/
void l1ctl_rx_dm_freq_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_dm_freq_req *freq_req =
(struct l1ctl_dm_freq_req *)ul->payload;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_dm_freq_req *freq_req = (struct l1ctl_dm_freq_req *) ul->payload;
DEBUGP(DL1C,
"Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn0=%u, hsn=%u, maio=%u)\n",
ntohs(freq_req->h0.band_arfcn), freq_req->h1.hsn,
freq_req->h1.maio);
DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn0=%u, hsn=%u, maio=%u)\n",
ntohs(freq_req->h0.band_arfcn), freq_req->h1.hsn, freq_req->h1.maio);
}
/**
@ -315,23 +319,21 @@ void l1ctl_rx_dm_freq_req(struct msgb *msg)
*/
void l1ctl_rx_crypto_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *)ul->payload;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n",
cr->algo, key_len);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n",
cr->algo, key_len);
if (cr->algo && key_len != A5_KEY_LEN) {
DEBUGP(DL1C, "L1CTL_CRYPTO_REQ -> Invalid key\n");
LOGP(DL1C, LOGL_ERROR, "L1CTL_CRYPTO_REQ -> Invalid key\n");
return;
}
l1_model_ms->crypto_inf->algo = cr->algo;
memcpy(l1_model_ms->crypto_inf->key, cr->key,
sizeof(uint8_t) * A5_KEY_LEN);
memcpy(l1_model_ms->crypto_inf->key, cr->key, sizeof(uint8_t) * A5_KEY_LEN);
}
/**
@ -354,8 +356,8 @@ void l1ctl_rx_dm_rel_req(struct msgb *msg)
l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN;
l1_model_ms->state->state = MS_STATE_IDLE_CAMPING;
// TODO: disable ciphering
// TODO: disable audio recording / playing
/* TODO: disable ciphering */
/* TODO: disable audio recording / playing */
}
/**
@ -375,9 +377,8 @@ void l1ctl_rx_param_req(struct msgb *msg)
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_par_req *par_req = (struct l1ctl_par_req *)ul->payload;
DEBUGP(DL1C,
"Received and ignored from l23 - L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n",
par_req->ta, par_req->tx_power);
DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n",
par_req->ta, par_req->tx_power);
}
/**
@ -395,26 +396,23 @@ void l1ctl_rx_param_req(struct msgb *msg)
*/
void l1ctl_rx_reset_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_reset *reset_req = (struct l1ctl_reset *)l1h->data;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_reset *reset_req = (struct l1ctl_reset *) l1h->data;
switch (reset_req->type) {
case L1CTL_RES_T_FULL:
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
l1_model_ms->state->state = MS_STATE_IDLE_SEARCHING;
virt_l1_sched_stop();
l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
break;
case L1CTL_RES_T_SCHED:
virt_l1_sched_restart(l1_model_ms->state->downlink_time);
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
break;
default:
LOGP(DL1C, LOGL_ERROR,
"Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
LOGP(DL1C, LOGL_ERROR, "Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
break;
}
}
@ -434,16 +432,15 @@ void l1ctl_rx_reset_req(struct msgb *msg)
*/
void l1ctl_rx_ccch_mode_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_ccch_mode_req *ccch_mode_req =
(struct l1ctl_ccch_mode_req *)l1h->data;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_ccch_mode_req *ccch_mode_req = (struct l1ctl_ccch_mode_req *) l1h->data;
uint8_t ccch_mode = ccch_mode_req->ccch_mode;
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_CCCH_MODE_REQ\n");
l1_model_ms->state->serving_cell.ccch_mode = ccch_mode;
// check if more has to be done here
/* check if more has to be done here */
l1ctl_tx_ccch_mode_conf(ccch_mode);
}
@ -460,21 +457,18 @@ void l1ctl_rx_ccch_mode_req(struct msgb *msg)
*/
void l1ctl_rx_tch_mode_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_tch_mode_req *tch_mode_req =
(struct l1ctl_tch_mode_req *)l1h->data;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_tch_mode_req *tch_mode_req = (struct l1ctl_tch_mode_req *) l1h->data;
l1_model_tch_mode_set(tch_mode_req->tch_mode);
l1_model_ms->state->audio_mode = tch_mode_req->audio_mode;
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
tch_mode_req->tch_mode, tch_mode_req->audio_mode);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
tch_mode_req->tch_mode, tch_mode_req->audio_mode);
// TODO: configure audio hardware for encoding / decoding / recording / playing voice
/* TODO: configure audio hardware for encoding / decoding / recording / playing voice */
l1ctl_tx_tch_mode_conf(l1_model_ms->state->tch_mode,
l1_model_ms->state->audio_mode);
l1ctl_tx_tch_mode_conf(l1_model_ms->state->tch_mode, l1_model_ms->state->audio_mode);
}
/**
@ -492,13 +486,11 @@ void l1ctl_rx_tch_mode_req(struct msgb *msg)
*/
void l1ctl_rx_neigh_pm_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_neigh_pm_req *pm_req =
(struct l1ctl_neigh_pm_req *)l1h->data;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_neigh_pm_req *pm_req = (struct l1ctl_neigh_pm_req *) l1h->data;
DEBUGP(DL1C,
"Received and ignored from l23 - L1CTL_NEIGH_PM_REQ new list with %u entries\n",
pm_req->n);
DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_NEIGH_PM_REQ new list with %u entries\n",
pm_req->n);
}
/**
@ -525,9 +517,8 @@ void l1ctl_rx_sim_req(struct msgb *msg)
uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
DEBUGP(DL1C,
"Received and ignored from l23 - SIM Request length: %u, data: %s: ",
len, osmo_hexdump(data, sizeof(data)));
LOGP(DL1C, LOGL_ERROR, "Received and ignored from l23 - SIM Request length: %u, data: %s\n",
len, osmo_hexdump(data, sizeof(data)));
}
@ -548,12 +539,11 @@ void l1ctl_rx_sim_req(struct msgb *msg)
void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
{
struct msgb *msg = l1ctl_msgb_alloc(msg_type);
struct l1ctl_reset *reset_resp;
reset_resp = (struct l1ctl_reset *)msgb_put(msg, sizeof(*reset_resp));
reset_resp->type = reset_type;
struct l1ctl_reset *reset_resp = (struct l1ctl_reset *) msgb_put(msg, sizeof(*reset_resp));
reset_resp->type = reset_type;
DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n", getL1ctlPrimName(msg_type), reset_type);
DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n",
getL1ctlPrimName(msg_type), reset_type);
l1ctl_sap_tx_to_l23(msg);
}
@ -570,12 +560,11 @@ void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
{
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
struct l1ctl_ccch_mode_conf *mode_conf;
mode_conf = (struct l1ctl_ccch_mode_conf *)msgb_put(msg,
sizeof(*mode_conf));
mode_conf = (struct l1ctl_ccch_mode_conf *) msgb_put(msg, sizeof(*mode_conf));
mode_conf->ccch_mode = ccch_mode;
DEBUGP(DL1C, "Sending to l23 - L1CTL_CCCH_MODE_CONF (mode: %u)\n",
ccch_mode);
DEBUGP(DL1C, "Sending to l23 - L1CTL_CCCH_MODE_CONF (mode: %u)\n", ccch_mode);
l1ctl_sap_tx_to_l23(msg);
}
@ -593,56 +582,53 @@ void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
{
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
struct l1ctl_tch_mode_conf *mode_conf;
mode_conf = (struct l1ctl_tch_mode_conf *)msgb_put(msg,
sizeof(*mode_conf));
mode_conf = (struct l1ctl_tch_mode_conf *) msgb_put(msg, sizeof(*mode_conf));
mode_conf->tch_mode = tch_mode;
mode_conf->audio_mode = audio_mode;
DEBUGP(DL1C,
"Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n",
tch_mode, audio_mode);
DEBUGP(DL1C, "Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n",
tch_mode, audio_mode);
l1ctl_sap_tx_to_l23(msg);
}
/**
* @brief Get the scheduled fn for a msg depending on its chan_nr and link_id.
*/
uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
uint8_t link_id)
uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr, uint8_t link_id)
{
uint8_t chan_type, chan_ss, chan_ts;
rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts);
uint32_t sched_fn = cur_time.fn;
uint16_t mod_102 = cur_time.fn % 2 * 51;
rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts);
/* TODO: Replace this spaghetti monster with some lookup table */
switch (chan_type) {
case RSL_CHAN_Bm_ACCHs:
switch (link_id) {
case LID_DEDIC:
// dl=[0...11,13...24] ul=[0...11,13...24]
// skip idle frames and frames reserved for TCH_ACCH
if(cur_time.t2 == 12 || cur_time.t2 == 25) {
/* dl=[0...11,13...24] ul=[0...11,13...24]
* skip idle frames and frames reserved for TCH_ACCH */
if (cur_time.t2 == 12 || cur_time.t2 == 25)
sched_fn++;
}
break;
// dl=42, ul=42+15
/* dl=42, ul=42+15 */
case LID_SACCH:
if((chan_ts & 1)) {
// Odd traffic channel timeslot -> dl=[25] ul=[25]
// TCH_ACCH always at the end of tch multiframe (mod 26)
if ((chan_ts & 1)) {
/* Odd traffic channel timeslot -> dl=[25] ul=[25]
* TCH_ACCH always at the end of tch multiframe (mod 26) */
sched_fn -= cur_time.t2;
sched_fn += 25;
}
else {
// Even traffic channel timeslot -> dl=[12] ul=[12]
if(cur_time.t2 <= 12) {
} else {
/* Even traffic channel timeslot -> dl=[12] ul=[12] */
if (cur_time.t2 <= 12) {
sched_fn -= cur_time.t2;
sched_fn += 12;
} else {
sched_fn -= cur_time.t2;
sched_fn += 26 + 12;
}
}
break;
}
@ -653,9 +639,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
switch (chan_ss) {
case 0:
switch (link_id) {
// dl=22, ul=22+15
/* dl=22, ul=22+15 */
case LID_DEDIC:
if(cur_time.t3 <= 22 + 15) {
if (cur_time.t3 <= 22 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 22 + 15;
} else {
@ -663,9 +649,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 22 + 15;
}
break;
// dl=42, ul=42+15
/* dl=42, ul=42+15 */
case LID_SACCH:
if(mod_102 <= 42 + 15) {
if (mod_102 <= 42 + 15) {
sched_fn -= mod_102;
sched_fn += 42 + 15;
} else {
@ -677,9 +663,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 1:
switch (link_id) {
// dl=26, ul=26+15
/* dl=26, ul=26+15 */
case LID_DEDIC:
if(cur_time.t3 <= 26 + 15) {
if (cur_time.t3 <= 26 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 26 + 15;
} else {
@ -687,9 +673,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 26 + 15;
}
break;
// dl=46, ul=46+15
/* dl=46, ul=46+15 */
case LID_SACCH:
if(mod_102 <= 46 + 15) {
if (mod_102 <= 46 + 15) {
sched_fn -= mod_102;
sched_fn += 46 + 15;
} else {
@ -701,9 +687,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 2:
switch (link_id) {
// dl=32, ul=32+15
/* dl=32, ul=32+15 */
case LID_DEDIC:
if(cur_time.t3 <= 32 + 15) {
if (cur_time.t3 <= 32 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 32 + 15;
} else {
@ -711,9 +697,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 32 + 15;
}
break;
// dl=51+42, ul=51+42+15
/* dl=51+42, ul=51+42+15 */
case LID_SACCH:
if(mod_102 <= 51 + 42 + 15) {
if (mod_102 <= 51 + 42 + 15) {
sched_fn -= mod_102;
sched_fn += 51 + 42 + 15;
} else {
@ -725,9 +711,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 3:
switch (link_id) {
// dl=36, ul=36+15
/* dl=36, ul=36+15 */
case LID_DEDIC:
if(cur_time.t3 <= 36 + 15) {
if (cur_time.t3 <= 36 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 36 + 15;
} else {
@ -735,9 +721,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 36 + 15;
}
break;
// dl=51+46, ul=51+46+15
/* dl=51+46, ul=51+46+15 */
case LID_SACCH:
if(mod_102 <= 51 + 46 + 15) {
if (mod_102 <= 51 + 46 + 15) {
sched_fn -= mod_102;
sched_fn += 51 + 46 + 15;
} else {
@ -753,9 +739,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
switch (chan_ss) {
case 0:
switch (link_id) {
// dl=0, ul=0+15
/* dl=0, ul=0+15 */
case LID_DEDIC:
if(cur_time.t3 <= 0 + 15) {
if (cur_time.t3 <= 0 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 0 + 15;
} else {
@ -763,9 +749,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 0 + 15;
}
break;
// dl=32, ul=32+15
/* dl=32, ul=32+15 */
case LID_SACCH:
if(mod_102 <= 32 + 15) {
if (mod_102 <= 32 + 15) {
sched_fn -= mod_102;
sched_fn += 32 + 15;
} else {
@ -777,9 +763,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 1:
switch (link_id) {
// dl=4, ul=4+15
/* dl=4, ul=4+15 */
case LID_DEDIC:
if(cur_time.t3 <= 4 + 15) {
if (cur_time.t3 <= 4 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 4 + 15;
} else {
@ -787,9 +773,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 4 + 15;
}
break;
// dl=36, ul=36+15
/* dl=36, ul=36+15 */
case LID_SACCH:
if(mod_102 <= 36 + 15) {
if (mod_102 <= 36 + 15) {
sched_fn -= mod_102;
sched_fn += 36 + 15;
} else {
@ -801,9 +787,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 2:
switch (link_id) {
// dl=8, ul=8+15
/* dl=8, ul=8+15 */
case LID_DEDIC:
if(cur_time.t3 <= 8 + 15) {
if (cur_time.t3 <= 8 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 8 + 15;
} else {
@ -811,9 +797,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 8 + 15;
}
break;
// dl=40, ul=40+15
/* dl=40, ul=40+15 */
case LID_SACCH:
if(mod_102 <= 40 + 15) {
if (mod_102 <= 40 + 15) {
sched_fn -= mod_102;
sched_fn += 40 + 15;
} else {
@ -825,9 +811,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 3:
switch (link_id) {
// dl=12, ul=12+15
/* dl=12, ul=12+15 */
case LID_DEDIC:
if(cur_time.t3 <= 12 + 15) {
if (cur_time.t3 <= 12 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 12 + 15;
} else {
@ -835,9 +821,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 12 + 15;
}
break;
// dl=44, ul=44+15
/* dl=44, ul=44+15 */
case LID_SACCH:
if(mod_102 <= 44 + 15) {
if (mod_102 <= 44 + 15) {
sched_fn -= mod_102;
sched_fn += 44 + 15;
} else {
@ -849,9 +835,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 4:
switch (link_id) {
// dl=16, ul=16+15
/* dl=16, ul=16+15 */
case LID_DEDIC:
if(cur_time.t3 <= 16 + 15) {
if (cur_time.t3 <= 16 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 16 + 15;
} else {
@ -859,9 +845,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 16 + 15;
}
break;
// dl=51+32, ul=51+32+15
/* dl=51+32, ul=51+32+15 */
case LID_SACCH:
if(mod_102 <= 51 + 32 + 15) {
if (mod_102 <= 51 + 32 + 15) {
sched_fn -= mod_102;
sched_fn += 51 + 32 + 15;
} else {
@ -873,9 +859,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 5:
switch (link_id) {
// dl=20, ul=36+15
/* dl=20, ul=36+15 */
case LID_DEDIC:
if(cur_time.t3 <= 20 + 15) {
if (cur_time.t3 <= 20 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 20 + 15;
} else {
@ -883,9 +869,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 20 + 15;
}
break;
// dl=51+36, ul=51+36+15 ==> 0
/* dl=51+36, ul=51+36+15 ==> 0 */
case LID_SACCH:
if(mod_102 <= 0) {
if (mod_102 <= 0) {
sched_fn -= mod_102;
sched_fn += 0;
} else {
@ -897,9 +883,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 6:
switch (link_id) {
// dl=24, ul=24+15
/* dl=24, ul=24+15 */
case LID_DEDIC:
if(cur_time.t3 <= 24 + 15) {
if (cur_time.t3 <= 24 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 24 + 15;
} else {
@ -907,9 +893,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 24 + 15;
}
break;
// dl=51+40, ul=51+40+15 ==> 4
/* dl=51+40, ul=51+40+15 ==> 4 */
case LID_SACCH:
if(mod_102 <= 4) {
if (mod_102 <= 4) {
sched_fn -= mod_102;
sched_fn += 4;
} else {
@ -921,9 +907,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
break;
case 7:
switch (link_id) {
// dl=28, ul=28+15
/* dl=28, ul=28+15 */
case LID_DEDIC:
if(cur_time.t3 <= 28 + 15) {
if (cur_time.t3 <= 28 + 15) {
sched_fn -= cur_time.t3;
sched_fn += 28 + 15;
} else {
@ -931,9 +917,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
sched_fn += 51 + 28 + 15;
}
break;
// dl=51+44, ul=51+44+15 ==> 8
/* dl=51+44, ul=51+44+15 ==> 8 */
case LID_SACCH:
if(mod_102 <= 8) {
if (mod_102 <= 8) {
sched_fn -= mod_102;
sched_fn += 8;
} else {

View File

@ -1,12 +1,12 @@
/* Socket based Layer1 <-> Layer23 communication over L1CTL primitives. */
/* (C) 2016 Sebastian Stumpf
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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
* 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,
@ -14,7 +14,7 @@
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
@ -61,36 +61,39 @@
static int l1ctl_sock_data_cb(struct osmo_fd *ofd, unsigned int what)
{
struct l1ctl_sock_inst *lsi = ofd->data;
// Check if request is really read request
if (what & BSC_FD_READ) {
struct msgb *msg = msgb_alloc(L1CTL_SOCK_MSGB_SIZE,
"L1CTL sock rx");
int rc;
uint16_t len;
struct l1ctl_hdr *l1h;
// read length of the message first and convert to host byte order
rc = read(ofd->fd, &len, sizeof(len));
if (rc < sizeof(len)) {
goto ERR;
}
// convert to host byte order
len = ntohs(len);
if (len <= 0 || len > L1CTL_SOCK_MSGB_SIZE) {
goto ERR;
}
rc = read(ofd->fd, msgb_data(msg), len);
struct l1ctl_hdr *l1h;
struct msgb *msg;
uint16_t len;
int rc;
if (rc == len) {
msgb_put(msg, rc);
l1h = (void *) msgb_data(msg);
msg->l1h = l1h;
lsi->recv_cb(lsi, msg);
return 0;
}
ERR: perror(
"Failed to receive msg from l2. Connection will be closed.\n");
l1ctl_sock_disconnect(lsi);
/* Check if request is really read request */
if (!(what & BSC_FD_READ))
return 0;
msg = msgb_alloc(L1CTL_SOCK_MSGB_SIZE, "L1CTL sock rx");
/* read length of the message first and convert to host byte order */
rc = read(ofd->fd, &len, sizeof(len));
if (rc < sizeof(len))
goto err_close;
/* convert to host byte order */
len = ntohs(len);
if (len <= 0 || len > L1CTL_SOCK_MSGB_SIZE)
goto err_close;
rc = read(ofd->fd, msgb_data(msg), len);
if (rc == len) {
msgb_put(msg, rc);
l1h = (void *) msgb_data(msg);
msg->l1h = l1h;
lsi->recv_cb(lsi, msg);
return 0;
}
err_close:
perror("Failed to receive msg from l2. Connection will be closed.\n");
l1ctl_sock_disconnect(lsi);
return 0;
}
@ -142,8 +145,7 @@ struct l1ctl_sock_inst *l1ctl_sock_init(
strcpy(local_addr.sun_path, path);
unlink(local_addr.sun_path);
if ((rc = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr)))
!= 0) {
if ((rc = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr))) != 0) {
fprintf(stderr, "Failed to bind the unix domain socket. '%s'\n",
local_addr.sun_path);
return NULL;
@ -161,7 +163,7 @@ struct l1ctl_sock_inst *l1ctl_sock_init(
lsi->ofd.fd = fd;
lsi->ofd.when = BSC_FD_READ;
lsi->ofd.cb = l1ctl_sock_accept_cb;
// no connection -> invalid filedescriptor and not 0 (==std_in)
/* no connection -> invalid filedescriptor and not 0 (==std_in) */
lsi->connection.fd = -1;
lsi->l1ctl_sock_path = path;

View File

@ -1,6 +1,7 @@
/* Logging/Debug support of the virtual physical layer */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
*
@ -57,20 +58,27 @@ const char* l1ctlPrimNames[] = {
"L1CTL_TRAFFIC_CONF",
"L1CTL_TRAFFIC_IND"};
static const struct log_info_cat default_categories[] = {[DL1C] = {
.name = "DL1C",
.description = "Layer 1 Control",
.color = "\033[1;31m",
.enabled = 1,
.loglevel = LOGL_DEBUG, }, [DVIRPHY] = {
.name = "DVIRPHY",
.description = "Virtual Layer 1 Interface",
.color = "\033[1;31m",
.enabled = 1,
.loglevel = LOGL_DEBUG, }};
static const struct log_info_cat default_categories[] = {
[DL1C] = {
.name = "DL1C",
.description = "Layer 1 Control",
.color = "\033[1;31m",
.enabled = 1,
.loglevel = LOGL_DEBUG, },
[DVIRPHY] = {
.name = "DVIRPHY",
.description = "Virtual Layer 1 Interface",
.color = "\033[1;31m",
.enabled = 1,
.loglevel = LOGL_DEBUG,
}
};
const struct log_info ms_log_info = {.filter_fn = NULL, .cat =
default_categories, .num_cat = ARRAY_SIZE(default_categories), };
const struct log_info ms_log_info = {
.filter_fn = NULL,
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
/**
* Initialize the logging system for the virtual physical layer.
@ -81,9 +89,9 @@ int ms_log_init(char *cat_mask)
log_init(&ms_log_info, NULL);
stderr_target = log_target_create_stderr();
if (!stderr) {
if (!stderr)
return -1;
}
log_add_target(stderr_target);
log_set_all_filter(stderr_target, 1);
//log_set_log_level(stderr_target, 1);
@ -91,9 +99,9 @@ int ms_log_init(char *cat_mask)
log_set_use_color(stderr_target, 0);
log_set_print_timestamp(stderr_target, 1);
log_set_print_category(stderr_target, 1);
if (cat_mask) {
if (cat_mask)
log_parse_category_mask(stderr_target, cat_mask);
}
return 0;
}

View File

@ -1,3 +1,23 @@
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <virtphy/virt_l1_model.h>
#include <talloc.h>

View File

@ -1,3 +1,22 @@
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <virtphy/virt_l1_sched.h>
#include <osmocom/core/linuxlist.h>
#include <virtphy/virt_l1_model.h>
@ -14,7 +33,7 @@ static uint32_t last_exec_fn = 0;
/**
* @brief Initialize schedulers data structures.
*/
void virt_l1_sched_init(struct l1_model_ms * model)
void virt_l1_sched_init(struct l1_model_ms *model)
{
l1_model_ms = model;
}
@ -53,11 +72,10 @@ void virt_l1_sched_stop()
struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
/* Empty tdma and mframe sched items lists */
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
{
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry)
{
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry) {
talloc_free(ti_next->msg);
llist_del(&ti_next->tdma_item_entry);
}
@ -74,32 +92,31 @@ void virt_l1_sched_execute(uint32_t fn)
struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
uint8_t hyperframe_restart = fn < last_exec_fn;
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
{
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
/* execute all registered handler for current mf sched item */
uint8_t exec_now = mi_next->fn <= fn || (hyperframe_restart && mi_next->fn > last_exec_fn);
/* break loop, as we have an ordered list in case the hyperframe had not been reset */
uint8_t break_now = mi_next->fn > fn && !hyperframe_restart;
if(exec_now) {
if (exec_now) {
struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
// run through all scheduled tdma sched items for that frame number
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry)
{
// exec tdma sched item's handler callback
// TODO: we do not have a tdma scheduler currently and execute alle scheduled tdma items here at once
/* run through all scheduled tdma sched items for that frame number */
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list,
tdma_item_entry) {
/* exec tdma sched item's handler callback */
/* TODO: we do not have a TDMA scheduler currently and execute
* all scheduled tdma items here at once */
ti_next->handler_cb(mi_next->fn, ti_next->msg);
// remove handled tdma sched item
/* remove handled tdma sched item */
llist_del(&ti_next->tdma_item_entry);
}
// remove handled mframe sched item
/* remove handled mframe sched item */
llist_del(&mi_next->mframe_item_entry);
talloc_free(mi_next);
}
if(break_now) {
if (break_now)
break;
}
}
last_exec_fn = fn;
}
@ -110,36 +127,33 @@ void virt_l1_sched_execute(uint32_t fn)
void virt_l1_sched_schedule(struct msgb * msg, uint32_t fn, uint8_t ts,
virt_l1_sched_cb * handler_cb)
{
struct virt_l1_sched_mframe_item *mi_next = NULL, *mi_tmp = NULL,
*mi_fn = NULL;
struct virt_l1_sched_mframe_item *mi_next = NULL, *mi_tmp = NULL, *mi_fn = NULL;
struct virt_l1_sched_tdma_item *ti_new = NULL;
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
{
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
if (mi_next->fn == fn) {
mi_fn = mi_next;
break;
} else if (mi_next->fn > fn) {
} else if (mi_next->fn > fn)
break;
}
}
if (!mi_fn) {
// list did not contain mframe item with needed fn
/* list did not contain mframe item with needed fn */
mi_fn = talloc_zero(NULL, struct virt_l1_sched_mframe_item);
mi_fn->fn = fn;
// need to manually init the struct content.... no so happy
/* 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);
/* TODO: check if we get an error if list is empty... */
llist_add(&mi_fn->mframe_item_entry, mi_next->mframe_item_entry.prev);
}
ti_new = talloc_zero(mi_fn, struct virt_l1_sched_tdma_item);
ti_new->msg = msg;
ti_new->handler_cb = handler_cb;
ti_new->ts = ts;
// simply add at end, no ordering for tdma sched items currently
llist_add_tail(&ti_new->tdma_item_entry, &mi_fn->tdma_item_list); // TODO: ordered insert needed if tdma scheduler should be implemented
/* simply add at end, no ordering for tdma sched items currently */
llist_add_tail(&ti_new->tdma_item_entry, &mi_fn->tdma_item_list);
/* TODO: ordered insert needed if tdma scheduler should be implemented */
}

View File

@ -2,6 +2,7 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
*
@ -79,9 +80,7 @@ void l1ctl_rx_data_req(struct msgb *msg)
msg->l2h = data_ind->data;
virt_l1_sched_schedule(msg, fn_sched, timeslot,
&virt_l1_sched_handler_cb);
virt_l1_sched_schedule(msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
}
void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
@ -103,16 +102,15 @@ void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
l1dl->frame_nr = htonl(fn);
l1dl->snr = snr;
l1dl->rx_level = signal_dbm;
l1dl->num_biterr = 0; // no biterrors
l1dl->num_biterr = 0; /* no biterrors */
l1dl->fire_crc = 0;
// TODO: data decoding and decryption
/* TODO: data decoding and decryption */
memcpy(l1di->data, msgb_data(msg), msgb_length(msg));
DEBUGP(DL1C, "Sending signaling-data to l23.\n");
l1ctl_sap_tx_to_l23(l1ctl_msg);
}
/**
@ -127,7 +125,7 @@ void l1ctl_tx_data_conf(uint32_t fn, uint16_t snr, uint16_t arfcn)
{
struct msgb * l1ctl_msg;
l1ctl_msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn, snr, arfcn);
// send confirm to layer23
/* send confirm to layer23 */
l1ctl_sap_tx_to_l23(l1ctl_msg);
}

View File

@ -1,3 +1,26 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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.
*
* 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>
#include <stdio.h>
#include <string.h>
@ -31,11 +54,10 @@ static uint16_t sync_count = 0;
*/
void l1ctl_rx_fbsb_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *)l1h->data;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
ntohs(sync_req->band_arfcn), sync_req->flags);
l1_model_ms->state->state = MS_STATE_IDLE_SYNCING;
@ -50,14 +72,15 @@ void l1ctl_rx_fbsb_req(struct msgb *msg)
void prim_fbsb_sync(struct msgb *msg)
{
struct gsmtap_hdr *gh = msgb_l1(msg);
uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the received msg
uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
// ignore messages from other arfcns as the one requested to sync to by l23
/* ignore messages from other arfcns as the one requested to sync to by l23 */
if (l1_model_ms->state->fbsb.arfcn != arfcn) {
talloc_free(msg);
// cancel sync if we did not receive a msg on dl from the requested arfcn that we can sync to
if(sync_count++ > 20) {
/* cancel sync if we did not receive a msg on dl from
* the requested arfcn that we can sync to */
if (sync_count++ > 20) {
sync_count = 0;
l1_model_ms->state->state = MS_STATE_IDLE_SEARCHING;
l1ctl_tx_fbsb_conf(1, (l1_model_ms->state->fbsb.arfcn));
@ -92,10 +115,10 @@ void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
{
struct msgb *msg;
struct l1ctl_fbsb_conf *resp;
uint32_t fn = 0; // 0 should be okay here
uint16_t snr = 40; // signal noise ratio > 40db is best signal (unused in virt)
int16_t initial_freq_err = 0; // 0 means no error (unused in virt)
uint8_t bsic = 0; // bsci can be read from sync burst (unused in virt)
uint32_t fn = 0; /* 0 should be okay here */
uint16_t snr = 40; /* signal noise ratio > 40db is best signal (unused in virt)*/
int16_t initial_freq_err = 0; /* 0 means no error (unused in virt) */
uint8_t bsic = 0; /* BSIC can be read from sync burst (unused in virt) */
msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, snr, arfcn);
@ -104,8 +127,7 @@ void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
resp->result = res;
resp->bsic = bsic;
DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n",
getL1ctlPrimName(L1CTL_FBSB_CONF), res);
DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n", getL1ctlPrimName(L1CTL_FBSB_CONF), res);
l1ctl_sap_tx_to_l23(msg);
}

View File

@ -1,3 +1,26 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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.
*
* 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>
#include <stdio.h>
#include <string.h>
@ -22,19 +45,26 @@ static struct l1_model_ms *l1_model_ms = NULL;
* @param [in] arfcn to change sig str for.
* @param [in] sig_lev the measured signal level value.
*/
uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev) {
if(l1_model_ms->state->pm.timeout_s > 0 || l1_model_ms->state->pm.timeout_us > 0) {
osmo_timer_schedule(&l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[arfcn], l1_model_ms->state->pm.timeout_s, l1_model_ms->state->pm.timeout_us);
uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev)
{
if (l1_model_ms->state->pm.timeout_s > 0 || l1_model_ms->state->pm.timeout_us > 0) {
osmo_timer_schedule(&l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[arfcn],
l1_model_ms->state->pm.timeout_s,
l1_model_ms->state->pm.timeout_us);
}
l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn] = sig_lev - l1_model_ms->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn];
DEBUGP(DL1C, "Power measurement set for arfcn %u. Set signal level to %d (== rxlev: %u).\n", arfcn, l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn], dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn]));
l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn] =
sig_lev - l1_model_ms->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn];
DEBUGP(DL1C, "Power measurement set for arfcn %u. Set signal level to %d (== rxlev: %u).\n",
arfcn, l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn],
dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn]));
return l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn];
}
void prim_pm_timer_cb(void *data) {
// reset the signal level to bad value if no messages have been received from that rfcn for a given time
DEBUGP(DL1C,
"Timeout occurred for arfcn, signal level reset to worst value.\n");
void prim_pm_timer_cb(void *data)
{
/* reset the signal level to bad value if no messages have been
* received from that rfcn for a given time */
DEBUGP(DL1C, "Timeout occurred for arfcn, signal level reset to worst value.\n");
*((int16_t*)data) = MIN_SIG_LEV_DBM;
}
@ -45,50 +75,47 @@ void prim_pm_timer_cb(void *data) {
*
* @param [in] msg the received message.
*
* Process power measurement for a given range of arfcns to calculate signal power and connection quality.
*
* Note: This should only be called after a certain time so some messages have already been received.
* Process power measurement for a given range of arfcns to calculate
* signal power and connection quality.
*
* Note: This should only be called after a certain time so some
* messages have already been received.
*/
void l1ctl_rx_pm_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *)l1h->data;
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
/* 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);
DEBUGP(DL1C,
"Received from l23 - 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);
DEBUGP(DL1C, "Received from l23 - 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);
for (arfcn_next = pm_req->range.band_arfcn_from;
arfcn_next <= pm_req->range.band_arfcn_to;
++arfcn_next) {
struct l1ctl_pm_conf *pm_conf =
(struct l1ctl_pm_conf *)msgb_put(resp_msg,
sizeof(*pm_conf));
arfcn_next <= pm_req->range.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)
/* set min and max to the value calculated for that
* arfcn (IGNORE UPLINKK AND PCS AND OTHER FLAGS) */
pm_conf->pm[0] = dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
pm_conf->pm[1] = dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
if (arfcn_next == pm_req->range.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 mor pm info in msgb, flush to l23 */
if (msgb_tailroom(resp_msg) < sizeof(*pm_conf)) {
l1ctl_sap_tx_to_l23(resp_msg);
resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
}
}
// transmit the remaining part of pm response to l23
if (resp_msg) {
/* transmit the remaining part of pm response to l23 */
if (resp_msg)
l1ctl_sap_tx_to_l23(resp_msg);
}
}
/**
@ -100,10 +127,10 @@ void prim_pm_init(struct l1_model_ms *model)
{
int i;
l1_model_ms = model;
// init the signal level of all arfcns with the lowest value possible
memset (model->state->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
// init timers
for(i = 0; i < 1024; ++i) {
/* init the signal level of all arfcns with the lowest value possible */
memset(model->state->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
/* init timers */
for (i = 0; i < 1024; ++i) {
l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[i].cb = prim_pm_timer_cb;
l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[i].data = &l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[i];
}

View File

@ -2,6 +2,7 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
*
@ -39,26 +40,28 @@
static struct l1_model_ms *l1_model_ms = NULL;
static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg);
// use if we have a combined uplink (RACH, SDCCH, ...) (see http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html)
// if we have no combined channel config, uplink consists of only RACH
static uint8_t t3_to_rach_comb[51] = {
/* use if we have a combined uplink (RACH, SDCCH, ...) (see
* http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html)
* if we have no combined channel config, uplink consists of only RACH * */
static const uint8_t t3_to_rach_comb[51] = {
0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 25, 25,
25, 25, 25, 25, 25, 26, 27, 27, 27, 27};
static uint8_t rach_to_t3_comb[27] = {
25, 25, 25, 25, 25, 26, 27, 27, 27, 27
};
static const uint8_t rach_to_t3_comb[27] = {
4, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 45, 46};
30, 31, 32, 33, 34, 35, 36, 45, 46
};
/**
* @brief Handler callback function for RACH request.
*
* @param [in] msg the msg to sent over virtual um.
*/
static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb *msg)
{
gsmtapl1_tx_to_virt_um(fn, msg);
l1ctl_tx_rach_conf(fn,
l1_model_ms->state->serving_cell.arfcn);
l1ctl_tx_rach_conf(fn, l1_model_ms->state->serving_cell.arfcn);
}
/**
@ -73,30 +76,29 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
*/
void l1ctl_rx_rach_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *)ul->payload;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
uint32_t fn_sched;
uint8_t ts = 1; //FIXME mostly, ts 1 is used for rach, where can i get that info? System info?
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);
DEBUGP(DL1C,
"Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
rach_req->ra, offset, rach_req->combined);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
rach_req->ra, offset, rach_req->combined);
if (rach_req->ra == 0x03) {
if (rach_req->ra == 0x03)
fn_sched = 42;
}
// set ra data to msg (8bits, the 11bit option is not used)
/* 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
/* 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;
// sched fn calculation if we have a combined ccch channel configuration
/* 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[l1_model_ms->state->current_time.t3];
@ -104,12 +106,10 @@ void l1ctl_rx_rach_req(struct msgb *msg)
fn_sched = l1_model_ms->state->current_time.fn - l1_model_ms->state->current_time.t3;
fn_sched += offset / 27 * 51;
fn_sched += rach_to_t3_comb[offset % 27];
} else {
} else
fn_sched = l1_model_ms->state->current_time.fn + offset;
}
virt_l1_sched_schedule(msg, fn_sched, ts, &virt_l1_sched_handler_cb);
}
/**

View File

@ -2,6 +2,7 @@
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* All Rights Reserved
*
@ -63,20 +64,18 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
*/
void l1ctl_rx_traffic_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *)ul->payload;
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *) ul->payload;
uint8_t rsl_chantype, subslot, timeslot;
uint32_t fn_sched = sched_fn_ul(l1_model_ms->state->current_time,
ul->chan_nr, ul->link_id);
uint32_t fn_sched = sched_fn_ul(l1_model_ms->state->current_time, ul->chan_nr, ul->link_id);
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n");
msg->l2h = tr->data;
virt_l1_sched_schedule(msg, fn_sched, timeslot,
&virt_l1_sched_handler_cb);
virt_l1_sched_schedule(msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
}
void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
@ -89,10 +88,8 @@ void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
struct l1ctl_info_dl * l1dl;
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(struct l1ctl_info_dl));
l1ti = (struct l1ctl_traffic_ind *)msgb_put(
l1ctl_msg, sizeof(struct l1ctl_traffic_ind));
l1dl = (struct l1ctl_info_dl *) msgb_put(l1ctl_msg, sizeof(*l1dl));
l1ti = (struct l1ctl_traffic_ind *) msgb_put(l1ctl_msg, sizeof(*l1ti));
rsl_dec_chan_nr(chan_nr, &rsl_chan_type, &subchan, &timeslot);
@ -102,10 +99,10 @@ void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
l1dl->frame_nr = htonl(fn);
l1dl->snr = snr;
l1dl->rx_level = signal_dbm;
l1dl->num_biterr = 0; // no biterrors
l1dl->num_biterr = 0; /* no biterrors */
l1dl->fire_crc = 0;
// TODO: traffic decoding and decryption
/* TODO: traffic decoding and decryption */
memcpy(l1ti->data, msgb_data(msg), msgb_length(msg));
DEBUGP(DL1C, "Sending to l23 - L1CTL_TRAFFIC_IND\n");
@ -124,7 +121,7 @@ void l1ctl_tx_traffic_conf(uint32_t fn, uint16_t snr, uint16_t arfcn)
{
struct msgb * l1ctl_msg;
l1ctl_msg = l1ctl_create_l2_msg(L1CTL_TRAFFIC_CONF, fn, snr, arfcn);
// send confirm to layer23
/* send confirm to layer23 */
l1ctl_sap_tx_to_l23(l1ctl_msg);
}

View File

@ -1,5 +1,24 @@
/* osmocom includes */
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <stdint.h>
@ -18,13 +37,13 @@
#define DEFAULT_MCAST_PORT 4729 /* IANA-registered port for GSMTAP */
#define DEFAULT_LOG_MASK "DL1C,1:DVIRPHY,1"
static char* dl_rx_grp = DEFAULT_MS_MCAST_GROUP;
static char* ul_tx_grp = DEFAULT_BTS_MCAST_GROUP;
static char *dl_rx_grp = DEFAULT_MS_MCAST_GROUP;
static char *ul_tx_grp = DEFAULT_BTS_MCAST_GROUP;
static int port = DEFAULT_MCAST_PORT;
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 *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 void handle_options(int argc, char **argv)
{
@ -75,17 +94,16 @@ static void handle_options(int argc, char **argv)
void parse_pm_timeout(struct l1_model_ms *model, char *pm_timeout) {
if(!pm_timeout || (strcmp(pm_timeout, "") == 0)) {
if (!pm_timeout || (strcmp(pm_timeout, "") == 0))
return;
}
// seconds
/* seconds */
char *buf = strtok(pm_timeout, ":");
model->state->pm.timeout_s = atoi(buf);
// microseconds
/* microseconds */
buf = strtok(NULL, ":");
if(buf) {
if (buf)
model->state->pm.timeout_us = atoi(buf);
}
}
/**
@ -93,30 +111,30 @@ void parse_pm_timeout(struct l1_model_ms *model, char *pm_timeout) {
*/
void parse_arfcn_sig_lev_red(struct l1_model_ms *model, char * arfcn_sig_lev_red_mask) {
if(!arfcn_sig_lev_red_mask || (strcmp(arfcn_sig_lev_red_mask, "") == 0)) {
if (!arfcn_sig_lev_red_mask || (strcmp(arfcn_sig_lev_red_mask, "") == 0))
return;
}
char *token = strtok(arfcn_sig_lev_red_mask, ":");
do {
char* colon = strstr(token, ",");
uint16_t arfcn;
uint8_t red;
if(!colon) {
if (!colon)
continue;
}
colon[0] = '\0';
arfcn = atoi(token);
red = atoi(colon + 1);
//TODO: this may go wild if the token string is not properly formatted
/* TODO: this may go wild if the token string is not properly formatted */
model->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn] = red;
} while ((token = strtok(NULL, ":")));
}
int main(int argc, char *argv[])
{
// init loginfo
/* init loginfo */
static struct l1_model_ms *model;
handle_options(argc, argv);
@ -136,7 +154,7 @@ int main(int argc, char *argv[])
l1ctl_sap_init(model);
virt_l1_sched_init(model);
// apply timeout and arfcn reduction value config to model
/* apply timeout and arfcn reduction value config to model */
parse_pm_timeout(model, pm_timeout);
parse_arfcn_sig_lev_red(model, arfcn_sig_lev_red_mask);
@ -146,12 +164,12 @@ int main(int argc, char *argv[])
l1ctl_sock_path);
while (1) {
// handle osmocom fd READ events (l1ctl-unix-socket, virtual-um-mcast-socket)
/* handle osmocom fd READ events (l1ctl-unix-socket, virtual-um-mcast-socket) */
osmo_select_main(0);
}
l1_model_ms_destroy(model);
// not reached
/* not reached */
return EXIT_FAILURE;
}