Review at https://gerrit.osmocom.org/3199
VIRT_PHY: Improved l1ctl-to-l23 interface + gsmtap header parsing. Fixed mapping from gsmtap msg type to rsl msg type and vice versa. Proper chan_nr decoding instead of usage of dummy values for timeslot / link_id / subslot. Implemented missing l23 rx handler routines. Change-Id: Ibad741d112643c55091b8ba00164b05d728ae1a1 --- M src/host/virt_phy/src/gsmtapl1_if.c M src/host/virt_phy/src/gsmtapl1_if.h M src/host/virt_phy/src/l1ctl_sap.c M src/host/virt_phy/src/l1ctl_sap.h M src/host/virt_phy/src/virt_l1_model.h M src/host/virt_phy/src/virtphy.c M src/host/virt_phy/src/virtual_um.c 7 files changed, 433 insertions(+), 342 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/99/3199/1 diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c index 53cc952..d46bb2f 100644 --- a/src/host/virt_phy/src/gsmtapl1_if.c +++ b/src/host/virt_phy/src/gsmtapl1_if.c @@ -91,25 +91,43 @@ /** * Replace l11 header of given msgb by a gsmtap header and send it over the virt um. */ -void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg) +void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint32_t fn, + struct msgb *msg) { struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data; struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data; - uint8_t ss = 0; - uint8_t *data = msgb_l2(msg); // data bits to transmit (whole message without l1 header) - uint8_t data_len = msgb_l2len(msg); - struct msgb *outmsg; + 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 - outmsg = gsmtap_makemsg(l1_model_ms->state->serving_cell.arfcn, ul->chan_nr, gsmtap_chan, - ss, fn, 0, 0, data, - data_len); + 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, ×lot); + gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, ul->link_id); + + outmsg = gsmtap_makemsg(arfcn, timeslot, gsmtap_chan, subslot, fn, + signal_dbm, snr, data, data_len); if (outmsg) { - struct gsmtap_hdr *gh = msgb_data(msg); - virt_um_write_msg(l1_model_ms->vui, outmsg); - 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); + 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", + 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", + gh->arfcn, gh->type, gh->sub_type, + gh->timeslot, gh->sub_slot); + } } else { LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not be created!\n"); } @@ -119,29 +137,12 @@ } /** - * @see void gsmtapl1_tx_to_virt_um(struct virt_um_inst *vui, uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg). + * @see void gsmtapl1_tx_to_virt_um(struct virt_um_inst *vui, uint32_t fn, struct msgb *msg). */ -void gsmtapl1_tx_to_virt_um(uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg) +void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg) { - gsmtapl1_tx_to_virt_um_inst(l1_model_ms->vui, tn, fn, gsmtap_chan, msg); + gsmtapl1_tx_to_virt_um_inst(l1_model_ms->vui, fn, msg); } - -/* This is the header as it is used by gsmtap peer virtual layer 1. -struct gsmtap_hdr { - guint8 version; // version, set to 0x01 currently - guint8 hdr_len; // length in number of 32bit words - guint8 type; // see GSMTAP_TYPE_* - guint8 timeslot; // timeslot (0..7 on Um) - guint16 arfcn; // ARFCN (frequency) - gint8 signal_dbm; // signal level in dBm - gint8 snr_db; // signal/noise ratio in dB - guint32 frame_number; // GSM Frame Number (FN) - guint8 sub_type; // Type of burst/channel, see above - guint8 antenna_nr; // Antenna Number - guint8 sub_slot; // sub-slot within timeslot - guint8 res; // reserved for future use (RFU) -} - */ /** * Receive a gsmtap message from the virt um. @@ -149,81 +150,117 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui, struct msgb *msg) { - if (msg) { - // we assume we only receive msgs if we actually camp on a cell - if (l1_model_ms->state->camping) { - struct gsmtap_hdr *gh; - struct l1ctl_info_dl *l1dl; - struct msgb *l1ctl_msg = NULL; - struct l1ctl_data_ind * l1di; - - msg->l1h = msgb_data(msg); - msg->l2h = msgb_pull(msg, sizeof(*gh)); - gh = msgb_l1(msg); - - DEBUGP(DVIRPHY, - "Receiving gsmtap msg from virt um - (arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u)\n", - ntohs(gh->arfcn), ntohl(gh->frame_number), get_value_string(gsmtap_types, gh->type), get_value_string(gsmtap_channels, gh->sub_type), gh->timeslot, - gh->sub_slot); - - // compose the l1ctl message for layer 2 - switch (gh->sub_type) { - case GSMTAP_CHANNEL_RACH: - LOGP(DL1C, LOGL_NOTICE, - "Ignoring gsmtap msg from virt um - channel type is uplink only!\n"); - break; - case GSMTAP_CHANNEL_TCH_F: - l1ctl_msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND); - // TODO: implement channel handling - break; - case GSMTAP_CHANNEL_SDCCH: - case GSMTAP_CHANNEL_SDCCH4: - case GSMTAP_CHANNEL_SDCCH8: - // TODO: we might need to implement own channel handling for standalone dedicated channels - case GSMTAP_CHANNEL_AGCH: - case GSMTAP_CHANNEL_PCH: - case GSMTAP_CHANNEL_BCCH: - l1ctl_msg = l1ctl_msgb_alloc(L1CTL_DATA_IND); - l1dl = (struct l1ctl_info_dl *) msgb_put(l1ctl_msg, sizeof(struct l1ctl_info_dl)); - l1di = (struct l1ctl_data_ind *) msgb_put(l1ctl_msg, sizeof(struct l1ctl_data_ind)); - - l1dl->band_arfcn = htons(ntohs(gh->arfcn)); - l1dl->link_id = gh->timeslot; - // see GSM 8.58 -> 9.3.1 for channel number encoding - l1dl->chan_nr = rsl_enc_chan_nr(chantype_gsmtap2rsl(gh->sub_type), gh->sub_slot, gh->timeslot); - l1dl->frame_nr = htonl(ntohl(gh->frame_number)); - l1dl->snr = gh->snr_db; - l1dl->rx_level = gh->signal_dbm; - l1dl->num_biterr = 0; - l1dl->fire_crc = 0; - - memcpy(l1di->data, msgb_data(msg), msgb_length(msg)); - - break; - case GSMTAP_CHANNEL_CCCH: - case GSMTAP_CHANNEL_TCH_H: - case GSMTAP_CHANNEL_PACCH: - case GSMTAP_CHANNEL_PDCH: - case GSMTAP_CHANNEL_PTCCH: - case GSMTAP_CHANNEL_CBCH51: - case GSMTAP_CHANNEL_CBCH52: - LOGP(DL1C, LOGL_NOTICE, - "Ignoring gsmtap msg from virt um - channel type not supported!\n"); - break; - default: - LOGP(DL1C, LOGL_NOTICE, - "Ignoring gsmtap msg from virt um - channel type unknown.\n"); - break; - } - - /* forward l1ctl message to l2 */ - if(l1ctl_msg) { - l1ctl_sap_tx_to_l23(l1ctl_msg); - } - } - // handle memory deallocation - talloc_free(msg); + if (!msg) { + return; } + // we assume we only receive msgs if we actually camp on a cell + if (!l1_model_ms->state->camping) { + talloc_free(msg); + return; + } + + struct gsmtap_hdr *gh = msgb_l1(msg); + struct msgb *l1ctl_msg = NULL; + struct l1ctl_info_dl *l1dl; + uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg + uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the cell we currently camp on + uint8_t gsmtap_chantype = gh->sub_type; // gsmtap channel type + uint8_t signal_dbm = gh->signal_dbm; // signal strength, 63 is best + 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 + + 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 + chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot); + + 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 (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) { + case GSMTAP_CHANNEL_TCH_H: + case GSMTAP_CHANNEL_TCH_F: + struct l1ctl_traffic_ind * l1ti; + 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->band_arfcn = htons(arfcn); + l1dl->link_id = link_id; + l1dl->chan_nr = chan_nr; + l1dl->frame_nr = htonl(fn); + l1dl->snr = snr; + l1dl->rx_level = signal_dbm; + l1dl->num_biterr = 0; // no biterrors + l1dl->fire_crc = 0; + + // TODO: traffic decoding and decryption + + memcpy(l1ti->data, msgb_data(msg), msgb_length(msg)); + break; + case GSMTAP_CHANNEL_SDCCH4: + case GSMTAP_CHANNEL_SDCCH8: + // TODO: we might need to implement own channel handling for standalone dedicated channels + case GSMTAP_CHANNEL_AGCH: + case GSMTAP_CHANNEL_PCH: + case GSMTAP_CHANNEL_BCCH: + struct l1ctl_data_ind * l1di; + l1ctl_msg = l1ctl_msgb_alloc(L1CTL_DATA_IND); + l1dl = (struct l1ctl_info_dl *)msgb_put(l1ctl_msg, + sizeof(struct l1ctl_info_dl)); + l1di = (struct l1ctl_data_ind *)msgb_put(l1ctl_msg, + sizeof(struct l1ctl_data_ind)); + + l1dl->band_arfcn = htons(arfcn); + l1dl->link_id = link_id; + l1dl->chan_nr = chan_nr; + l1dl->frame_nr = htonl(fn); + l1dl->snr = snr; + l1dl->rx_level = signal_dbm; + l1dl->num_biterr = 0; // no biterrors + l1dl->fire_crc = 0; // TODO: check if this means fire crc is not used or crc produced no error + + // TODO: data decoding and decryption + + memcpy(l1di->data, msgb_data(msg), msgb_length(msg)); + + break; + case GSMTAP_CHANNEL_RACH: + LOGP(DVIRPHY, LOGL_NOTICE, + "Ignoring gsmtap msg from virt um - channel type is uplink only!\n"); + break; + case GSMTAP_CHANNEL_SDCCH: + 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(DVIRPHY, LOGL_NOTICE, + "Ignoring gsmtap msg from virt um - channel type not supported!\n"); + break; + default: + LOGP(DVIRPHY, LOGL_NOTICE, + "Ignoring gsmtap msg from virt um - channel type unknown.\n"); + break; + } + + /* forward l1ctl message to l2 */ + if (l1ctl_msg) { + l1ctl_sap_tx_to_l23(l1ctl_msg); + } + // handle memory deallocation + talloc_free(msg); } /** @@ -236,41 +273,77 @@ /*! \brief convert GSMTAP channel type to RSL channel number * \param[in] gsmtap_chantype GSMTAP channel type - * \returns RSL channel type + * \param[out] rsl_chantype rsl channel type + * \param[out] rsl_chantype rsl link id + * + * Mapping from gsmtap channel: + * GSMTAP_CHANNEL_UNKNOWN * 0x00 + * GSMTAP_CHANNEL_BCCH * 0x01 + * GSMTAP_CHANNEL_CCCH * 0x02 + * GSMTAP_CHANNEL_RACH * 0x03 + * GSMTAP_CHANNEL_AGCH * 0x04 + * GSMTAP_CHANNEL_PCH * 0x05 + * GSMTAP_CHANNEL_SDCCH * 0x06 + * GSMTAP_CHANNEL_SDCCH4 * 0x07 + * GSMTAP_CHANNEL_SDCCH8 * 0x08 + * GSMTAP_CHANNEL_TCH_F * 0x09 + * GSMTAP_CHANNEL_TCH_H * 0x0a + * GSMTAP_CHANNEL_PACCH * 0x0b + * GSMTAP_CHANNEL_CBCH52 * 0x0c + * GSMTAP_CHANNEL_PDCH * 0x0d + * GSMTAP_CHANNEL_PTCCH * 0x0e + * GSMTAP_CHANNEL_CBCH51 * 0x0f + * to rsl channel type: + * RSL_CHAN_NR_MASK * 0xf8 + * RSL_CHAN_NR_1 * * 0x08 + * RSL_CHAN_Bm_ACCHs * 0x08 + * RSL_CHAN_Lm_ACCHs * 0x10 + * RSL_CHAN_SDCCH4_ACCH * 0x20 + * RSL_CHAN_SDCCH8_ACCH * 0x40 + * RSL_CHAN_BCCH * * 0x80 + * RSL_CHAN_RACH * * 0x88 + * RSL_CHAN_PCH_AGCH * 0x90 + * RSL_CHAN_OSMO_PDCH * 0xc0 + * and logical channel link id: + * LID_SACCH * * 0x40 + * LID_DEDIC * * 0x00 + * + * TODO: move this to a library used by both ms and bts virt um */ -uint8_t chantype_gsmtap2rsl(uint8_t gsmtap_chantype) +void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype, + uint8_t *link_id) { - // TODO: proper retval for unknown channel - uint8_t ret = 0; - - switch (gsmtap_chantype) { - case GSMTAP_CHANNEL_TCH_F: - ret = RSL_CHAN_Bm_ACCHs; + // switch case with removed acch flag + switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) { + case GSMTAP_CHANNEL_TCH_F: // TCH/F, FACCH/F + *rsl_chantype = RSL_CHAN_Bm_ACCHs; break; - case GSMTAP_CHANNEL_TCH_H: - ret = RSL_CHAN_Lm_ACCHs; + case GSMTAP_CHANNEL_TCH_H: // TCH/H, FACCH/H + *rsl_chantype = RSL_CHAN_Lm_ACCHs; break; - case GSMTAP_CHANNEL_SDCCH4: - ret = RSL_CHAN_SDCCH4_ACCH; + case GSMTAP_CHANNEL_SDCCH4: // SDCCH/4 + *rsl_chantype = RSL_CHAN_SDCCH4_ACCH; break; - case GSMTAP_CHANNEL_SDCCH8: - ret = RSL_CHAN_SDCCH8_ACCH; + case GSMTAP_CHANNEL_SDCCH8: // SDCCH/8 + *rsl_chantype = RSL_CHAN_SDCCH8_ACCH; break; - case GSMTAP_CHANNEL_BCCH: - ret = RSL_CHAN_BCCH; + case GSMTAP_CHANNEL_BCCH: // BCCH + *rsl_chantype = RSL_CHAN_BCCH; break; - case GSMTAP_CHANNEL_RACH: - ret = RSL_CHAN_RACH; + case GSMTAP_CHANNEL_RACH: // RACH + *rsl_chantype = RSL_CHAN_RACH; break; - case GSMTAP_CHANNEL_PCH: - case GSMTAP_CHANNEL_AGCH: - ret = RSL_CHAN_PCH_AGCH; + case GSMTAP_CHANNEL_PCH: // PCH + case GSMTAP_CHANNEL_AGCH: // AGCH + *rsl_chantype = RSL_CHAN_PCH_AGCH; + break; + case GSMTAP_CHANNEL_PDCH: + *rsl_chantype = GSMTAP_CHANNEL_PDCH; break; } - // TODO: check how to handle this... -// if (link_id & 0x40) -// ret |= GSMTAP_CHANNEL_ACCH; + *link_id = gsmtap_chantype & GSMTAP_CHANNEL_ACCH ? + LID_SACCH : + LID_DEDIC; - return ret; } diff --git a/src/host/virt_phy/src/gsmtapl1_if.h b/src/host/virt_phy/src/gsmtapl1_if.h index 09d34f4..6311e07 100644 --- a/src/host/virt_phy/src/gsmtapl1_if.h +++ b/src/host/virt_phy/src/gsmtapl1_if.h @@ -8,11 +8,11 @@ #include "virt_l1_model.h" void gsmtapl1_init(struct l1_model_ms *model); - -void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui, struct msgb *msg); +void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui, + struct msgb *msg); void gsmtapl1_rx_from_virt_um(struct msgb *msg); - -void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg); -void gsmtapl1_tx_to_virt_um(uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg); - -uint8_t chantype_gsmtap2rsl(uint8_t gsmtap_chantype); +void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint32_t fn, + struct msgb *msg); +void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg); +void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype, + uint8_t *link_id); diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c index b5fb0f0..91f1d10 100644 --- a/src/host/virt_phy/src/l1ctl_sap.c +++ b/src/host/virt_phy/src/l1ctl_sap.c @@ -4,9 +4,13 @@ #include <osmocom/core/msgb.h> #include <osmocom/core/utils.h> #include <osmocom/core/gsmtap.h> +#include <osmocom/gsm/protocol/gsm_08_58.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> +#include <osmocom/gsm/rsl.h> #include <stdio.h> #include <l1ctl_proto.h> #include <netinet/in.h> +#include <string.h> #include "virtual_um.h" #include "l1ctl_sock.h" @@ -16,6 +20,18 @@ #include "gsmtapl1_if.h" 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) { + l1_model_ms->state->tch_mode = tch_mode; + + } else { + // set default value if no proper mode was assigned by l23 + l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN; + } +} /** * @brief Init the SAP. @@ -30,7 +46,8 @@ * * 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 if (msg) { @@ -56,11 +73,11 @@ { uint16_t *len; /* prepend 16bit length before sending */ - len = (uint16_t *) msgb_push(msg, sizeof(*len)); + len = (uint16_t *)msgb_push(msg, sizeof(*len)); *len = htons(msg->len - sizeof(*len)); - if(l1ctl_sock_write_msg(lsi, msg) == -1 ) { - //DEBUGP(DL1C, "Error writing to layer2 socket"); + if (l1ctl_sock_write_msg(lsi, msg) == -1) { + DEBUGP(DL1C, "Error writing to layer2 socket"); } } @@ -140,22 +157,22 @@ /** * @brief General handler for incoming L1CTL messages from layer 2/3. * - * This handler will dequeue the rx queue (if !empty) and call the specific routine for the dequeued l1ctl message. + * This handler will call the specific routine dependent on the L1CTL message type. * */ void l1ctl_sap_handler(struct msgb *msg) { -// struct msgb *msg; struct l1ctl_hdr *l1h; - unsigned long flags; - if (!msg) + if (!msg) { return; + } l1h = (struct l1ctl_hdr *)msg->data; if (sizeof(*l1h) > msg->len) { - LOGP(DL1C, LOGL_NOTICE, "Short message. %u\n", msg->len); + LOGP(DL1C, LOGL_NOTICE, "Malformed message: too short. %u\n", + msg->len); goto exit_msgbfree; } @@ -182,7 +199,6 @@ l1ctl_rx_rach_req(msg); // msg is freed by rx routine goto exit_nofree; - break; case L1CTL_DATA_REQ: l1ctl_rx_data_req(msg); /* we have to keep the msgb, not free it! */ @@ -229,24 +245,29 @@ * Transmit frequency control and synchronisation bursts on FCCH and SCH to calibrate transceiver and search for base stations. * Sync to a given arfcn. * - * Note: Not needed for virtual physical layer. + * Note: ms will start receiving msgs on virtual um only after this req was received. + * Note: virt bts does not broadcast freq and sync bursts. + * * TODO: Could be used to bind/connect to different virtual_bts sockets with a arfcn-socket mapping. + * TODO: Check flags if this is a sync or freq request and handle it accordingly. */ 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; - 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->camping = 1; - l1_model_ms->state->serving_cell.arfcn = ntohs(sync_req->band_arfcn); - l1_model_ms->state->serving_cell.ccch_mode = sync_req->ccch_mode; - l1_model_ms->state->serving_cell.fn_offset = 0; - l1_model_ms->state->serving_cell.bsic = 0; - l1_model_ms->state->serving_cell.time_alignment = 0; - // TODO: reset and synchronize the ms uplink schedulers with bts multiframe structure. + l1_model_ms->state->serving_cell.arfcn = ntohs(sync_req->band_arfcn); // freq req + + // not needed in virt um + l1_model_ms->state->serving_cell.ccch_mode = sync_req->ccch_mode; // sync req + l1_model_ms->state->serving_cell.fn_offset = 0; // sync req + l1_model_ms->state->serving_cell.bsic = 0; // sync req + l1_model_ms->state->serving_cell.time_alignment = 0; // sync req l1ctl_tx_fbsb_conf(0, l1_model_ms->state->serving_cell.arfcn); } @@ -268,47 +289,25 @@ 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, ×lot); DEBUGP(DL1C, - "Received and handled from l23 - L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n", - ntohs(est_req->h0.band_arfcn), ul->chan_nr, - est_req->tsc); + "Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u)\n", + ul->chan_nr, timeslot); -// /* disable neighbour cell measurement of C0 TS 0 */ -// mframe_disable(MF_TASK_NEIGH_PM51_C0T0); -// -// /* configure dedicated channel state */ -// l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr); -// l1s.dedicated.tsc = est_req->tsc; -// l1s.dedicated.tn = ul->chan_nr & 0x7; -// l1s.dedicated.h = est_req->h; -// -// if (est_req->h) { -// int i; -// l1s.dedicated.h1.hsn = est_req->h1.hsn; -// l1s.dedicated.h1.maio = est_req->h1.maio; -// l1s.dedicated.h1.n = est_req->h1.n; -// for (i=0; i<est_req->h1.n; i++) -// l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]); -// } else { -// l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn); -// } -// -// /* TCH config */ -// if (chan_nr_is_tch(ul->chan_nr)) { -// /* Mode */ -// l1a_tch_mode_set(est_req->tch_mode); -// l1a_audio_mode_set(est_req->audio_mode); -// -// /* Sync */ -// l1s.tch_sync = 1; /* can be set without locking */ -// -// /* Audio path */ -// audio_set_enabled(est_req->tch_mode, est_req->audio_mode); -// } -// -// /* figure out which MF tasks to enable */ -// l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM)); + l1_model_ms->state->dedicated.chan_type = rsl_chantype; + l1_model_ms->state->dedicated.tn = timeslot; + + /* TCH config */ + 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 + } } /** @@ -320,7 +319,7 @@ * * Handle frequency change in dedicated mode. E.g. used for frequency hopping. * - * Note: Not needed for virtual physical layer. + * Note: Not needed for virtual physical layer as freqency hopping is generally disabled. */ void l1ctl_rx_dm_freq_req(struct msgb *msg) { @@ -330,8 +329,9 @@ (struct l1ctl_dm_freq_req *)ul->payload; DEBUGP(DL1C, - "Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n", - ntohs(freq_req->h0.band_arfcn), freq_req->tsc); + "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); } /** @@ -359,12 +359,14 @@ "Received and handled from l23 - L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len); -// if (cr->algo && key_len != 8) { -// DEBUGP(DL1C, "L1CTL_CRYPTO_REQ -> Invalid key\n"); -// return; -// } -// -// dsp_load_ciph_param(cr->algo, cr->key); + if (cr->algo && key_len != A5_KEY_LEN) { + DEBUGP(DL1C, "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); } /** @@ -380,19 +382,13 @@ */ void l1ctl_rx_dm_rel_req(struct msgb *msg) { -// struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data; + DEBUGP(DL1C, "Received and handled from l23 - L1CTL_DM_REL_REQ\n"); - DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_DM_REL_REQ\n"); -// l1a_mftask_set(0); -// l1s.dedicated.type = GSM_DCHAN_NONE; -// l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]); -// l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]); -// l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_TRAFFIC]); -// l1a_meas_msgb_set(NULL); -// dsp_load_ciph_param(0, NULL); -// l1a_tch_mode_set(GSM48_CMODE_SIGN); -// audio_set_enabled(GSM48_CMODE_SIGN, 0); -// l1s.neigh_pm.n = 0; + l1_model_ms->state->dedicated.chan_type = 0; + l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN; + + // TODO: disable ciphering + // TODO: disable audio recording / playing } /** @@ -424,44 +420,38 @@ * * @param [in] msg the received message. * - * Transmit RACH request on RACH. + * Transmit RACH request on RACH. Refer to 04.08 - 9.1.8 - Channel request. * - * TODO: Implement this handler routine! */ 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; - - uint32_t fn_sched; - uint8_t ts; + 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; + // FIXME: proper frame number + uint32_t fn_sched = 42; DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n", rach_req->ra, ntohs(rach_req->offset), rach_req->combined); - // TODO: calculate correct fn/ts for a RACH (if needed by bts) - // TODO: implement scheduler for uplink! - fn_sched = 42; - ts = 0; // for the rach channel request, there is no layer2 header, but only the one bit ra content to submit - // see 4.18-9.1.8 CHannel Request - // that means we have to set l2h of msgb to the ra content - msg->l2h = &rach_req->ra; - // avoid all data after ra to also be submitted - msgb_trim(msg, sizeof(rach_req->ra)); - // TODO: check if we need to submit more data than the ra content to the bts + // replace l1ctl_rach_req with ra data that rly shall be submitted + // ra on peer side is decoded as uint16_t, but we do not use the 11bit option and thus 8bits must be sufficient + msg->l2h = msgb_put(msg, sizeof(uint8_t)); + *msg->l2h = rach_req->ra; + + // chan_nr is not specified in info_ul for rach request coming from l23, but needed in gsmtapl1_tx_to_virt_um() + ul->chan_nr = rsl_enc_chan_nr(RSL_CHAN_RACH, 0, 0); + ul->link_id = LID_DEDIC; // send rach over virt um - gsmtapl1_tx_to_virt_um(ts, fn_sched, GSMTAP_CHANNEL_RACH, msg); + gsmtapl1_tx_to_virt_um(fn_sched, msg); // send confirm to layer23 l1ctl_tx_rach_conf(fn_sched, l1_model_ms->state->serving_cell.arfcn); -// l1a_rach_req(ntohs(rach_req->offset), rach_req->combined, -// rach_req->ra); } /** @@ -473,36 +463,29 @@ * * Transmit message on a signalling channel. FACCH/SDCCH or SACCH depending on the headers set link id (TS 8.58 - 9.3.2). * - * TODO: Implement this handler routine! + * TODO: Check if a msg on FACCH is coming in here and needs special handling. */ void l1ctl_rx_data_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_data_ind *data_ind = (struct l1ctl_data_ind *)ul->payload; - struct llist_head *tx_queue; + // FIXME: proper frame number + uint32_t fn_sched = 42; DEBUGP(DL1C, - "Received and handled from l23 - L1CTL_DATA_REQ (link_id=0x%02x)\n", - ul->link_id); + "Received and handled from l23 - L1CTL_DATA_REQ (link_id=0x%02x, ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p)\n", + ul->link_id, ul, ul->payload, data_ind, data_ind->data, + msg->l3h); -// msg->l3h = data_ind->data; -// if (ul->link_id & 0x40) { -// struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5); -// if (gh->proto_discr == GSM48_PDISC_RR -// && gh->msg_type == GSM48_MT_RR_MEAS_REP) { -// DEBUGP(DL1C, "updating measurement report\n"); -// l1a_meas_msgb_set(msg); -// return; -// } -// tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH]; -// } else -// tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN]; -// -// DEBUGP(DL1C, "ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n", -// ul, ul->payload, data_ind, data_ind->data, msg->l3h); -// -// l1a_txq_msgb_enq(tx_queue, msg); + msg->l2h = data_ind->data; + + // send msg over virt um + gsmtapl1_tx_to_virt_um(fn_sched, msg); + + // send confirm to layer23 + msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn_sched, 0, 0); + l1ctl_sap_tx_to_l23(msg); } /** @@ -528,26 +511,33 @@ 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)); + 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)); pm_conf->band_arfcn = htons(arfcn_next); // rxlev 63 is great, 0 is bad the two values are min and max pm_conf->pm[0] = 63; pm_conf->pm[1] = 63; - if(arfcn_next == pm_req->range.band_arfcn_to) { + 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 in msgb, flush to l2 - if(msgb_tailroom(resp_msg) < sizeof(*pm_conf)) { + // 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); } } - if(resp_msg) { + // transmit the remaining part of pm response to l23 + if (resp_msg) { l1ctl_sap_tx_to_l23(resp_msg); } } @@ -563,7 +553,6 @@ * * Note: Currently we do not perform anything else than response with a reset confirm * to just tell l2 that we are rdy. - * TODO: Validate if an action has to be done here. * */ void l1ctl_rx_reset_req(struct msgb *msg) @@ -573,16 +562,20 @@ 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->camping = 0; + // TODO: check if we also need to reset the dedicated channel state l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type); break; case L1CTL_RES_T_SCHED: - 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; } } @@ -595,6 +588,8 @@ * @param [in] msg the received message. * * Configure CCCH combined / non-combined mode. + * + * @see l1ctl_proto.h -- enum ccch_mode * * TODO: Implement this handler routine! */ @@ -610,22 +605,7 @@ l1_model_ms->state->serving_cell.ccch_mode = ccch_mode; // check if more has to be done here - l1ctl_tx_ccch_mode_conf(ccch_mode); - -// /* pre-set the CCCH mode */ -// l1s.serving_cell.ccch_mode = ccch_mode; -// -// /* Update task */ -// mframe_disable(MF_TASK_CCCH_COMB); -// mframe_disable(MF_TASK_CCCH); -// -// if (ccch_mode == CCCH_MODE_COMBINED) -// mframe_enable(MF_TASK_CCCH_COMB); -// else if (ccch_mode == CCCH_MODE_NON_COMBINED) -// mframe_enable(MF_TASK_CCCH); -// -// l1ctl_tx_ccch_mode_conf(ccch_mode); } /** @@ -644,20 +624,18 @@ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data; struct l1ctl_tch_mode_req *tch_mode_req = (struct l1ctl_tch_mode_req *)l1h->data; - uint8_t tch_mode = tch_mode_req->tch_mode; - uint8_t audio_mode = tch_mode_req->audio_mode; + + 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, audio_mode); -// tch_mode = l1a_tch_mode_set(tch_mode); -// audio_mode = l1a_audio_mode_set(audio_mode); -// -// audio_set_enabled(tch_mode, audio_mode); -// -// l1s.tch_sync = 1; /* Needed for audio to work */ -// -// l1ctl_tx_tch_mode_conf(tch_mode, audio_mode); + tch_mode_req->tch_mode, tch_mode_req->audio_mode); + + // 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); } /** @@ -671,7 +649,7 @@ * The neighbor cell description is one of the info messages sent by the BTS on BCCH. * This method will also enable neighbor measurement in the multiframe scheduler. * - * Note: Not needed for virtual physical layer. + * Note: Not needed for virtual physical layer as we dont maintain neigbors. */ void l1ctl_rx_neigh_pm_req(struct msgb *msg) { @@ -691,30 +669,26 @@ * * @param [in] msg the received message. * - * Enqueue the message (traffic frame) to the L1 state machine's transmit queue. - * Will drop the traffic frame at queue sizes >= 4. + * Enqueue the message (traffic frame) to the L1 state machine's transmit queue. In virtual layer1 just submit it to the virt um. * - * TODO: Implement this handler routine! */ 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; - int num = 0; + uint32_t fn_sched = 42; DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n"); -// msg->l2h = tr->data; + msg->l2h = tr->data; -// num = l1a_txq_msgb_count(&l1s.tx_queue[L1S_CHAN_TRAFFIC]); -// if (num >= 4) { -// DEBUGP(DL1C, "dropping traffic frame\n"); -// msgb_free(msg); -// return; -// } -// -// l1a_txq_msgb_enq(&l1s.tx_queue[L1S_CHAN_TRAFFIC], msg); + // send msg over virt um + gsmtapl1_tx_to_virt_um(fn_sched, msg); + + // send confirm to layer23 + msg = l1ctl_create_l2_msg(L1CTL_TRAFFIC_CONF, fn_sched, 0, 0); + l1ctl_sap_tx_to_l23(msg); } /** @@ -727,6 +701,7 @@ * Forward and a sim request to the SIM APDU. * * Note: Not needed for virtual layer. Please configure layer23 application to use test-sim implementation. + * In this case layer1 wont need to handle sim logic. * ms <x> * -------- * sim test @@ -766,7 +741,7 @@ reset_resp->type = reset_type; DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n", - getL1ctlPrimName(msg_type), reset_type); + getL1ctlPrimName(msg_type), reset_type); l1ctl_sap_tx_to_l23(msg); } @@ -783,7 +758,7 @@ struct msgb * msg = l1ctl_create_l2_msg(L1CTL_RACH_CONF, fn, 0, arfcn); DEBUGP(DL1C, "Sending to l23 - %s (fn: %u, arfcn: %u)\n", - getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn); + getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn); l1ctl_sap_tx_to_l23(msg); } @@ -807,22 +782,20 @@ * @param [in] res 0 -> success, 255 -> error. * @param [in] arfcn the arfcn we are synced to. * - * No calculation needed for virtual pyh -> uses default values for a good link quality. + * No calculation needed for virtual pyh -> uses dummy values for a good link quality. */ 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. - int16_t initial_freq_err = 0; // 0 means no error. - uint8_t bsic = 0; + 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) - msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, - snr, - arfcn); + msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, snr, arfcn); - resp = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*resp)); + resp = (struct l1ctl_fbsb_conf *)msgb_put(msg, sizeof(*resp)); resp->initial_freq_err = htons(initial_freq_err); resp->result = res; resp->bsic = bsic; @@ -875,9 +848,8 @@ 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); + "Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n", + tch_mode, audio_mode); l1ctl_sap_tx_to_l23(msg); } - diff --git a/src/host/virt_phy/src/l1ctl_sap.h b/src/host/virt_phy/src/l1ctl_sap.h index f540197..9472013 100644 --- a/src/host/virt_phy/src/l1ctl_sap.h +++ b/src/host/virt_phy/src/l1ctl_sap.h @@ -15,6 +15,10 @@ #define L3_MSG_DATA 200 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr) + L3_MSG_HEAD + L3_MSG_DATA) +/* lchan link ID */ +#define LID_SACCH 0x40 +#define LID_DEDIC 0x00 + void l1ctl_sap_init(struct l1_model_ms *model); void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg); void l1ctl_sap_tx_to_l23(struct msgb *msg); diff --git a/src/host/virt_phy/src/virt_l1_model.h b/src/host/virt_phy/src/virt_l1_model.h index f0619ab..38d9efe 100644 --- a/src/host/virt_phy/src/virt_l1_model.h +++ b/src/host/virt_phy/src/virt_l1_model.h @@ -1,29 +1,65 @@ #pragma once -#include <layer1/sync.h> #include "l1ctl_sock.h" #include "virtual_um.h" + +#define L1S_NUM_NEIGH_CELL 6 +#define A5_KEY_LEN 8 struct l1_model_ms { struct l1ctl_sock_inst *lsi; struct virt_um_inst *vui; struct l1_state_ms *state; + struct crypto_info_ms *crypto_inf; }; -//TODO: must contain logical channel information (fram number, ciphering mode, ...) +/* structure representing L1 sync information about a cell */ +struct l1_cell_info { + /* on which ARFCN (+band) is the cell? */ + uint16_t arfcn; + /* what's the BSIC of the cell (from SCH burst decoding) */ + uint8_t bsic; + /* Combined or non-combined CCCH */ + uint8_t ccch_mode; /* enum ccch_mode */ + /* whats the delta of the cells current GSM frame number + * compared to our current local frame number */ + int32_t fn_offset; + /* how much does the TPU need adjustment (delta) to synchronize + * with the cells burst */ + uint32_t time_alignment; +}; + +struct crypto_info_ms { + /* key is expected in the same format as in RSL + * Encryption information IE. */ + uint8_t key[A5_KEY_LEN]; + uint8_t algo; +}; + struct l1_state_ms { - uint8_t camping; + uint8_t camping; // are we currently camping on a cell + /* the cell on which we are camping right now */ struct l1_cell_info serving_cell; - /* neighbor cell sync info */ struct l1_cell_info neigh_cell[L1S_NUM_NEIGH_CELL]; - /* TCH */ - uint8_t tch_mode; - uint8_t tch_sync; - uint8_t audio_mode; + /* TCH info */ + uint8_t tch_mode; // see enum gsm48_chan_mode in gsm_04_08.h + uint8_t tch_sync; // needed for audio synchronization + uint8_t audio_mode; // see l1ctl_proto.h, e.g. AUDIO_TX_MICROPHONE + + /* dedicated channel info */ + struct { + uint8_t chan_type; // like rsl chantype 08.58 -> Chapter 9.3.1 */ + + uint8_t tn; // timeslot number 1-7 + + uint8_t scn; // single-hop cellular network? (ununsed in virtual um) + uint8_t tsc; // training sequence code (ununsed in virtual um) + uint8_t h; // hopping enabled flag (ununsed in virtual um) + } dedicated; }; struct l1_model_ms *l1_model_ms_init(void *ctx); diff --git a/src/host/virt_phy/src/virtphy.c b/src/host/virt_phy/src/virtphy.c index 94f6fa5..b2a2d4f 100644 --- a/src/host/virt_phy/src/virtphy.c +++ b/src/host/virt_phy/src/virtphy.c @@ -17,10 +17,10 @@ int main(void) { - // init loginfo static struct l1_model_ms *model; - ms_log_init("DL1C,1:DVIRPHY,1"); + //ms_log_init("DL1C,1:DVIRPHY,1"); + ms_log_init("DL1C,1"); //ms_log_init("DL1C,8:DVIRPHY,8"); LOGP(DVIRPHY, LOGL_INFO, "Virtual physical layer starting up...\n"); @@ -28,7 +28,10 @@ model = l1_model_ms_init(NULL); // TODO: make this configurable - model->vui = virt_um_init(NULL, DEFAULT_BTS_MCAST_GROUP, DEFAULT_BTS_MCAST_PORT, DEFAULT_MS_MCAST_GROUP, DEFAULT_MS_MCAST_PORT, gsmtapl1_rx_from_virt_um_inst_cb); + model->vui = virt_um_init(NULL, DEFAULT_BTS_MCAST_GROUP, + DEFAULT_BTS_MCAST_PORT, DEFAULT_MS_MCAST_GROUP, + DEFAULT_MS_MCAST_PORT, + gsmtapl1_rx_from_virt_um_inst_cb); model->lsi = l1ctl_sock_init(NULL, l1ctl_sap_rx_from_l23_inst_cb, NULL); gsmtapl1_init(model); diff --git a/src/host/virt_phy/src/virtual_um.c b/src/host/virt_phy/src/virtual_um.c index 2b15509..e2e86e4 100644 --- a/src/host/virt_phy/src/virtual_um.c +++ b/src/host/virt_phy/src/virtual_um.c @@ -19,7 +19,6 @@ * */ -#include <unistd.h> #include <osmocom/core/select.h> #include <osmocom/core/utils.h> #include <osmocom/core/socket.h> @@ -46,10 +45,12 @@ int rc; // read message from fd in message buffer - rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), msgb_tailroom(msg)); + rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), + msgb_tailroom(msg)); // rc is number of bytes actually read if (rc > 0) { msgb_put(msg, rc); + msg->l1h = msgb_data(msg); // call the l1 callback function for a received msg vui->recv_cb(vui, msg); } else { @@ -68,12 +69,13 @@ struct virt_um_inst *virt_um_init( void *ctx, const char *tx_mcast_group, uint16_t tx_mcast_port, - const char *rx_mcast_group, uint16_t rx_mcast_port, void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg)) + const char *rx_mcast_group, uint16_t rx_mcast_port, + void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg)) { - struct virt_um_inst *vui = talloc_zero(ctx, struct virt_um_inst); - vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, tx_mcast_port, - rx_mcast_group, rx_mcast_port, 1, virt_um_fd_cb, vui); + vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, + tx_mcast_port, rx_mcast_group, rx_mcast_port, 1, + virt_um_fd_cb, vui); vui->recv_cb = recv_cb; return vui; @@ -93,7 +95,8 @@ { int rc; - rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg), msgb_length(msg)); + rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg), + msgb_length(msg)); msgb_free(msg); return rc; -- To view, visit https://gerrit.osmocom.org/3199 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ibad741d112643c55091b8ba00164b05d728ae1a1 Gerrit-PatchSet: 1 Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Owner: Harald Welte <lafo...@gnumonks.org> Gerrit-Reviewer: BastusIII <sebastian.stump...@googlemail.com>