--- configure.ac | 1 - src/Makefile.am | 2 +- src/osmo-bts-bb/Makefile.am | 8 -- src/osmo-bts-bb/l1ctl.c | 304 -------------------------------------------- src/osmo-bts-bb/main.c | 215 ------------------------------- 5 files changed, 1 insertion(+), 529 deletions(-) delete mode 100644 src/osmo-bts-bb/Makefile.am delete mode 100644 src/osmo-bts-bb/l1ctl.c delete mode 100644 src/osmo-bts-bb/main.c
diff --git a/configure.ac b/configure.ac index 5abed70..1ca0dbe 100644 --- a/configure.ac +++ b/configure.ac @@ -54,7 +54,6 @@ AC_OUTPUT( src/Makefile src/common/Makefile src/osmo-bts-sysmo/Makefile -dnl src/osmo-bts-bb/Makefile include/Makefile include/osmo-bts/Makefile tests/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 92bbed9..e2eab0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = common #osmo-bts-bb +SUBDIRS = common
if ENABLE_SYSMOBTS SUBDIRS += osmo-bts-sysmo diff --git a/src/osmo-bts-bb/Makefile.am b/src/osmo-bts-bb/Makefile.am deleted file mode 100644 index 022931a..0000000 --- a/src/osmo-bts-bb/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) -LDADD = $(LIBOSMOCORE_LIBS) - -bin_PROGRAMS = osmo-bts-bb - -osmo_bts_bb_SOURCES = main.c -osmo_bts_bb_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) diff --git a/src/osmo-bts-bb/l1ctl.c b/src/osmo-bts-bb/l1ctl.c deleted file mode 100644 index ccba37b..0000000 --- a/src/osmo-bts-bb/l1ctl.c +++ /dev/null @@ -1,304 +0,0 @@ -/* Layer1 control code, talking L1CTL protocol with L1 on the phone */ - -/* (C) 2010 by Holger Hans Peter Freyther zecke@selfish.org - * (C) 2010 by Harald Welte laforge@gnumonks.org - * (C) 2011 by Andreas Eversberg jolly@eversberg.eu - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 <stdio.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> - -#include <arpa/inet.h> - -#include <l1ctl_proto.h> - -#include <osmocom/core/signal.h> -#include <osmocom/core/timer.h> -#include <osmocom/core/msgb.h> -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/gsm_utils.h> -#include <osmocom/gsm/gsmtap_util.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/protocol/gsm_08_58.h> -#include <osmocom/gsm/rsl.h> - -#include <osmocom/bb/common/l1ctl.h> -#include <osmocom/bb/common/osmocom_data.h> -#include <osmocom/bb/common/l1l2_interface.h> -#include <osmocom/bb/common/lapdm.h> -#include <osmo-bts/logging.h> -#include <osmo-bts/abis.h> -#include <osmo-bts/rtp.h> -#include <osmo-bts/bts.h> - -static struct msgb *osmo_l1_alloc(uint8_t msg_type) -{ - struct l1ctl_hdr *l1h; - struct msgb *msg = msgb_alloc_headroom(256, 4, "osmo_l1"); - - if (!msg) { - LOGP(DL1C, LOGL_ERROR, "Failed to allocate memory.\n"); - return NULL; - } - - msg->l1h = msgb_put(msg, sizeof(*l1h)); - l1h = (struct l1ctl_hdr *) msg->l1h; - l1h->msg_type = msg_type; - - return msg; -} - - -static int osmo_make_band_arfcn(struct osmocom_ms *ms, uint16_t arfcn) -{ - /* TODO: Include the band */ - return arfcn; -} - -/* Receive L1CTL_DATA_IND (Data Indication from L1) */ -int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg) -{ - struct l1ctl_info_dl *dl, dl_cpy; - struct l1ctl_data_ind *ccch; - struct lapdm_entity *le; - struct rx_meas_stat *meas = &ms->meas; - uint8_t chan_type, chan_ts, chan_ss; - uint8_t gsmtap_chan_type; - struct gsm_time tm; - struct osmobts_ms *bts_ms = container_of(ms, struct osmobts_ms, ms); - struct osmobts_lchan *lchan; - - if (msgb_l3len(msg) < sizeof(*ccch)) { - LOGP(DL1C, LOGL_ERROR, "MSG too short Data Ind: %u\n", - msgb_l3len(msg)); - msgb_free(msg); - return -1; - } - - dl = (struct l1ctl_info_dl *) msg->l1h; - msg->l2h = dl->payload; - ccch = (struct l1ctl_data_ind *) msg->l2h; - - gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr)); - rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts); - lchan = bts_ms->trx->slot[chan_ts].lchan[chan_ss]; - if (!lchan) { - LOGP(DL1C, LOGL_ERROR, "Data IND for non existing lchan\n"); - msgb_free(msg); - return -1; - } - LOGP(DL1C, LOGL_NOTICE, "RX: %s | %s(%.4u/%.2u/%.2u) %d dBm\n", - rsl_chan_nr_str(dl->chan_nr), - hexdump(ccch->data, sizeof(ccch->data)), - tm.t1, tm.t2, tm.t3, (int)dl->rx_level-110); - - meas->last_fn = ntohl(dl->frame_nr); - meas->frames++; - meas->snr += dl->snr; - meas->berr += dl->num_biterr; - meas->rxlev += dl->rx_level; - - if (dl->fire_crc >= 2) { - LOGP(DL1C, LOGL_NOTICE, "Dropping frame with %u bit errors\n", - dl->num_biterr); - msgb_free(msg); - return 0; - } - - /* send CCCH data via GSMTAP */ - gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, dl->link_id); - gsmtap_sendmsg(ntohs(dl->band_arfcn), chan_ts, gsmtap_chan_type, chan_ss, - tm.fn, dl->rx_level-110, dl->snr, ccch->data, - sizeof(ccch->data)); - - /* determine LAPDm entity based on SACCH or not */ - if (dl->link_id & 0x40) - le = &lchan->l2_entity.lapdm_acch; - else - le = &lchan->l2_entity.lapdm_dcch; - /* make local stack copy of l1ctl_info_dl, as LAPDm will - * overwrite skb hdr */ - memcpy(&dl_cpy, dl, sizeof(dl_cpy)); - - /* pull the L1 header from the msgb */ - msgb_pull(msg, msg->l2h - (msg->l1h-sizeof(struct l1ctl_hdr))); - msg->l1h = NULL; - - /* send it up into LAPDm */ - l2_ph_data_ind(msg, le, &dl_cpy); - - return 0; -} - -/* Receive L1CTL_DATA_CONF (Data Confirm from L1) */ -static int rx_ph_data_conf(struct osmocom_ms *ms, struct msgb *msg) -{ - struct l1ctl_info_dl *dl; - struct lapdm_entity *le; - uint8_t chan_type, chan_ts, chan_ss; - struct osmobts_ms *bts_ms = container_of(ms, struct osmobts_ms, ms); - struct osmobts_lchan *lchan; - - dl = (struct l1ctl_info_dl *) msg->l1h; - - rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts); - lchan = bts_ms->trx->slot[chan_ts].lchan[chan_ss]; - if (!lchan) { - LOGP(DL1C, LOGL_ERROR, "Data IND for non existing lchan\n"); - msgb_free(msg); - return -1; - } - - /* determine LAPDm entity based on SACCH or not */ - if (dl->link_id & 0x40) - le = &lchan->l2_entity.lapdm_acch; - else - le = &lchan->l2_entity.lapdm_dcch; - - /* send it up into LAPDm */ - l2_ph_data_conf(msg, le); - - return 0; -} - -/* Transmit L1CTL_DATA_REQ */ -int l1ctl_tx_data_req(struct osmocom_ms *ms, struct msgb *msg, - uint8_t chan_nr, uint8_t link_id) -{ - struct l1ctl_hdr *l1h; - struct l1ctl_info_ul *l1i_ul; - uint8_t chan_type, chan_ts, chan_ss; - uint8_t gsmtap_chan_type; - - if (msgb_l2len(msg) > GSM_MACBLOCK_LEN) { - LOGP(DL1C, LOGL_ERROR, "L1 cannot handle message length " - "> 23 (%u)\n", msgb_l2len(msg)); - msgb_free(msg); - return -EINVAL; - } else if (msgb_l2len(msg) < GSM_MACBLOCK_LEN) - LOGP(DL1C, LOGL_ERROR, "L1 message length < 23 (%u) " - "doesn't seem right!\n", msgb_l2len(msg)); - - /* send copy via GSMTAP */ - rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts); - gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, link_id); - gsmtap_sendmsg(0|0x4000, chan_ts, gsmtap_chan_type, chan_ss, - 0, 127, 255, msg->l2h, msgb_l2len(msg)); - - LOGP(DL1C, LOGL_NOTICE, "TX: %s | %s\n", rsl_chan_nr_str(chan_nr), - hexdump(msg->l2h, msgb_l2len(msg))); - - /* prepend uplink info header */ - l1i_ul = (struct l1ctl_info_ul *) msgb_push(msg, sizeof(*l1i_ul)); - - l1i_ul->chan_nr = chan_nr; - l1i_ul->link_id = link_id; - - /* prepend l1 header */ - msg->l1h = msgb_push(msg, sizeof(*l1h)); - l1h = (struct l1ctl_hdr *) msg->l1h; - l1h->msg_type = L1CTL_DATA_REQ; - - printf("todo: transcode message\n"); - - return osmo_send_l1(ms, msg); -} - -/* Transmit L1CTL_RESET_REQ */ -int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type) -{ - struct msgb *msg; - struct l1ctl_reset *res; - - msg = osmo_l1_alloc(L1CTL_RESET_REQ); - if (!msg) - return -1; - - LOGP(DL1C, LOGL_INFO, "Tx Reset Req (%u)\n", type); - res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res)); - res->type = type; - - return osmo_send_l1(ms, msg); -} - -/* Receive L1CTL_RESET_IND */ -static int rx_l1_reset(struct osmocom_ms *ms) -{ - LOGP(DL1C, LOGL_INFO, "Layer1 Reset indication\n"); - dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms); - - return 0; -} - -/* Receive incoming data from L1 using L1CTL format */ -int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg) -{ - int rc = 0; - struct l1ctl_hdr *l1h; - struct l1ctl_info_dl *dl; - - if (msgb_l2len(msg) < sizeof(*dl)) { - LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n", - msgb_l2len(msg)); - msgb_free(msg); - return -1; - } - - l1h = (struct l1ctl_hdr *) msg->l1h; - - /* move the l1 header pointer to point _BEHIND_ l1ctl_hdr, - as the l1ctl header is of no interest to subsequent code */ - msg->l1h = l1h->data; - - switch (l1h->msg_type) { - case L1CTL_DATA_IND: - rc = rx_ph_data_ind(ms, msg); - break; - case L1CTL_DATA_CONF: - rc = rx_ph_data_conf(ms, msg); - break; - case L1CTL_RESET_IND: - case L1CTL_RESET_CONF: - rc = rx_l1_reset(ms); - msgb_free(msg); - break; - default: - LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type); - msgb_free(msg); - break; - } - - return rc; -} - -int l1ctl_tx_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power) -{ - return -ENOTSUP; -} - -int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset, - uint8_t combined) -{ - return -ENOTSUP; -} - - diff --git a/src/osmo-bts-bb/main.c b/src/osmo-bts-bb/main.c deleted file mode 100644 index 7300b68..0000000 --- a/src/osmo-bts-bb/main.c +++ /dev/null @@ -1,215 +0,0 @@ -/* (C) 2011 by Andreas Eversberg jolly@eversberg.eu - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 <netinet/in.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/signal.h> -#include <osmocom/core/timer.h> -#include <osmocom/core/select.h> -#include <osmo-bts/logging.h> -//#include <osmocom/bb/common/osmocom_data.h> -#include <osmo-bts/support.h> -#include <osmo-bts/abis.h> -#include <osmo-bts/rtp.h> -#include <osmo-bts/bts.h> - -#include <net/if.h> - -#define _GNU_SOURCE -#include <getopt.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <netdb.h> -#include <string.h> -#include <time.h> - -struct log_target *stderr_target; -char *debugs = "DL1C:DLAPDM:DABIS:DOML:DRSL:DSUM"; - -void *l23_ctx = NULL; -static struct osmocom_bts *bts; -int debug_set = 0; -char *software_version = "0.0"; -uint8_t abis_mac[6] = { 0, 1, 2, 3, 4, 5 }; -char *bsc_host = "localhost"; -char *bts_id = "1801/0"; -int quit = 0; - -// FIXME this is a hack -static void get_mac(void) -{ - struct if_nameindex *ifn = if_nameindex(); - struct ifreq ifr; - int sock; - int ret; - - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) - return; - - memset(&ifr, 0, sizeof(ifr)); - if (!ifn) - return; - while (ifn->if_name) { - strncpy(ifr.ifr_name, ifn->if_name, sizeof(ifr.ifr_name)-1); - ret = ioctl(sock, SIOCGIFHWADDR, &ifr); - if (ret == 0 && !!memcmp(ifr.ifr_hwaddr.sa_data, - "\0\0\0\0\0\0", 6)) { - memcpy(abis_mac, ifr.ifr_hwaddr.sa_data, 6); - printf("Using MAC address of %s: " - "'%02x:%02x:%02x:%02x:%02x:%02x'\n", - ifn->if_name, - abis_mac[0], abis_mac[1], abis_mac[2], - abis_mac[3], abis_mac[4], abis_mac[5]); - break; - } - ifn++; - } -// if_freenameindex(ifn); -} - -static void print_usage(const char *app) -{ - printf("Usage: %s [option]\n", app); - printf(" -h --help this text\n"); - printf(" -d --debug Change debug flags. (-d %s)\n", debugs); - printf(" -i --bsc-ip IP address of the BSC\n"); -} - -static void handle_options(int argc, char **argv) -{ - while (1) { - int option_index = 0, c; - static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"debug", 1, 0, 'd'}, - {"bsc-ip", 1, 0, 'i'}, - {0, 0, 0, 0}, - }; - - c = getopt_long(argc, argv, "hd:i:", - long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - print_usage(argv[0]); - exit(0); - case 'd': - log_parse_category_mask(stderr_target, optarg); - debug_set = 1; - break; - case 'i': - bsc_host = strdup(optarg); - break; - default: - break; - } - } -} - -void sighandler(int sigset) -{ - if (sigset == SIGHUP || sigset == SIGPIPE) - return; - - fprintf(stderr, "Signal %d recevied.\n", sigset); - - /* in case there is a lockup during exit */ - signal(SIGINT, SIG_DFL); - signal(SIGHUP, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGPIPE, SIG_DFL); - - quit = 1; -// dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); -} - -int main(int argc, char **argv) -{ - int ret; - struct hostent *hostent; - struct in_addr *ina; - uint32_t bsc_ip; - uint8_t maskv_tx[2], maskv_rx[2]; - - printf("((*))\n"); - printf(" |\n"); - printf(" / \ OsmoBTS\n"); - - get_mac(); - bts_support_init(); - - srand(time(NULL)); - - log_init(&log_info); - stderr_target = log_target_create_stderr(); - log_add_target(stderr_target); - log_set_all_filter(stderr_target, 1); - - l23_ctx = talloc_named_const(NULL, 1, "layer2 context"); - - handle_options(argc, argv); - - if (!debug_set) - log_parse_category_mask(stderr_target, debugs); - log_set_log_level(stderr_target, LOGL_INFO); - - hostent = gethostbyname(bsc_host); - if (!hostent) { - fprintf(stderr, "Failed to resolve BSC hostname '%s'.\n", - bsc_host); - } - ina = (struct in_addr *) hostent->h_addr; - bsc_ip = ntohl(ina->s_addr); - printf("Using BSC at IP: '%d.%d.%d.%d'\n", bsc_ip >> 24, - (bsc_ip >> 16) & 0xff, (bsc_ip >> 8) & 0xff, bsc_ip & 0xff); - - printf("Using BTS ID: '%s'\n", bts_id); - bts = create_bts(1, bts_id); - if (!bts) - exit(-1); - maskv_tx[0] = 0x55; - maskv_rx[0] = 0x55; - ret = create_ms(bts->trx[0], 1, maskv_tx, maskv_rx); - if (ret < 0) - goto fail; - ret = abis_open(&bts->link, bsc_ip); - if (ret < 0) - goto fail; - - signal(SIGINT, sighandler); - signal(SIGHUP, sighandler); - signal(SIGTERM, sighandler); - signal(SIGPIPE, sighandler); - - while (!quit) { - work_bts(bts); - osmo_select_main(0); - } - -fail: - destroy_bts(bts); - - return 0; -}
Instead of handling primitives directly at layer 1 specific code, osmo-bts handles primitives at common code. Therefore a new file 'l1sap.c' is added and integrated.
The l1sap.c file: - receives PH-DATA indications and forwards them to layer 2. - checks for RF link loss and notifies BSC. - receives TCH indications and forwards them via RTP. - receives PH-RTS indications and sends PH-DATA requests with content according to its logical channel. - receives TCH-RTS indications and sends TCH requests with content received via RTP or loopback from TCH indications. - send MPH-INFO requests to activate, deactivate and modify logical channels and handles their confirms. - receives MPH-INFO indications with measurements from tranceiver. - forwards received and transmitted PH-DATA to GSMTAP.
Therefore some obsolete bts_model_* calls have been replaced by bts_model_l1sap_down to send primitves down to layer 1 specific code. --- include/osmo-bts/bts.h | 2 + include/osmo-bts/bts_model.h | 12 +- include/osmo-bts/gsm_data.h | 1 + include/osmo-bts/l1sap.h | 71 +++ include/osmo-bts/rsl.h | 2 +- include/osmo-bts/vty.h | 4 +- src/common/Makefile.am | 2 +- src/common/bts.c | 8 + src/common/l1sap.c | 948 ++++++++++++++++++++++++++++++++++++++ src/common/logging.c | 4 +- src/common/measurement.c | 5 + src/common/pcu_sock.c | 15 +- src/common/rsl.c | 29 +- src/common/vty.c | 131 +++++- src/osmo-bts-sysmo/l1_if.c | 6 + src/osmo-bts-sysmo/main.c | 2 +- src/osmo-bts-sysmo/oml.c | 4 +- src/osmo-bts-sysmo/sysmobts_vty.c | 27 -- tests/stubs.c | 3 + 19 files changed, 1204 insertions(+), 72 deletions(-) create mode 100644 include/osmo-bts/l1sap.h create mode 100644 src/common/l1sap.c
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index 583c1eb..6b91c82 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -27,5 +27,7 @@ int lchan_init_lapdm(struct gsm_lchan *lchan);
void load_timer_start(struct gsm_bts *bts);
+struct gsm_time *get_time(struct gsm_bts *bts); + #endif /* _BTS_H */
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index bfa6bd8..3b2855a 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -12,8 +12,6 @@
int bts_model_init(struct gsm_bts *bts);
-struct gsm_time *bts_model_get_time(struct gsm_bts *bts); - int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, struct tlv_parsed *old_attr, struct tlv_parsed *new_attr, void *obj); @@ -27,20 +25,14 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj, uint8_t adm_state);
-int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp); -int bts_model_rsl_chan_rel(struct gsm_lchan *lchan); -int bts_model_rsl_deact_sacch(struct gsm_lchan *lchan); -int bts_model_rsl_mode_modify(struct gsm_lchan *lchan); - int bts_model_trx_deact_rf(struct gsm_bts_trx *trx); int bts_model_trx_close(struct gsm_bts_trx *trx);
-void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len); - int bts_model_vty_init(struct gsm_bts *bts);
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts); void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx);
+int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); + #endif diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index c6cd7e4..980f8ef 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -58,6 +58,7 @@ struct gsm_bts_role_bts { struct { uint8_t tc4_ctr; } si; + struct gsm_time gsm_time; uint8_t radio_link_timeout;
/* used by the sysmoBTS to adjust band */ diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h new file mode 100644 index 0000000..a1dc303 --- /dev/null +++ b/include/osmo-bts/l1sap.h @@ -0,0 +1,71 @@ +#ifndef L1SAP_H +#define L1SAP_H + +/* timeslot and subslot from chan_nr */ +#define L1SAP_CHAN2TS(chan_nr) (chan_nr & 7) +#define L1SAP_CHAN2SS_TCHH(chan_nr) ((chan_nr >> 3) & 1) +#define L1SAP_CHAN2SS_SDCCH4(chan_nr) ((chan_nr >> 3) & 3) +#define L1SAP_CHAN2SS_SDCCH8(chan_nr) ((chan_nr >> 3) & 7) + +/* logical channel from chan_nr + link_id */ +#define L1SAP_IS_LINK_SACCH(link_id) ((link_id & 0xC0) == 0x40) +#define L1SAP_IS_CHAN_TCHF(chan_nr) ((chan_nr & 0xf8) == 0x08) +#define L1SAP_IS_CHAN_TCHH(chan_nr) ((chan_nr & 0xf0) == 0x10) +#define L1SAP_IS_CHAN_SDCCH4(chan_nr) ((chan_nr & 0xe0) == 0x20) +#define L1SAP_IS_CHAN_SDCCH8(chan_nr) ((chan_nr & 0xc0) == 0x40) +#define L1SAP_IS_CHAN_BCCH(chan_nr) ((chan_nr & 0xf8) == 0x80) +#define L1SAP_IS_CHAN_RACH(chan_nr) ((chan_nr & 0xf8) == 0x88) +#define L1SAP_IS_CHAN_AGCH_PCH(chan_nr) ((chan_nr & 0xf8) == 0x90) + +/* rach type from ra */ +#define L1SAP_IS_PACKET_RACH(ra) ((ra & 0xf0) == 0x70) + +/* CCCH block from frame number */ +#define L1SAP_FN2CCCHBLOCK(fn) ((fn % 51) / 5 - 1) + +/* PTCH layout from frame number */ +#define L1SAP_FN2MACBLOCK(fn) ((fn % 52) / 4) +#define L1SAP_FN2PTCCHBLOCK(fn) ((fn / 52) & 7) +#define L1SAP_IS_PTCCH(fn) ((fn % 52) == 12) + +/* subslot from any chan_nr */ +static inline uint8_t l1sap_chan2ss(uint8_t chan_nr) +{ + if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) + return L1SAP_CHAN2SS_SDCCH8(chan_nr); + if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) + return L1SAP_CHAN2SS_SDCCH4(chan_nr); + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + return L1SAP_CHAN2SS_TCHH(chan_nr); + return 0; +} + + +/* allocate a msgb containing a osmo_phsap_prim + optional l2 data */ +struct msgb *l1sap_msgb_alloc(unsigned int l2_len); + +/* any L1 prim received from bts model */ +int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); + +/* pcu (socket interface) sends us a data request primitive */ +int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, + uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); + +/* call-back function for incoming RTP */ +void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, + unsigned int rtp_pl_len); + +/* channel control */ +int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr); + +extern const struct value_string gsmtap_sapi_names[]; +extern struct gsmtap_inst *gsmtap; +extern uint32_t gsmtap_sapi_mask; +extern uint8_t gsmtap_sapi_acch; + +#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h) + +#endif /* L1SAP_H */ diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 251cd23..eae7845 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -7,7 +7,7 @@ int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime, uint8_t ra, uint8_t acc_delay); int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int len);
-int rsl_tx_chan_act_ack(struct gsm_lchan *lchan, struct gsm_time *gtime); +int rsl_tx_chan_act_ack(struct gsm_lchan *lchan); int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h index 1bc7e71..9b113a8 100644 --- a/include/osmo-bts/vty.h +++ b/include/osmo-bts/vty.h @@ -15,8 +15,10 @@ extern struct cmd_element ournode_end_cmd; enum node_type bts_vty_go_parent(struct vty *vty); int bts_vty_is_config_node(struct vty *vty, int node);
-int bts_vty_init(const struct log_info *cat); +int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat);
extern struct vty_app_info bts_vty_info;
+char *osmo_str_tolower(const char *in); + #endif diff --git a/src/common/Makefile.am b/src/common/Makefile.am index b2f6f8e..1c6ff9e 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -5,4 +5,4 @@ LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) noinst_LIBRARIES = libbts.a libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ rsl.c vty.c paging.c measurement.c amr.c lchan.c \ - load_indication.c pcu_sock.c + load_indication.c pcu_sock.c l1sap.c diff --git a/src/common/bts.c b/src/common/bts.c index e899ebd..c495fcd 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -239,3 +239,11 @@ int bts_supports_cipher(struct gsm_bts_role_bts *bts, int rsl_cipher) sup = (1 << (rsl_cipher - 2)) & bts->support.ciphers; return sup > 0; } + +struct gsm_time *get_time(struct gsm_bts *bts) +{ + struct gsm_bts_role_bts *btsb = bts->role; + + return &btsb->gsm_time; +} + diff --git a/src/common/l1sap.c b/src/common/l1sap.c new file mode 100644 index 0000000..ad833ea --- /dev/null +++ b/src/common/l1sap.c @@ -0,0 +1,948 @@ +/* L1 SAP primitives */ + +/* (C) 2011 by Harald Welte laforge@gnumonks.org + * (C) 2013 by Andreas Eversberg jolly@eversberg.eu + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/gsm/l1sap.h> +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/gsmtap_util.h> +#include <osmocom/core/utils.h> + +#include <osmocom/trau/osmo_ortp.h> + +#include <osmo-bts/logging.h> +#include <osmo-bts/gsm_data.h> +#include <osmo-bts/l1sap.h> +#include <osmo-bts/pcu_if.h> +#include <osmo-bts/measurement.h> +#include <osmo-bts/bts.h> +#include <osmo-bts/rsl.h> +#include <osmo-bts/bts_model.h> + +static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); + +static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { + 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B +}; + +/* allocate a msgb containing a osmo_phsap_prim + optional l2 data */ +struct msgb *l1sap_msgb_alloc(unsigned int l2_len) +{ + struct msgb *msg = msgb_alloc(sizeof(struct osmo_phsap_prim) + l2_len, + "l1sap_prim"); + + if (!msg) + return NULL; + + msg->l1h = msgb_put(msg, sizeof(struct osmo_phsap_prim)); + + return msg; +} + +static int l1sap_tx_ciph_req(struct gsm_bts_trx *trx, uint8_t chan_nr, + uint8_t downlink, uint8_t uplink) +{ + struct osmo_phsap_prim l1sap_ciph; + + osmo_prim_init(&l1sap_ciph.oph, SAP_GSM_PH, PRIM_MPH_INFO, + PRIM_OP_REQUEST, NULL); + l1sap_ciph.u.info.type = PRIM_INFO_ACT_CIPH; + l1sap_ciph.u.info.u.ciph_req.chan_nr = chan_nr; + l1sap_ciph.u.info.u.ciph_req.downlink = downlink; + l1sap_ciph.u.info.u.ciph_req.uplink = uplink; + + return l1sap_down(trx, &l1sap_ciph); +} + + +/* check if the message is a GSM48_MT_RR_CIPH_M_CMD, and if yes, enable + * uni-directional de-cryption on the uplink. We need this ugly layering + * violation as we have no way of passing down L3 metadata (RSL CIPHERING CMD) + * to this point in L1 */ +static int check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan, + uint8_t chan_nr) +{ + + /* only do this if we are in the right state */ + switch (lchan->ciph_state) { + case LCHAN_CIPH_NONE: + case LCHAN_CIPH_RX_REQ: + break; + default: + return 0; + } + + /* First byte (Address Field) of LAPDm header) */ + if (msg->data[0] != 0x03) + return 0; + /* First byte (protocol discriminator) of RR */ + if ((msg->data[3] & 0xF) != GSM48_PDISC_RR) + return 0; + /* 2nd byte (msg type) of RR */ + if ((msg->data[4] & 0x3F) != GSM48_MT_RR_CIPH_M_CMD) + return 0; + + l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 0, 1); + + return 1; +} + +struct gsmtap_inst *gsmtap = NULL; +uint32_t gsmtap_sapi_mask = 0; +uint8_t gsmtap_sapi_acch = 0; + +const struct value_string gsmtap_sapi_names[] = { + { 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_TCH_F, "TCH/F" }, + { GSMTAP_CHANNEL_TCH_H, "TCH/H" }, + { GSMTAP_CHANNEL_PACCH, "PACCH" }, + { GSMTAP_CHANNEL_PDCH, "PDTCH" }, + { GSMTAP_CHANNEL_PTCCH, "PTCCH" }, + { GSMTAP_CHANNEL_CBCH51,"CBCH" }, + { GSMTAP_CHANNEL_ACCH, "SACCH" }, + { 0, NULL } +}; + +static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + struct msgb *msg = l1sap->oph.msg; + uint8_t *data; + int len; + uint8_t chan_type = 0, tn = 0, ss = 0; + uint32_t fn; + uint8_t chan_nr, link_id; + uint16_t uplink = GSMTAP_ARFCN_F_UPLINK; + + if (!gsmtap) + return 0; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): + uplink = 0; + /* fall through */ + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_INDICATION): + data = msg->data + sizeof(struct osmo_phsap_prim); + len = msg->len - sizeof(struct osmo_phsap_prim); + fn = l1sap->u.data.fn; + tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr); + chan_nr = l1sap->u.data.chan_nr; + link_id = l1sap->u.data.link_id; + if (L1SAP_IS_CHAN_TCHF(chan_nr)) { + if (trx->ts[tn].pchan == GSM_PCHAN_PDCH) { + if (L1SAP_IS_PTCCH(fn)) { + chan_type = GSMTAP_CHANNEL_PTCCH; + ss = L1SAP_FN2PTCCHBLOCK(fn); + if (l1sap->oph.primitive + == PRIM_OP_INDICATION) { + if (data[0] == 7) + return -EINVAL; + data++; + len--; + } + } else { + chan_type = GSMTAP_CHANNEL_PACCH; + } + } else + chan_type = GSMTAP_CHANNEL_TCH_F; + } else if (L1SAP_IS_CHAN_TCHH(chan_nr)) { + ss = L1SAP_CHAN2SS_TCHH(chan_nr); + chan_type = GSMTAP_CHANNEL_TCH_H; + } else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) { + ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); + chan_type = GSMTAP_CHANNEL_SDCCH; + } else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) { + ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); + chan_type = GSMTAP_CHANNEL_SDCCH; + } else if (L1SAP_IS_CHAN_BCCH(chan_nr)) { + chan_type = GSMTAP_CHANNEL_BCCH; + } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { +#warning Set BS_AG_BLKS_RES + /* The sapi depends on DSP configuration, not + * on the actual SYSTEM INFORMATION 3. */ + if (L1SAP_FN2CCCHBLOCK(fn) >= 1) + chan_type = GSMTAP_CHANNEL_PCH; + else + chan_type = GSMTAP_CHANNEL_AGCH; + } + if (L1SAP_IS_LINK_SACCH(link_id)) + chan_type |= GSMTAP_CHANNEL_ACCH; + break; + case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION): + chan_type = GSMTAP_CHANNEL_RACH; + fn = l1sap->u.rach_ind.fn; + tn = L1SAP_CHAN2TS(l1sap->u.rach_ind.chan_nr); + chan_nr = l1sap->u.rach_ind.chan_nr; + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); + else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) + ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); + else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) + ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); + data = &l1sap->u.rach_ind.ra; + len = 1; + break; + default: + return -ENOTSUP; + } + + if (len == 0) + return 0; + if ((chan_type & GSMTAP_CHANNEL_ACCH)) { + if (!gsmtap_sapi_acch) + return 0; + } else { + if (!((1 << (chan_type & 31)) & gsmtap_sapi_mask)) + return 0; + } + + gsmtap_send(gsmtap, trx->arfcn | uplink, tn, chan_type, ss, fn, 0, 0, + data, len); + + return 0; +} + +/* time information received from bts model */ +static int l1sap_info_time_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_time_ind_param *info_time_ind) +{ + struct gsm_bts *bts = trx->bts; + struct gsm_bts_role_bts *btsb = bts->role; + + DEBUGP(DL1P, "MPH_INFO time ind %u\n", info_time_ind->fn); + + /* Update our data structures with the current GSM time */ + gsm_fn2gsmtime(&btsb->gsm_time, info_time_ind->fn); + + /* Update time on PCU interface */ + pcu_tx_time_ind(info_time_ind->fn); + + /* check if the measurement period of some lchan has ended + * and pre-compute the respective measurement */ + trx_meas_check_compute(trx, info_time_ind->fn - 1); + + /* increment 'total' for every possible rach */ + if (bts->c0->ts[0].pchan != GSM_PCHAN_CCCH_SDCCH4 + || (info_time_ind->fn % 51) < 27) + btsb->load.rach.total++; + + return 0; +} + +/* measurement information received from bts model */ +static int l1sap_info_meas_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_meas_ind_param *info_meas_ind) +{ + struct bts_ul_meas ulm; + struct gsm_lchan *lchan; + + DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=%02x\n", + info_meas_ind->chan_nr); + + lchan = &trx->ts[L1SAP_CHAN2TS(info_meas_ind->chan_nr)] + .lchan[l1sap_chan2ss(info_meas_ind->chan_nr)]; + + /* in the GPRS case we are not interested in measurement + * processing. The PCU will take care of it */ + if (lchan->type == GSM_LCHAN_PDTCH) + return 0; + + memset(&ulm, 0, sizeof(ulm)); + ulm.ta_offs_qbits = info_meas_ind->ta_offs_qbits; + ulm.ber10k = info_meas_ind->ber10k; + ulm.inv_rssi = info_meas_ind->inv_rssi; + + lchan_new_ul_meas(lchan, &ulm); + + return 0; +} + +/* any L1 MPH_INFO indication prim recevied from bts model */ +static int l1sap_mph_info_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct mph_info_param *info) +{ + int rc = 0; + + switch (info->type) { + case PRIM_INFO_TIME: + rc = l1sap_info_time_ind(trx, l1sap, &info->u.time_ind); + break; + case PRIM_INFO_MEAS: + rc = l1sap_info_meas_ind(trx, l1sap, &info->u.meas_ind); + break; + default: + LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO ind type %d\n", + info->type); + break; + } + + return rc; +} + +/* activation confirm received from bts model */ +static int l1sap_info_act_cnf(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_act_cnf_param *info_act_cnf) +{ + struct gsm_lchan *lchan; + + LOGP(DL1P, LOGL_INFO, "activate confirm chan_nr=%02x trx=%d\n", + info_act_cnf->chan_nr, trx->nr); + + lchan = &trx->ts[L1SAP_CHAN2TS(info_act_cnf->chan_nr)] + .lchan[l1sap_chan2ss(info_act_cnf->chan_nr)]; + + if (info_act_cnf->cause) + rsl_tx_chan_act_nack(lchan, info_act_cnf->cause); + else + rsl_tx_chan_act_ack(lchan); + + return 0; +} + +/* activation confirm received from bts model */ +static int l1sap_info_rel_cnf(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_act_cnf_param *info_act_cnf) +{ + struct gsm_lchan *lchan; + + LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=%02x trx=%d\n", + info_act_cnf->chan_nr, trx->nr); + + lchan = &trx->ts[L1SAP_CHAN2TS(info_act_cnf->chan_nr)] + .lchan[l1sap_chan2ss(info_act_cnf->chan_nr)]; + + rsl_tx_rf_rel_ack(lchan); + + return 0; +} + +/* any L1 MPH_INFO confirm prim recevied from bts model */ +static int l1sap_mph_info_cnf(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct mph_info_param *info) +{ + int rc = 0; + + switch (info->type) { + case PRIM_INFO_ACTIVATE: + rc = l1sap_info_act_cnf(trx, l1sap, &info->u.act_cnf); + break; + case PRIM_INFO_DEACTIVATE: + rc = l1sap_info_rel_cnf(trx, l1sap, &info->u.act_cnf); + break; + default: + LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO cnf type %d\n", + info->type); + break; + } + + return rc; +} + +/* PH-RTS-IND prim recevied from bts model */ +static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind) +{ + struct msgb *msg = l1sap->oph.msg; + struct gsm_time g_time; + struct gsm_lchan *lchan; + uint8_t chan_nr, link_id; + uint8_t tn, ss; + uint32_t fn; + uint8_t *p, *si; + struct lapdm_entity *le; + struct osmo_phsap_prim pp; + int rc; + + chan_nr = rts_ind->chan_nr; + link_id = rts_ind->link_id; + fn = rts_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx PH-RTS.ind %02u/%02u/%02u chan_nr=%d link_id=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id); + + if (trx->ts[tn].pchan == GSM_PCHAN_PDCH) { + if (L1SAP_IS_PTCCH(rts_ind->fn)) { + pcu_tx_rts_req(&trx->ts[tn], 1, fn, 1 /* ARFCN */, + L1SAP_FN2PTCCHBLOCK(fn)); + + return 0; + } + pcu_tx_rts_req(&trx->ts[tn], 0, fn, 0 /* ARFCN */, + L1SAP_FN2MACBLOCK(fn)); + + return 0; + } + + /* reuse PH-RTS.ind for PH-DATA.req */ + if (!msg) { + LOGP(DL1P, LOGL_FATAL, "RTS without msg to be reused. Please " + "fix!\n"); + abort(); + } + msgb_trim(msg, sizeof(*l1sap)); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_REQUEST, + msg); + msg->l2h = msg->l1h + sizeof(*l1sap); + + if (L1SAP_IS_CHAN_BCCH(chan_nr)) { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + /* get them from bts->si_buf[] */ + si = bts_sysinfo_get(trx->bts, &g_time); + if (si) + memcpy(p, si, GSM_MACBLOCK_LEN); + else + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + } else if (!(chan_nr & 0x80)) { /* only TCH/F, TCH/H, SDCCH/4 and SDCCH/8 have C5 bit cleared */ + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); /* TCH/H */ + else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) + ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); /* SDCCH/4 */ + else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) + ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); /* SDCCH/8 */ + else + ss = 0; /* TCH/F */ + lchan = &trx->ts[tn].lchan[ss]; + if (L1SAP_IS_LINK_SACCH(link_id)) { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + /* L1-header, if not set/modified by layer 1 */ + p[0] = lchan->ms_power; + p[1] = lchan->rqd_ta; + le = &lchan->lapdm_ch.lapdm_acch; + } else + le = &lchan->lapdm_ch.lapdm_dcch; + rc = lapdm_phsap_dequeue_prim(le, &pp); + if (rc < 0) { + if (L1SAP_IS_LINK_SACCH(link_id)) { + /* No SACCH data from LAPDM pending, send SACCH filling */ + uint8_t *si = lchan_sacch_get(lchan, &g_time); + if (si) { + /* The +2 is empty space where the DSP inserts the L1 hdr */ + memcpy(p + 2, si, GSM_MACBLOCK_LEN - 2); + } else + memcpy(p + 2, fill_frame, GSM_MACBLOCK_LEN - 2); + } else if ((!L1SAP_IS_CHAN_TCHF(chan_nr) && !L1SAP_IS_CHAN_TCHH(chan_nr)) + || lchan->rsl_cmode == RSL_CMOD_SPD_SIGN) { + /* send fill frame only, if not TCH/x != Signalling, otherwise send empty frame */ + p = msgb_put(msg, GSM_MACBLOCK_LEN); + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + } /* else the message remains empty, so TCH frames are sent */ + } else { + /* The +2 is empty space where the DSP inserts the L1 hdr */ + if (L1SAP_IS_LINK_SACCH(link_id)) + memcpy(p + 2, pp.oph.msg->data + 2, GSM_MACBLOCK_LEN - 2); + else { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + memcpy(p, pp.oph.msg->data, GSM_MACBLOCK_LEN); + /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ + check_for_ciph_cmd(pp.oph.msg, lchan, chan_nr); + } + msgb_free(pp.oph.msg); + } + } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { + p = msgb_put(msg, GSM_MACBLOCK_LEN); +#warning Set BS_AG_BLKS_RES + /* The sapi depends on DSP configuration, not + * on the actual SYSTEM INFORMATION 3. */ + struct gsm_bts_role_bts *btsb = trx->bts->role; + if (L1SAP_FN2CCCHBLOCK(fn) >= 1) { + /* PCH */ + paging_gen_msg(btsb->paging_state, p, &g_time); + } else { + /* AGCH */ + /* special queue of messages from IMM ASS CMD */ + struct msgb *amsg = bts_agch_dequeue(trx->bts); + if (!amsg) + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + else { + memcpy(p, amsg->data, amsg->len); + msgb_free(amsg); + } + } + } + + DEBUGP(DL1P, "Tx PH-DATA.req %02u/%02u/%02u chan_nr=%d link_id=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id); + + l1sap_down(trx, l1sap); + + /* don't free, because we forwarded data */ + return 1; +} + +/* TCH-RTS-IND prim recevied from bts model */ +static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_tch_param *rts_ind) +{ + struct msgb *resp_msg; + struct osmo_phsap_prim *resp_l1sap, empty_l1sap; + struct gsm_time g_time; + struct gsm_lchan *lchan; + uint8_t chan_nr; + uint8_t tn, ss; + uint32_t fn; + + chan_nr = rts_ind->chan_nr; + fn = rts_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx TCH-RTS.ind %02u/%02u/%02u chan_nr=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr); + + /* get timeslot and subslot */ + tn = L1SAP_CHAN2TS(chan_nr); + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); /* TCH/H */ + else + ss = 0; /* TCH/F */ + lchan = &trx->ts[tn].lchan[ss]; + + if (!lchan->loopback && lchan->abis_ip.rtp_socket) { + osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); + /* FIXME: we _assume_ that we never miss TDMA + * frames and that we always get to this point + * for every to-be-transmitted voice frame. A + * better solution would be to compute + * rx_user_ts based on how many TDMA frames have + * elapsed since the last call */ + lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION; + } + /* get a msgb from the dl_tx_queue */ + resp_msg = msgb_dequeue(&lchan->dl_tch_queue); + if (!resp_msg) { + LOGP(DL1P, LOGL_DEBUG, "%s DL TCH Tx queue underrun\n", + gsm_lchan_name(lchan)); + resp_l1sap = &empty_l1sap; + } else { + resp_msg->l2h = resp_msg->data; + msgb_push(resp_msg, sizeof(*resp_l1sap)); + resp_msg->l1h = resp_msg->data; + resp_l1sap = msgb_l1sap_prim(resp_msg); + } + + memset(resp_l1sap, 0, sizeof(*resp_l1sap)); + osmo_prim_init(&resp_l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_REQUEST, + resp_msg); + resp_l1sap->u.tch.chan_nr = chan_nr; + resp_l1sap->u.tch.fn = fn; + + DEBUGP(DL1P, "Tx TCH.req %02u/%02u/%02u chan_nr=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr); + + l1sap_down(trx, resp_l1sap); + + return 0; +} + +/* DATA received from bts model */ +static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_data_param *data_ind) +{ + struct msgb *msg = l1sap->oph.msg; + struct gsm_time g_time; + struct gsm_lchan *lchan; + struct lapdm_entity *le; + uint8_t *data = msg->l2h; + int len = msgb_l2len(msg); + uint8_t chan_nr, link_id; + uint8_t tn, ss; + uint32_t fn; + int8_t rssi; + + rssi = data_ind->rssi; + chan_nr = data_ind->chan_nr; + link_id = data_ind->link_id; + fn = data_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx PH-DATA.ind %02u/%02u/%02u chan_nr=%d link_id=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id); + + if (trx->ts[tn].pchan == GSM_PCHAN_PDCH) { + if (len == 0) + return -EINVAL; + if (L1SAP_IS_PTCCH(fn)) { + pcu_tx_data_ind(&trx->ts[tn], 1, fn, + 0 /* ARFCN */, L1SAP_FN2PTCCHBLOCK(fn), + data, len, rssi); + + return 0; + } + /* drop incomplete UL block */ + if (data[0] != 7) + return 0; + /* PDTCH / PACCH frame handling */ + pcu_tx_data_ind(&trx->ts[tn], 0, fn, 0 /* ARFCN */, + L1SAP_FN2MACBLOCK(fn), data + 1, len - 1, rssi); + + return 0; + } + + lchan = &trx->ts[tn].lchan[ss]; + + /* bad frame */ + if (len == 0) { + if (L1SAP_IS_LINK_SACCH(link_id) && lchan->s > 0) { + /* count down radio link counter S */ + lchan->s--; + DEBUGP(DMEAS, "counting down radio link counter S=%d\n", + lchan->s); + if (lchan->s == 0) + rsl_tx_conn_fail(lchan, + RSL_ERR_RADIO_LINK_FAIL); + } + + return -EINVAL; + } + + if (L1SAP_IS_LINK_SACCH(link_id)) { + struct gsm_bts_role_bts *btsb = trx->bts->role; + + le = &lchan->lapdm_ch.lapdm_acch; + /* count up radio link counter S */ + if (lchan->s < btsb->radio_link_timeout) { + lchan->s += 2; + if (lchan->s > btsb->radio_link_timeout) + lchan->s = btsb->radio_link_timeout; + DEBUGP(DMEAS, "counting up radio link counter S=%d\n", + lchan->s); + } + /* save the SACCH L1 header in the lchan struct for RSL MEAS RES */ + if (len < 2) { + LOGP(DL1P, LOGL_NOTICE, "SACCH with size %u<2 !?!\n", + len); + return -EINVAL; + } + /* Some brilliant engineer decided that the ordering of + * fields on the Um interface is different from the + * order of fields in RLS. See TS 04.04 (Chapter 7.2) + * vs. TS 08.58 (Chapter 9.3.10). */ + lchan->meas.l1_info[0] = data[0] << 3; + lchan->meas.l1_info[0] |= ((data[0] >> 5) & 1) << 2; + lchan->meas.l1_info[1] = data[1]; + lchan->meas.flags |= LC_UL_M_F_L1_VALID; + } else + le = &lchan->lapdm_ch.lapdm_dcch; + + /* if this is the first valid message after enabling Rx + * decryption, we have to enable Tx encryption */ + if (lchan->ciph_state == LCHAN_CIPH_RX_CONF) { + /* HACK: check if it's an I frame, in order to + * ignore some still buffered/queued UI frames received + * before decryption was enabled */ + if (data[0] == 0x01 && (data[1] & 0x01) == 0) { + l1sap_tx_ciph_req(trx, chan_nr, 1, 0); + } + } + + /* SDCCH, SACCH and FACCH all go to LAPDm */ + msgb_pull(msg, (msg->l2h - msg->data)); + msg->l1h = NULL; + lapdm_phsap_up(&l1sap->oph, le); + + /* don't free, because we forwarded data */ + return 1; +} + +/* TCH received from bts model */ +static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, + struct ph_tch_param *tch_ind) +{ + struct msgb *msg = l1sap->oph.msg; + struct gsm_time g_time; + struct gsm_lchan *lchan; + uint8_t tn, ss, chan_nr; + uint32_t fn; + + chan_nr = tch_ind->chan_nr; + fn = tch_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); + else + ss = 0; + lchan = &trx->ts[tn].lchan[ss]; + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx TCH.ind %02u/%02u/%02u chan_nr=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr); + + msgb_pull(msg, sizeof(*l1sap)); + + /* hand msg to RTP code for transmission */ + if (lchan->abis_ip.rtp_socket) + osmo_rtp_send_frame(lchan->abis_ip.rtp_socket, + msg->data, msg->len, 160); + + /* if loopback is enabled, also queue received RTP data */ + if (lchan->loopback) { + struct msgb *tmp; + int count = 0; + + /* make sure the queue doesn't get too long */ + llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) + count++; + while (count >= 1) { + tmp = msgb_dequeue(&lchan->dl_tch_queue); + msgb_free(tmp); + count--; + } + + msgb_enqueue(&lchan->dl_tch_queue, msg); + } + + return 0; +} + +/* RACH received from bts model */ +static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_rach_ind_param *rach_ind) +{ + struct gsm_bts *bts = trx->bts; + struct gsm_bts_role_bts *btsb = bts->role; + struct lapdm_channel *lc; + + DEBUGP(DL1P, "Rx PH-RA.ind"); + + lc = &trx->ts[0].lchan[4].lapdm_ch; + if (!lc) { + LOGP(DL1P, LOGL_ERROR, "unable to resolve LAPD channel\n"); + return -ENODEV; + } + + /* check for under/overflow / sign */ + if (rach_ind->acc_delay > btsb->max_ta) { + LOGP(DL1P, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", + rach_ind->acc_delay, btsb->max_ta); + return 0; + } + + /* check for packet access */ + if (trx == bts->c0 + && L1SAP_IS_PACKET_RACH(rach_ind->ra)) { + LOGP(DL1P, LOGL_INFO, "RACH for packet access\n"); + pcu_tx_rach_ind(bts, rach_ind->acc_delay << 2, + rach_ind->ra, rach_ind->fn); + + return 0; + } + + LOGP(DL1P, LOGL_INFO, "RACH for RR access (toa=%d, ra=%d)\n", + rach_ind->acc_delay, rach_ind->ra); + lapdm_phsap_up(&l1sap->oph, &lc->lapdm_dcch); + + return 0; +} + +/* any L1 prim received from bts model */ +int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + struct msgb *msg = l1sap->oph.msg; + int rc = 0; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_INDICATION): + rc = l1sap_mph_info_ind(trx, l1sap, &l1sap->u.info); + break; + case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_CONFIRM): + rc = l1sap_mph_info_cnf(trx, l1sap, &l1sap->u.info); + break; + case OSMO_PRIM(PRIM_PH_RTS, PRIM_OP_INDICATION): + rc = l1sap_ph_rts_ind(trx, l1sap, &l1sap->u.data); + break; + case OSMO_PRIM(PRIM_TCH_RTS, PRIM_OP_INDICATION): + rc = l1sap_tch_rts_ind(trx, l1sap, &l1sap->u.tch); + break; + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_INDICATION): + to_gsmtap(trx, l1sap); + rc = l1sap_ph_data_ind(trx, l1sap, &l1sap->u.data); + break; + case OSMO_PRIM(PRIM_TCH, PRIM_OP_INDICATION): + rc = l1sap_tch_ind(trx, l1sap, &l1sap->u.tch); + break; + case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION): + to_gsmtap(trx, l1sap); + rc = l1sap_ph_rach_ind(trx, l1sap, &l1sap->u.rach_ind); + break; + default: + LOGP(DL1P, LOGL_NOTICE, "unknown prim %d op %d\n", + l1sap->oph.primitive, l1sap->oph.operation); + break; + } + + /* Special return value '1' means: do not free */ + if (rc != 1 && msg) + msgb_free(msg); + + return rc; +} + +/* any L1 prim sent to bts model */ +static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + if (OSMO_PRIM_HDR(&l1sap->oph) == + OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST)) + to_gsmtap(trx, l1sap); + + return bts_model_l1sap_down(trx, l1sap); +} + +/* pcu (socket interface) sends us a data request primitive */ +int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, + uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len) +{ + struct msgb *msg; + struct osmo_phsap_prim *l1sap; + struct gsm_time g_time; + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "TX packet data %02u/%02u/%02u is_ptcch=%d trx=%d ts=%d " + "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2, + g_time.t3, is_ptcch, ts->trx->nr, ts->nr, block_nr, arfcn, len); + + msg = l1sap_msgb_alloc(len); + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_REQUEST, + msg); + l1sap->u.data.chan_nr = 0x08 | ts->nr; + l1sap->u.data.link_id = 0x00; + l1sap->u.data.fn = fn; + msg->l2h = msgb_put(msg, len); + memcpy(msg->l2h, data, len); + + return l1sap_down(ts->trx, l1sap); +} + +/*! \brief call-back function for incoming RTP */ +void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, + unsigned int rtp_pl_len) +{ + struct gsm_lchan *lchan = rs->priv; + struct msgb *msg, *tmp; + struct osmo_phsap_prim *l1sap; + int count = 0; + + msg = l1sap_msgb_alloc(rtp_pl_len); + if (!msg) + return; + memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + msgb_pull(msg, sizeof(*l1sap)); + + + /* make sure the queue doesn't get too long */ + llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) + count++; + while (count >= 2) { + tmp = msgb_dequeue(&lchan->dl_tch_queue); + msgb_free(tmp); + count--; + } + + msgb_enqueue(&lchan->dl_tch_queue, msg); +} + +static int l1sap_chan_act_dact_modify(struct gsm_bts_trx *trx, uint8_t chan_nr, + enum osmo_mph_info_type type, uint8_t sacch_only) +{ + struct osmo_phsap_prim l1sap; + + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, PRIM_OP_REQUEST, + NULL); + l1sap.u.info.type = type; + l1sap.u.info.u.act_req.chan_nr = chan_nr; + l1sap.u.info.u.act_req.sacch_only = sacch_only; + + return l1sap_down(trx, &l1sap); +} + +int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + struct gsm_bts_role_bts *btsb = trx->bts->role; + struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)] + .lchan[l1sap_chan2ss(chan_nr)]; + + LOGP(DL1P, LOGL_INFO, "activating channel chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + lchan->sacch_deact = 0; + lchan->s = btsb->radio_link_timeout; + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_ACTIVATE, 0); +} + +int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, + 0); +} + +int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)] + .lchan[l1sap_chan2ss(chan_nr)]; + + LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + lchan->sacch_deact = 1; + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, + 1); +} + +int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_MODIFY, 0); +} diff --git a/src/common/logging.c b/src/common/logging.c index 98fd205..f56846e 100644 --- a/src/common/logging.c +++ b/src/common/logging.c @@ -69,8 +69,8 @@ static struct log_info_cat bts_log_info_cat[] = { [DL1C] = { .name = "DL1C", .description = "Layer 1", - .loglevel = LOGL_INFO, - .enabled = 1, + .color = "\033[1;32m", + .enabled = 1, .loglevel = LOGL_NOTICE, }, [DL1P] = { .name = "DL1P", diff --git a/src/common/measurement.c b/src/common/measurement.c index 774962d..ff80a9f 100644 --- a/src/common/measurement.c +++ b/src/common/measurement.c @@ -89,6 +89,11 @@ static int is_meas_complete(enum gsm_phys_chan_config pchan, unsigned int ts, /* receive a L1 uplink measurement from L1 */ int lchan_new_ul_meas(struct gsm_lchan *lchan, struct bts_ul_meas *ulm) { + /* in the GPRS case we are not interested in measurement + * processing. The PCU will take care of it */ + if (lchan->type == GSM_LCHAN_PDTCH) + return 0; + DEBUGP(DMEAS, "%s adding measurement, num_ul_meas=%d\n", gsm_lchan_name(lchan), lchan->meas.num_ul_meas);
diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index a90caac..76ecf22 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -39,7 +39,7 @@ #include <osmo-bts/bts.h> #include <osmo-bts/rsl.h> #include <osmo-bts/signal.h> -#include <osmo-bts/bts_model.h> +#include <osmo-bts/l1sap.h>
uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx);
@@ -57,10 +57,6 @@ static const char *sapi_string[] = { [PCU_IF_SAPI_PTCCH] = "PTCCH", };
-/* FIXME: common l1if include ? */ -int l1if_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, - uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); - static int pcu_sock_send(struct gsm_network *net, struct msgb *msg); /* FIXME: move this to libosmocore */ int osmo_unixsock_listen(struct osmo_fd *bfd, int type, const char *path); @@ -511,7 +507,7 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, } ts = &trx->ts[data_req->ts_nr]; is_ptcch = (data_req->sapi == PCU_IF_SAPI_PTCCH); - rc = l1if_pdch_req(ts, is_ptcch, data_req->fn, data_req->arfcn, + rc = l1sap_pdch_req(ts, is_ptcch, data_req->fn, data_req->arfcn, data_req->block_nr, data_req->data, data_req->len); break; default: @@ -544,9 +540,9 @@ static int pcu_rx_act_req(struct gsm_bts *bts, return -EINVAL; } if (act_req->activate) - bts_model_rsl_chan_act(lchan, NULL); + l1sap_chan_act(trx, gsm_lchan2chan_nr(lchan)); else - bts_model_rsl_chan_rel(lchan); + l1sap_chan_rel(trx, gsm_lchan2chan_nr(lchan));
return 0; } @@ -650,7 +646,8 @@ static void pcu_sock_close(struct pcu_sock_state *state) ts = &trx->ts[j]; if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED && ts->pchan == GSM_PCHAN_PDCH) - bts_model_rsl_chan_rel(ts->lchan); + l1sap_chan_rel(trx, + gsm_lchan2chan_nr(ts->lchan)); } }
diff --git a/src/common/rsl.c b/src/common/rsl.c index 616ae0d..150f686 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -41,9 +41,9 @@ #include <osmo-bts/oml.h> #include <osmo-bts/amr.h> #include <osmo-bts/signal.h> -#include <osmo-bts/bts_model.h> #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> +#include <osmo-bts/l1sap.h>
//#define FAKE_CIPH_MODE_COMPL
@@ -499,8 +499,9 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan) }
/* 8.4.2 sending CHANnel ACTIVation ACKnowledge */ -int rsl_tx_chan_act_ack(struct gsm_lchan *lchan, struct gsm_time *gtime) +int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) { + struct gsm_time *gtime = get_time(lchan->ts->trx->bts); struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); uint8_t ie[2]; @@ -760,14 +761,12 @@ static int rsl_rx_chan_activ(struct msgb *msg) dch->chan_nr, type, lchan->tch_mode);
/* actually activate the channel in the BTS */ - return bts_model_rsl_chan_act(msg->lchan, &tp); + return l1sap_chan_act(lchan->ts->trx, dch->chan_nr); }
/* 8.4.14 RF CHANnel RELease is received */ -static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan) +static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr) { - int rc; - if (lchan->abis_ip.rtp_socket) { rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC); osmo_rtp_socket_free(lchan->abis_ip.rtp_socket); @@ -775,11 +774,11 @@ static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan) msgb_queue_flush(&lchan->dl_tch_queue); }
- rc = bts_model_rsl_chan_rel(lchan); + l1sap_chan_rel(lchan->ts->trx, chan_nr);
lapdm_channel_exit(&lchan->lapdm_ch);
- return rc; + return 0; }
#ifdef FAKE_CIPH_MODE_COMPL @@ -962,10 +961,10 @@ static int rsl_tx_mode_modif_ack(struct gsm_lchan *lchan) /* 8.4.9 MODE MODIFY */ static int rsl_rx_mode_modif(struct msgb *msg) { + struct abis_rsl_dchan_hdr *dch = msgb_l2(msg); struct gsm_lchan *lchan = msg->lchan; struct rsl_ie_chan_mode *cm; struct tlv_parsed tp; - int rc;
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
@@ -1005,12 +1004,12 @@ static int rsl_rx_mode_modif(struct msgb *msg) /* 9.3.53 MultiRate Control */ /* 9.3.54 Supported Codec Types */
- rc = bts_model_rsl_mode_modify(msg->lchan); + l1sap_chan_modify(lchan->ts->trx, dch->chan_nr);
/* FIXME: delay this until L1 says OK? */ - rsl_tx_mode_modif_ack(msg->lchan); + rsl_tx_mode_modif_ack(lchan);
- return rc; + return 0; }
/* 8.4.20 SACCH INFO MODify */ @@ -1314,7 +1313,7 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg) OSMO_RTP_P_JITBUF, btsb->rtp_jitter_buf_ms); lchan->abis_ip.rtp_socket->priv = lchan; - lchan->abis_ip.rtp_socket->rx_cb = &bts_model_rtp_rx_cb; + lchan->abis_ip.rtp_socket->rx_cb = &l1sap_rtp_rx_cb;
if (connect_ip && connect_port) { /* if CRCX specifies a remote IP, we can bind() @@ -1646,13 +1645,13 @@ static int rsl_rx_dchan(struct gsm_bts_trx *trx, struct msgb *msg) ret = rsl_rx_chan_activ(msg); break; case RSL_MT_RF_CHAN_REL: - ret = rsl_rx_rf_chan_rel(msg->lchan); + ret = rsl_rx_rf_chan_rel(msg->lchan, dch->chan_nr); break; case RSL_MT_SACCH_INFO_MODIFY: ret = rsl_rx_sacch_inf_mod(msg); break; case RSL_MT_DEACTIVATE_SACCH: - ret = bts_model_rsl_deact_sacch(msg->lchan); + ret = l1sap_chan_deact_sacch(trx, dch->chan_nr); break; case RSL_MT_ENCR_CMD: ret = rsl_rx_encr_cmd(msg); diff --git a/src/common/vty.c b/src/common/vty.c index 5eddc8d..4daa92c 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -22,12 +22,15 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <ctype.h>
#include <osmocom/core/talloc.h> #include <osmocom/gsm/abis_nm.h> #include <osmocom/vty/vty.h> #include <osmocom/vty/command.h> #include <osmocom/vty/logging.h> +#include <osmocom/vty/misc.h> +#include <osmocom/core/gsmtap.h>
#include <osmocom/trau/osmo_ortp.h>
@@ -42,7 +45,7 @@ #include <osmo-bts/bts_model.h> #include <osmo-bts/measurement.h> #include <osmo-bts/vty.h> - +#include <osmo-bts/l1sap.h>
enum node_type bts_vty_go_parent(struct vty *vty) { @@ -171,10 +174,38 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, return CMD_SUCCESS; }
+/* FIXME: move to libosmocore ? */ +static char buf_casecnvt[256]; +char *osmo_str_tolower(const char *in) +{ + int len, i; + + if (!in) + return NULL; + + len = strlen(in); + if (len > sizeof(buf_casecnvt)) + len = sizeof(buf_casecnvt); + + for (i = 0; i < len; i++) { + buf_casecnvt[i] = tolower(in[i]); + if (in[i] == '\0') + break; + } + if (i < sizeof(buf_casecnvt)) + buf_casecnvt[i] = '\0'; + + /* just to make sure we're always zero-terminated */ + buf_casecnvt[sizeof(buf_casecnvt)-1] = '\0'; + + return buf_casecnvt; +} + static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm_bts_trx *trx; + int i;
vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE); if (bts->description) @@ -190,6 +221,17 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(btsb->paging_state), VTY_NEWLINE);
+ for (i = 0; i < 32; i++) { + if (gsmtap_sapi_mask & (1 << i)) { + const char *name = get_value_string(gsmtap_sapi_names, i); + vty_out(vty, " gsmtap-sapi %s%s", osmo_str_tolower(name), VTY_NEWLINE); + } + } + if (gsmtap_sapi_acch) { + const char *name = get_value_string(gsmtap_sapi_names, GSMTAP_CHANNEL_ACCH); + vty_out(vty, " gsmtap-sapi %s%s", osmo_str_tolower(name), VTY_NEWLINE); + } + bts_model_config_write_bts(vty, bts);
llist_for_each_entry(trx, &bts->trx_list, list) { @@ -475,6 +517,36 @@ static struct gsm_lchan *resolve_lchan(struct gsm_network *net, "logical channel commands\n" \ "logical channel number\n"
+DEFUN(cfg_trx_gsmtap_sapi, cfg_trx_gsmtap_sapi_cmd, + "HIDDEN", "HIDDEN") +{ + int sapi; + + sapi = get_string_value(gsmtap_sapi_names, argv[0]); + + if (sapi == GSMTAP_CHANNEL_ACCH) + gsmtap_sapi_acch = 1; + else + gsmtap_sapi_mask |= (1 << sapi); + + return CMD_SUCCESS; +} + +DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, + "HIDDEN", "HIDDEN") +{ + int sapi; + + sapi = get_string_value(gsmtap_sapi_names, argv[0]); + + if (sapi == GSMTAP_CHANNEL_ACCH) + gsmtap_sapi_acch = 0; + else + gsmtap_sapi_mask &= ~(1 << sapi); + + return CMD_SUCCESS; +} + DEFUN(bts_t_t_l_jitter_buf, bts_t_t_l_jitter_buf_cmd, "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> rtp jitter-buffer <0-10000>", @@ -501,8 +573,58 @@ DEFUN(bts_t_t_l_jitter_buf, return CMD_SUCCESS; }
-int bts_vty_init(const struct log_info *cat) +DEFUN(bts_t_t_l_loopback, + bts_t_t_l_loopback_cmd, + "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> loopback", + BTS_T_T_L_STR "Set loopback\n") { + struct gsm_network *net = gsmnet_from_vty(vty); + struct gsm_lchan *lchan; + + lchan = resolve_lchan(net, argv, 0); + if (!lchan) { + vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + lchan->loopback = 1; + + return CMD_SUCCESS; +} + +DEFUN(no_bts_t_t_l_loopback, + no_bts_t_t_l_loopback_cmd, + "no bts <0-0> trx <0-0> ts <0-7> lchan <0-1> loopback", + NO_STR BTS_T_T_L_STR "Set loopback\n") +{ + struct gsm_network *net = gsmnet_from_vty(vty); + struct gsm_lchan *lchan; + + lchan = resolve_lchan(net, argv, 0); + if (!lchan) { + vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + lchan->loopback = 0; + + return CMD_SUCCESS; +} + +int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) +{ + cfg_trx_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + "gsmtap-sapi (", + "|",")", VTY_DO_LOWER); + cfg_trx_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + "GSMTAP SAPI\n", + "\n", "", 0); + + cfg_trx_no_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + "no gsmtap-sapi (", + "|",")", VTY_DO_LOWER); + cfg_trx_no_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + NO_STR "GSMTAP SAPI\n", + "\n", "", 0); + install_element_ve(&show_bts_cmd);
logging_vty_add_cmds(cat); @@ -520,12 +642,17 @@ int bts_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_paging_queue_size_cmd); install_element(BTS_NODE, &cfg_bts_paging_lifetime_cmd);
+ install_element(BTS_NODE, &cfg_trx_gsmtap_sapi_cmd); + install_element(BTS_NODE, &cfg_trx_no_gsmtap_sapi_cmd); + /* add and link to TRX config node */ install_element(BTS_NODE, &cfg_bts_trx_cmd); install_node(&trx_node, config_write_dummy); install_default(TRX_NODE);
install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd); + install_element(ENABLE_NODE, &bts_t_t_l_loopback_cmd); + install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd);
return 0; } diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 16f1523..6efb9d6 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1303,3 +1303,9 @@ int l1if_close(struct femtol1_hdl *fl1h) l1if_transport_close(MQ_SYS_WRITE, fl1h); return 0; } + +/* temporary stub to make this patch compile */ +int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + return -ENOTSUP; +} diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 595a6eb..7e7f761 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -255,7 +255,7 @@ int main(int argc, char **argv) bts_log_init(NULL);
vty_init(&bts_vty_info); - bts_vty_init(&bts_log_info); + bts_vty_init(bts, &bts_log_info);
handle_options(argc, argv);
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index faef025..aeddad7 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -868,10 +868,8 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) if (lchan->state != LCHAN_S_ACT_REQ) return 0;
- struct gsm_time *time; lchan_set_state(lchan, LCHAN_S_ACTIVE); - time = bts_model_get_time(lchan->ts->trx->bts); - rsl_tx_chan_act_ack(lchan, time); + rsl_tx_chan_act_ack(lchan);
/* set the initial ciphering parameters for both directions */ l1if_set_ciphering(fl1h, lchan, 0); diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index 5bc948e..61deda4 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -444,33 +444,6 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " auto-band%s", VTY_NEWLINE); }
-/* FIXME: move to libosmocore ? */ -static char buf_casecnvt[256]; -char *osmo_str_tolower(const char *in) -{ - int len, i; - - if (!in) - return NULL; - - len = strlen(in); - if (len > sizeof(buf_casecnvt)) - len = sizeof(buf_casecnvt); - - for (i = 0; i < len; i++) { - buf_casecnvt[i] = tolower(in[i]); - if (in[i] == '\0') - break; - } - if (i < sizeof(buf_casecnvt)) - buf_casecnvt[i] = '\0'; - - /* just to make sure we're always zero-terminated */ - buf_casecnvt[sizeof(buf_casecnvt)-1] = '\0'; - - return buf_casecnvt; -} - void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); diff --git a/tests/stubs.c b/tests/stubs.c index c46bb4a..c0089c5 100644 --- a/tests/stubs.c +++ b/tests/stubs.c @@ -46,3 +46,6 @@ int l1if_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn,
uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) { return 0; } + +int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ return 0; }
On Mon, Jul 15, 2013 at 10:35:31AM +0200, Andreas Eversberg wrote:
Instead of handling primitives directly at layer 1 specific code, osmo-bts handles primitives at common code. Therefore a new file 'l1sap.c' is added and integrated.
make distcheck... is faili...
Holger Hans Peter Freyther wrote:
make distcheck... is faili...
what message do you get? my distcheck looks weird:
... checking for LIBOSMOCORE... yes checking for LIBOSMOVTY... yes checking for LIBOSMOTRAU... yes checking for LIBOSMOGSM... yes checking whether to enable sysmocom-bts hardware support... no checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking openbsc/gsm_data_shared.h usability... no checking openbsc/gsm_data_shared.h presence... no checking for openbsc/gsm_data_shared.h... no configure: error: openbsc/gsm_data_shared.h can not be found in /files/projects/gsm/osmo-bts/osmo-bts-0.3.0.34-ea0c/../openbsc/openbsc/include make: *** [distcheck] Error 1
On Mon, Jul 15, 2013 at 04:58:53PM +0200, Andreas Eversberg wrote:
make distcheck... is faili...
what message do you get? my distcheck looks weird:
Really? After the issues/thread we had last week? You are supposed to do these checks before asking people to review. If make distcheck doesn't work for you, you should ask before posting your patches.
Holger Hans Peter Freyther wrote:
Really? After the issues/thread we had last week? You are supposed to do these checks before asking people to review. If make distcheck doesn't work for you, you should ask before posting your patches
it workes, if i link openbsc to the osmo-bts directory:
ln -s path/to/openbsc/ .
attached is the corrected version. include/osmo-bts/l1sap.h was not added to the makefile of include/osmo-bts.
On Mon, Jul 15, 2013 at 07:35:12PM +0200, Andreas Eversberg wrote:
ln -s path/to/openbsc/ .
attached is the corrected version. include/osmo-bts/l1sap.h was not added to the makefile of include/osmo-bts.
You could have taken a look at the build log of the jenkins and see the DISTCHECK_CONFIGURE_FLAGS environment variable in use. These flags will be passed to configure.
Do the other patches pass make distcheck too?
Holger Hans Peter Freyther wrote:
Do the other patches pass make distcheck too?
yes, every patch works. i did a "git reset --hard" for scrolling back patch by patch. is there a more elegant way to test every patch?
On Mon, Jul 15, 2013 at 08:04:34PM +0200, Andreas Eversberg wrote:
yes, every patch works. i did a "git reset --hard" for scrolling back patch by patch. is there a more elegant way to test every patch?
With git 1.8 one can do git rebase -i -x "CMD FOR EVERY CHANGE" origin/master, the script I posted yesterday is using it
Instead of handling primitves itself, sysmo-bts code sends and receives PH-/MPH-/TCH primitves to and from common code. --- src/osmo-bts-sysmo/l1_if.c | 1092 +++++++++++++++++-------------------- src/osmo-bts-sysmo/l1_if.h | 13 +- src/osmo-bts-sysmo/main.c | 3 +- src/osmo-bts-sysmo/oml.c | 46 +- src/osmo-bts-sysmo/sysmobts_vty.c | 94 ---- src/osmo-bts-sysmo/tch.c | 117 +--- 6 files changed, 559 insertions(+), 806 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 6efb9d6..f2e4440 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -32,21 +32,17 @@ #include <osmocom/core/select.h> #include <osmocom/core/timer.h> #include <osmocom/core/write_queue.h> -#include <osmocom/core/gsmtap.h> -#include <osmocom/core/gsmtap_util.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/lapdm.h>
-#include <osmocom/trau/osmo_ortp.h> - #include <osmo-bts/logging.h> #include <osmo-bts/bts.h> #include <osmo-bts/oml.h> -#include <osmo-bts/rsl.h> #include <osmo-bts/gsm_data.h> #include <osmo-bts/paging.h> #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> +#include <osmo-bts/l1sap.h>
#include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -63,98 +59,6 @@ extern int pcu_direct; #define MIN_QUAL_RACH 5.0f /* at least 5 dB C/I */ #define MIN_QUAL_NORM -0.5f /* at least -1 dB C/I */
-/* mapping from femtobts L1 SAPI to GSMTAP channel type */ -static const uint8_t l1sapi2gsmtap_cht[GsmL1_Sapi_NUM] = { - [GsmL1_Sapi_Idle] = 255, - [GsmL1_Sapi_Fcch] = 255, - [GsmL1_Sapi_Sch] = 255, - [GsmL1_Sapi_Sacch] = GSMTAP_CHANNEL_SDCCH | GSMTAP_CHANNEL_ACCH, - [GsmL1_Sapi_Sdcch] = GSMTAP_CHANNEL_SDCCH, - [GsmL1_Sapi_Bcch] = GSMTAP_CHANNEL_BCCH, - [GsmL1_Sapi_Pch] = GSMTAP_CHANNEL_PCH, - [GsmL1_Sapi_Agch] = GSMTAP_CHANNEL_AGCH, - [GsmL1_Sapi_Cbch] = GSMTAP_CHANNEL_CBCH51, - [GsmL1_Sapi_Rach] = GSMTAP_CHANNEL_RACH, - [GsmL1_Sapi_TchF] = 255, - [GsmL1_Sapi_FacchF] = GSMTAP_CHANNEL_TCH_F, - [GsmL1_Sapi_TchH] = 255, - [GsmL1_Sapi_FacchH] = GSMTAP_CHANNEL_TCH_H, - [GsmL1_Sapi_Nch] = GSMTAP_CHANNEL_CCCH, - [GsmL1_Sapi_Pdtch] = GSMTAP_CHANNEL_PACCH, - [GsmL1_Sapi_Pacch] = GSMTAP_CHANNEL_PACCH, - [GsmL1_Sapi_Pbcch] = 255, - [GsmL1_Sapi_Pagch] = 255, - [GsmL1_Sapi_Ppch] = 255, - [GsmL1_Sapi_Pnch] = 255, - [GsmL1_Sapi_Ptcch] = GSMTAP_CHANNEL_PTCCH, - [GsmL1_Sapi_Prach] = 255, -}; - -static void tx_to_gsmtap(struct femtol1_hdl *fl1h, struct msgb *msg) -{ - struct gsm_bts_trx *trx = fl1h->priv; - GsmL1_Prim_t *l1p = msgb_l1prim(msg); - GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; - - if (fl1h->gsmtap) { - uint8_t ss, chan_type; - if (data_req->subCh == 0x1f) - ss = 0; - else - ss = data_req->subCh; - - if (!(fl1h->gsmtap_sapi_mask & (1 << data_req->sapi))) - return; - - chan_type = l1sapi2gsmtap_cht[data_req->sapi]; - if (chan_type == 255) - return; - - gsmtap_send(fl1h->gsmtap, trx->arfcn, data_req->u8Tn, - chan_type, ss, data_req->u32Fn, 0, 0, - data_req->msgUnitParam.u8Buffer, - data_req->msgUnitParam.u8Size); - } -} - -static void ul_to_gsmtap(struct femtol1_hdl *fl1h, struct msgb *msg) -{ - struct gsm_bts_trx *trx = fl1h->priv; - GsmL1_Prim_t *l1p = msgb_l1prim(msg); - GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd; - int skip = 0; - - if (fl1h->gsmtap) { - uint8_t ss, chan_type; - if (data_ind->subCh == 0x1f) - ss = 0; - else - ss = data_ind->subCh; - - if (!(fl1h->gsmtap_sapi_mask & (1 << data_ind->sapi))) - return; - - chan_type = l1sapi2gsmtap_cht[data_ind->sapi]; - if (chan_type == 255) - return; - if (chan_type == GSMTAP_CHANNEL_PACCH - || chan_type == GSMTAP_CHANNEL_PDCH) { - if (data_ind->msgUnitParam.u8Buffer[0] - != GsmL1_PdtchPlType_Full) - return; - skip = 1; - } - - gsmtap_send(fl1h->gsmtap, trx->arfcn | GSMTAP_ARFCN_F_UPLINK, - data_ind->u8Tn, chan_type, ss, data_ind->u32Fn, - data_ind->measParam.fRssi, - data_ind->measParam.fLinkQuality, - data_ind->msgUnitParam.u8Buffer + skip, - data_ind->msgUnitParam.u8Size - skip); - } -} - - struct wait_l1_conf { struct llist_head list; /* internal linked list */ struct osmo_timer_list timer; /* timer for L1 timeout */ @@ -314,74 +218,442 @@ empty_req_from_rts_ind(GsmL1_Prim_t *l1p, return empty_req; }
-/* obtain a ptr to the lapdm_channel for a given hLayer2 */ -static struct lapdm_channel * -get_lapdm_chan_by_hl2(struct gsm_bts_trx *trx, uint32_t hLayer2) -{ - struct gsm_lchan *lchan; +static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { + 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B +};
- lchan = l1if_hLayer_to_lchan(trx, hLayer2); - if (!lchan) - return NULL; +static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) +{ + LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, " + "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality, + m->fBer, m->i16BurstTiming); +}
- return &lchan->lapdm_ch; +static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, + GsmL1_MeasParam_t *m) +{ + struct osmo_phsap_prim l1sap; + + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, + PRIM_OP_INDICATION, NULL); + l1sap.u.info.type = PRIM_INFO_MEAS; + l1sap.u.info.u.meas_ind.chan_nr = chan_nr; + l1sap.u.info.u.meas_ind.ta_offs_qbits = m->i16BurstTiming; + l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (m->fBer * 100); + l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (m->fRssi * -1); + + return l1sap_up(trx, &l1sap); }
-/* check if the message is a GSM48_MT_RR_CIPH_M_CMD, and if yes, enable - * uni-directional de-cryption on the uplink. We need this ugly layering - * violation as we have no way of passing down L3 metadata (RSL CIPHERING CMD) - * to this point in L1 */ -static int check_for_ciph_cmd(struct femtol1_hdl *fl1h, - struct msgb *msg, struct gsm_lchan *lchan) +/* primitive from common part */ +int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { + struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); + struct msgb *msg = l1sap->oph.msg; + uint32_t u32Fn; + uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi, ss; + uint8_t chan_nr, link_id; + int rc = 0; + struct msgb *nmsg = NULL; + GsmL1_Prim_t *l1p; + struct gsm_lchan *lchan; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): + if (!msg) { + LOGP(DL1C, LOGL_FATAL, "PH-DATA.req without msg. " + "Please fix!\n"); + abort(); + } + chan_nr = l1sap->u.data.chan_nr; + link_id = l1sap->u.data.link_id; + u32Fn = l1sap->u.data.fn; + u8Tn = L1SAP_CHAN2TS(chan_nr); + subCh = 0x1f; + if (L1SAP_IS_LINK_SACCH(link_id)) { + sapi = GsmL1_Sapi_Sacch; + if (!L1SAP_IS_CHAN_TCHF(chan_nr)) + subCh = l1sap_chan2ss(chan_nr); + } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { + if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) { + if (L1SAP_IS_PTCCH(u32Fn)) { + sapi = GsmL1_Sapi_Ptcch; + u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); + } else { + sapi = GsmL1_Sapi_Pdtch; + u8BlockNbr = L1SAP_FN2MACBLOCK(u32Fn); + } + } else { + sapi = GsmL1_Sapi_FacchF; + u8BlockNbr = (u32Fn % 13) >> 2; + } + } else if (L1SAP_IS_CHAN_TCHH(chan_nr)) { + subCh = L1SAP_CHAN2SS_TCHH(chan_nr); + sapi = GsmL1_Sapi_FacchH; + u8BlockNbr = (u32Fn % 26) >> 3; + } else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) { + subCh = L1SAP_CHAN2SS_SDCCH4(chan_nr); + sapi = GsmL1_Sapi_Sdcch; + } else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) { + subCh = L1SAP_CHAN2SS_SDCCH8(chan_nr); + sapi = GsmL1_Sapi_Sdcch; + } else if (L1SAP_IS_CHAN_BCCH(chan_nr)) { + sapi = GsmL1_Sapi_Bcch; + } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { +#warning Set BS_AG_BLKS_RES + /* The sapi depends on DSP configuration, not + * on the actual SYSTEM INFORMATION 3. */ + u8BlockNbr = L1SAP_FN2CCCHBLOCK(u32Fn); + if (u8BlockNbr >= 1) + sapi = GsmL1_Sapi_Pch; + else + sapi = GsmL1_Sapi_Agch; + } else { + LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d " + "chan_nr %d link_id %d\n", l1sap->oph.primitive, + l1sap->oph.operation, chan_nr, link_id); + rc = -EINVAL; + goto done; + } + + msgb_pull(msg, sizeof(*l1sap)); + + /* create new message */ + nmsg = l1p_msgb_alloc(); + l1p = msgb_l1prim(nmsg); + if (msg->len) { + /* data request */ + GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; + GsmL1_MsgUnitParam_t *msu_param; + + l1p->id = GsmL1_PrimId_PhDataReq; + + data_req->hLayer1 = fl1->hLayer1; + data_req->u8Tn = u8Tn; + data_req->u32Fn = u32Fn; + data_req->sapi = sapi; + data_req->subCh = subCh; + data_req->u8BlockNbr = u8BlockNbr; + msu_param = &data_req->msgUnitParam; + msu_param->u8Size = msg->len; + memcpy(msu_param->u8Buffer, msg->data, msg->len); + } else { + /* empty frame */ + GsmL1_PhEmptyFrameReq_t *empty_req = + &l1p->u.phEmptyFrameReq; + + l1p->id = GsmL1_PrimId_PhEmptyFrameReq; + + empty_req->hLayer1 = fl1->hLayer1; + empty_req->u8Tn = u8Tn; + empty_req->u32Fn = u32Fn; + empty_req->sapi = sapi; + empty_req->subCh = subCh; + empty_req->u8BlockNbr = u8BlockNbr; + } + + /* send message to DSP's queue */ + osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg); + break; + case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST): + chan_nr = l1sap->u.tch.chan_nr; + u32Fn = l1sap->u.tch.fn; + u8Tn = L1SAP_CHAN2TS(chan_nr); + u8BlockNbr = (u32Fn % 13) >> 2; + if (L1SAP_IS_CHAN_TCHH(chan_nr)) { + ss = subCh = L1SAP_CHAN2SS_TCHH(chan_nr); + sapi = GsmL1_Sapi_TchH; + } else { + subCh = 0x1f; + ss = 0; + sapi = GsmL1_Sapi_TchF; + } + + lchan = &trx->ts[u8Tn].lchan[ss]; + + /* create new message and fill data */ + if (msg) { + msgb_pull(msg, sizeof(*l1sap)); + /* create new message */ + nmsg = l1p_msgb_alloc(); + if (!nmsg) { + rc = -ENOMEM; + goto done; + } + l1p = msgb_l1prim(nmsg); + l1if_tch_encode(lchan, + l1p->u.phDataReq.msgUnitParam.u8Buffer, + &l1p->u.phDataReq.msgUnitParam.u8Size, + msg->data, msg->len); + } + + /* no message/data, we generate an empty traffic msg */ + if (!nmsg) + nmsg = gen_empty_tch_msg(lchan); + + /* no traffic message, we generate an empty msg */ + if (!nmsg) { + nmsg = l1p_msgb_alloc(); + if (!nmsg) { + rc = -ENOMEM; + goto done; + } + } + + l1p = msgb_l1prim(nmsg);
- /* only do this if we are in the right state */ - switch (lchan->ciph_state) { - case LCHAN_CIPH_NONE: - case LCHAN_CIPH_RX_REQ: + /* if we provide data, or if data is already in nmsg */ + if (l1p->u.phDataReq.msgUnitParam.u8Size) { + /* data request */ + GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; + + l1p->id = GsmL1_PrimId_PhDataReq; + + data_req->hLayer1 = fl1->hLayer1; + data_req->u8Tn = u8Tn; + data_req->u32Fn = u32Fn; + data_req->sapi = sapi; + data_req->subCh = subCh; + data_req->u8BlockNbr = u8BlockNbr; + } else { + /* empty frame */ + GsmL1_PhEmptyFrameReq_t *empty_req = + &l1p->u.phEmptyFrameReq; + + l1p->id = GsmL1_PrimId_PhEmptyFrameReq; + + empty_req->hLayer1 = fl1->hLayer1; + empty_req->u8Tn = u8Tn; + empty_req->u32Fn = u32Fn; + empty_req->sapi = sapi; + empty_req->subCh = subCh; + empty_req->u8BlockNbr = u8BlockNbr; + } + /* send message to DSP's queue */ + osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg); + break; + case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST): + switch (l1sap->u.info.type) { + case PRIM_INFO_ACT_CIPH: + chan_nr = l1sap->u.info.u.ciph_req.chan_nr; + u8Tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + lchan = &trx->ts[u8Tn].lchan[ss]; + if (l1sap->u.info.u.ciph_req.downlink) { + l1if_set_ciphering(fl1, lchan, 1); + lchan->ciph_state = LCHAN_CIPH_RX_REQ; + } + if (l1sap->u.info.u.ciph_req.uplink) { + l1if_set_ciphering(fl1, lchan, 0); + lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + } + break; + case PRIM_INFO_ACTIVATE: + case PRIM_INFO_DEACTIVATE: + case PRIM_INFO_MODIFY: + chan_nr = l1sap->u.info.u.act_req.chan_nr; + u8Tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + lchan = &trx->ts[u8Tn].lchan[ss]; + if (l1sap->u.info.type == PRIM_INFO_ACTIVATE) + l1if_rsl_chan_act(lchan); + else if (l1sap->u.info.type == PRIM_INFO_MODIFY) + l1if_rsl_mode_modify(lchan); + else if (l1sap->u.info.u.act_req.sacch_only) + l1if_rsl_deact_sacch(lchan); + else + l1if_rsl_chan_rel(lchan); + break; + default: + LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n", + l1sap->u.info.type); + rc = -EINVAL; + goto done; + } break; default: - return 0; + LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n", + l1sap->oph.primitive, l1sap->oph.operation); + rc = -EINVAL; + goto done; }
- /* First byte (Address Field) of LAPDm header) */ - if (msg->data[0] != 0x03) - return 0; - /* First byte (protocol discriminator) of RR */ - if ((msg->data[3] & 0xF) != GSM48_PDISC_RR) - return 0; - /* 2nd byte (msg type) of RR */ - if ((msg->data[4] & 0x3F) != GSM48_MT_RR_CIPH_M_CMD) +done: + if (msg) + msgb_free(msg); + return rc; +} + +static int handle_mph_time_ind(struct femtol1_hdl *fl1, + GsmL1_MphTimeInd_t *time_ind) +{ + struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts *bts = trx->bts; + struct osmo_phsap_prim l1sap; + uint32_t fn; + + /* increment the primitive count for the alive timer */ + fl1->alive_prim_cnt++; + + /* ignore every time indication, except for c0 */ + if (trx != bts->c0) { return 0; + }
- lchan->ciph_state = LCHAN_CIPH_RX_REQ; - l1if_set_ciphering(fl1h, lchan, 0); + fn = time_ind->u32Fn;
- return 1; + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, + PRIM_OP_INDICATION, NULL); + l1sap.u.info.type = PRIM_INFO_TIME; + l1sap.u.info.u.time_ind.fn = fn; + + return l1sap_up(trx, &l1sap); }
-static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { - 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B -}; +static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, + GsmL1_Sapi_t sapi, GsmL1_SubCh_t subCh, + uint8_t u8Tn, uint32_t u32Fn) +{ + uint8_t cbits = 0; + switch (sapi) { + case GsmL1_Sapi_Bcch: + cbits = 0x10; + break; + case GsmL1_Sapi_Sacch: + switch(pchan) { + case GSM_PCHAN_TCH_F: + cbits = 0x01; + break; + case GSM_PCHAN_TCH_H: + cbits = 0x02 + subCh; + break; + case GSM_PCHAN_CCCH_SDCCH4: + cbits = 0x04 + subCh; + break; + case GSM_PCHAN_SDCCH8_SACCH8C: + cbits = 0x08 + subCh; + break; + default: + LOGP(DL1C, LOGL_ERROR, "SACCH for pchan %d?\n", + pchan); + return 0; + } + break; + case GsmL1_Sapi_Sdcch: + switch(pchan) { + case GSM_PCHAN_CCCH_SDCCH4: + cbits = 0x04 + subCh; + break; + case GSM_PCHAN_SDCCH8_SACCH8C: + cbits = 0x08 + subCh; + break; + default: + LOGP(DL1C, LOGL_ERROR, "SDCCH for pchan %d?\n", + pchan); + return 0; + } + break; + case GsmL1_Sapi_Agch: + case GsmL1_Sapi_Pch: + cbits = 0x12; + break; + case GsmL1_Sapi_TchF: + cbits = 0x01; + break; + case GsmL1_Sapi_TchH: + cbits = 0x02 + subCh; + break; + case GsmL1_Sapi_FacchF: + cbits = 0x01; + break; + case GsmL1_Sapi_FacchH: + cbits = 0x02 + subCh; + break; + case GsmL1_Sapi_Pdtch: + case GsmL1_Sapi_Pacch: + switch(pchan) { + case GSM_PCHAN_PDCH: + cbits = 0x01; + break; + default: + LOGP(DL1C, LOGL_ERROR, "PDTCH for pchan %d?\n", + pchan); + return 0; + } + break; + case GsmL1_Sapi_Ptcch: + if (!L1SAP_IS_PTCCH(u32Fn)) { + LOGP(DL1C, LOGL_FATAL, "Not expecting PTCCH at frame " + "number other than 12, got it at %u (%u). " + "Please fix!\n", u32Fn % 52, u32Fn); + abort(); + } + switch(pchan) { + case GSM_PCHAN_PDCH: + cbits = 0x01; + break; + default: + LOGP(DL1C, LOGL_ERROR, "PTCCH for pchan %d?\n", + pchan); + return 0; + } + break; + default: + return 0; + } + + return (cbits << 3) | u8Tn; +}
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, - GsmL1_PhReadyToSendInd_t *rts_ind) + GsmL1_PhReadyToSendInd_t *rts_ind, + struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts; - struct gsm_bts_role_bts *btsb = bts->role; + struct osmo_phsap_prim *l1sap; + struct gsm_time g_time; + uint8_t chan_nr, link_id; + uint32_t fn; + int rc; struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; GsmL1_MsgUnitParam_t *msu_param; - struct lapdm_entity *le; - struct gsm_lchan *lchan; - struct gsm_time g_time; uint32_t t3p; - uint8_t *si; - struct osmo_phsap_prim pp; - int rc; + + /* in case we need to forward primitive to common part*/ + chan_nr = chan_nr_by_sapi(trx->ts[rts_ind->u8Tn].pchan, rts_ind->sapi, + rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn); + if (chan_nr) { + fn = rts_ind->u32Fn; + if (rts_ind->sapi == GsmL1_Sapi_Sacch) + link_id = 0x40; + else + link_id = 0; + rc = msgb_trim(l1p_msg, sizeof(*l1sap)); + if (rc < 0) + MSGB_ABORT(l1p_msg, "No room for primitive\n"); + l1sap = msgb_l1sap_prim(l1p_msg); + if (rts_ind->sapi == GsmL1_Sapi_TchF + || rts_ind->sapi == GsmL1_Sapi_TchH) { + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS, + PRIM_OP_INDICATION, l1p_msg); + l1sap->u.tch.chan_nr = chan_nr; + l1sap->u.tch.fn = fn; + } else { + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, + PRIM_OP_INDICATION, l1p_msg); + l1sap->u.data.link_id = link_id; + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.fn = fn; + } + + return l1sap_up(trx, l1sap); + }
gsm_fn2gsmtime(&g_time, rts_ind->u32Fn);
@@ -389,57 +661,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, g_time.t1, g_time.t2, g_time.t3, get_value_string(femtobts_l1sapi_names, rts_ind->sapi));
- /* In case of TCH downlink trasnmission, we already have a l1 - * primitive msgb pre-allocated and pre-formatted in the - * dl_tch_queue. All we need to do is to pull it off the queue - * and transmit it */ - switch (rts_ind->sapi) { - case GsmL1_Sapi_TchF: - case GsmL1_Sapi_TchH: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - if (!lchan) - break; - - if (!lchan->loopback && lchan->abis_ip.rtp_socket) { - osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); - /* FIXME: we _assume_ that we never miss TDMA - * frames and that we always get to this point - * for every to-be-transmitted voice frame. A - * better solution would be to compute - * rx_user_ts based on how many TDMA frames have - * elapsed since the last call */ - lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION; - } - /* get a msgb from the dl_tx_queue */ - resp_msg = msgb_dequeue(&lchan->dl_tch_queue); - /* if there is none, try to generate empty TCH frame - * like AMR SID_BAD */ - if (!resp_msg) { - LOGP(DL1C, LOGL_DEBUG, "%s DL TCH Tx queue underrun\n", - gsm_lchan_name(lchan)); - resp_msg = gen_empty_tch_msg(lchan); - /* if there really is none, break here and send empty */ - if (!resp_msg) - break; - } - - /* fill header */ - data_req_from_rts_ind(msgb_l1prim(resp_msg), rts_ind); - /* actually transmit it */ - goto tx; - break; - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - return pcu_tx_rts_req(&trx->ts[rts_ind->u8Tn], 0, - rts_ind->u32Fn, rts_ind->u16Arfcn, rts_ind->u8BlockNbr); - case GsmL1_Sapi_Ptcch: - return pcu_tx_rts_req(&trx->ts[rts_ind->u8Tn], 1, - rts_ind->u32Fn, rts_ind->u16Arfcn, rts_ind->u8BlockNbr); - default: - break; - } - /* in all other cases, we need to allocate a new PH-DATA.ind * primitive msgb and start to fill it */ resp_msg = l1p_msgb_alloc(); @@ -451,6 +672,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
switch (rts_ind->sapi) { case GsmL1_Sapi_Sch: + gsm_fn2gsmtime(&g_time, rts_ind->u32Fn); /* compute T3prime */ t3p = (g_time.t3 - 1) / 10; /* fill SCH burst with data */ @@ -460,87 +682,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, msu_param->u8Buffer[2] = (g_time.t1 << 7) | (g_time.t2 << 2) | (t3p >> 1); msu_param->u8Buffer[3] = (t3p & 1); break; - case GsmL1_Sapi_Bcch: - /* get them from bts->si_buf[] */ - si = bts_sysinfo_get(bts, &g_time); - if (si) - memcpy(msu_param->u8Buffer, si, GSM_MACBLOCK_LEN); - else - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - break; - case GsmL1_Sapi_Sacch: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - le = &lchan->lapdm_ch.lapdm_acch; - /* if the DSP is taking care of power control - * (ul_power_target==0), then this value will be - * overridden. */ - msu_param->u8Buffer[0] = lchan->ms_power; - rc = lapdm_phsap_dequeue_prim(le, &pp); - if (rc < 0) { - /* No SACCH data from LAPDM pending, send SACCH filling */ - uint8_t *si = lchan_sacch_get(lchan, &g_time); - if (si) { - /* The +2 is empty space where the DSP inserts the L1 hdr */ - memcpy(msu_param->u8Buffer+2, si, GSM_MACBLOCK_LEN-2); - } else - memcpy(msu_param->u8Buffer+2, fill_frame, GSM_MACBLOCK_LEN-2); - } else { - /* The +2 is empty space where the DSP inserts the L1 hdr */ - memcpy(msu_param->u8Buffer+2, pp.oph.msg->data, GSM_MACBLOCK_LEN-2); - msgb_free(pp.oph.msg); - } - break; - case GsmL1_Sapi_Sdcch: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - le = &lchan->lapdm_ch.lapdm_dcch; - rc = lapdm_phsap_dequeue_prim(le, &pp); - if (rc < 0) - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - else { - memcpy(msu_param->u8Buffer, pp.oph.msg->data, GSM_MACBLOCK_LEN); - /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ - check_for_ciph_cmd(fl1, pp.oph.msg, lchan); - msgb_free(pp.oph.msg); - } - break; - case GsmL1_Sapi_Agch: - /* special queue of messages from IMM ASS CMD */ - { - struct msgb *msg = bts_agch_dequeue(bts); - if (!msg) - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - else { - memcpy(msu_param->u8Buffer, msg->data, msg->len); - msgb_free(msg); - } - } - break; - case GsmL1_Sapi_Pch: - rc = paging_gen_msg(btsb->paging_state, msu_param->u8Buffer, &g_time); - break; - case GsmL1_Sapi_TchF: - case GsmL1_Sapi_TchH: - /* only hit in case we have a RTP underflow, as real TCH - * frames are handled way above */ - goto empty_frame; - break; - case GsmL1_Sapi_FacchF: - case GsmL1_Sapi_FacchH: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - le = &lchan->lapdm_ch.lapdm_dcch; - rc = lapdm_phsap_dequeue_prim(le, &pp); - if (rc < 0) - goto empty_frame; - else { - memcpy(msu_param->u8Buffer, pp.oph.msg->data, GSM_MACBLOCK_LEN); - /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ - check_for_ciph_cmd(fl1, pp.oph.msg, lchan); - msgb_free(pp.oph.msg); - } - break; case GsmL1_Sapi_Prach: goto empty_frame; break; @@ -548,13 +689,12 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); break; } -tx: - - tx_to_gsmtap(fl1, resp_msg);
+tx: /* transmit */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], resp_msg);
+ msgb_free(l1p_msg); return 0;
empty_frame: @@ -564,143 +704,38 @@ empty_frame: goto tx; }
-static int handle_mph_time_ind(struct femtol1_hdl *fl1, - GsmL1_MphTimeInd_t *time_ind) -{ - struct gsm_bts_trx *trx = fl1->priv; - struct gsm_bts *bts = trx->bts; - struct gsm_bts_role_bts *btsb = bts->role; - - int frames_expired = time_ind->u32Fn - fl1->gsm_time.fn; - - /* update time on PCU interface */ - pcu_tx_time_ind(time_ind->u32Fn); - - /* Update our data structures with the current GSM time */ - gsm_fn2gsmtime(&fl1->gsm_time, time_ind->u32Fn); - - /* check if the measurement period of some lchan has ended - * and pre-compute the respective measurement */ - trx_meas_check_compute(fl1->priv, time_ind->u32Fn -1); - - /* increment the primitive count for the alive timer */ - fl1->alive_prim_cnt++; - - /* increment number of RACH slots that have passed by since the - * last time indication */ - if (trx == bts->c0) { - unsigned int num_rach_per_frame; - /* 27 / 51 taken from TS 05.01 Figure 3 */ - if (bts->c0->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4) - num_rach_per_frame = 27; - else - num_rach_per_frame = 51; - - btsb->load.rach.total += frames_expired * num_rach_per_frame; - } - - return 0; -} - -/* determine LAPDm entity inside LAPDm channel for given L1 sapi */ -static struct lapdm_entity *le_by_l1_sapi(struct lapdm_channel *lc, GsmL1_Sapi_t sapi) -{ - switch (sapi) { - case GsmL1_Sapi_Sacch: - return &lc->lapdm_acch; - default: - return &lc->lapdm_dcch; - } -} - -static uint8_t gen_link_id(GsmL1_Sapi_t l1_sapi, uint8_t lapdm_sapi) -{ - uint8_t c_bits = 0; - - if (l1_sapi == GsmL1_Sapi_Sacch) - c_bits = 0x40; - - return c_bits | (lapdm_sapi & 7); -} - -static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) -{ - LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, " - "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality, - m->fBer, m->i16BurstTiming); -} - -static int process_meas_res(struct gsm_lchan *lchan, GsmL1_MeasParam_t *m) -{ - struct bts_ul_meas ulm; - - /* in the GPRS case we are not interested in measurement - * processing. The PCU will take care of it */ - if (lchan->type == GSM_LCHAN_PDTCH) - return 0; - - ulm.ta_offs_qbits = m->i16BurstTiming; - ulm.ber10k = (unsigned int) (m->fBer * 100); - ulm.inv_rssi = (uint8_t) (m->fRssi * -1); - - return lchan_new_ul_meas(lchan, &ulm); -} - -/* process radio link timeout counter S */ -static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame) -{ - struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role; - - /* if link loss criterion already reached */ - if (lchan->s == 0) { - DEBUGP(DMEAS, "%s radio link counter S already 0.\n", - gsm_lchan_name(lchan)); - return; - } - - if (bad_frame) { - /* count down radio link counter S */ - lchan->s--; - DEBUGP(DMEAS, "%s counting down radio link counter S=%d\n", - gsm_lchan_name(lchan), lchan->s); - if (lchan->s == 0) - rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL); - return; - } - - if (lchan->s < btsb->radio_link_timeout) { - /* count up radio link counter S */ - lchan->s += 2; - if (lchan->s > btsb->radio_link_timeout) - lchan->s = btsb->radio_link_timeout; - DEBUGP(DMEAS, "%s counting up radio link counter S=%d\n", - gsm_lchan_name(lchan), lchan->s); - } -} - static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; - struct osmo_phsap_prim pp; - struct gsm_lchan *lchan; - struct lapdm_entity *le; - struct msgb *msg; - int rc = 0; - - ul_to_gsmtap(fl1, l1p_msg); + struct osmo_phsap_prim *l1sap; + uint8_t chan_nr, link_id; + uint32_t fn; + uint8_t *data, len; + int rc;
- lchan = l1if_hLayer_to_lchan(fl1->priv, data_ind->hLayer2); - if (!lchan) { - LOGP(DL1C, LOGL_ERROR, "unable to resolve lchan by hLayer2\n"); - return -ENODEV; + /* chan_nr and link_id */ + chan_nr = chan_nr_by_sapi(trx->ts[data_ind->u8Tn].pchan, data_ind->sapi, + data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn); + if (!chan_nr) { + LOGP(DL1C, LOGL_ERROR, "PH-DATA-INDICATION for unknown sapi " + "%d\n", data_ind->sapi); + return ENOTSUP; } + fn = data_ind->u32Fn; + if (data_ind->sapi == GsmL1_Sapi_Sacch) + link_id = 0x40; + else + link_id = 0;
- process_meas_res(lchan, &data_ind->measParam); + /* uplink measurement */ + process_meas_res(trx, chan_nr, &data_ind->measParam);
if (data_ind->measParam.fLinkQuality < fl1->min_qual_norm - && data_ind->msgUnitParam.u8Size != 0) - return 0; + && data_ind->msgUnitParam.u8Size != 0) { + msgb_free(l1p_msg); + return 0; + }
DEBUGP(DL1C, "Rx PH-DATA.ind %s (hL2 %08x): %s", get_value_string(femtobts_l1sapi_names, data_ind->sapi), @@ -709,165 +744,85 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i data_ind->msgUnitParam.u8Size)); dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
- switch (data_ind->sapi) { - case GsmL1_Sapi_Sacch: - radio_link_timeout(lchan, (data_ind->msgUnitParam.u8Size == 0)); - if (data_ind->msgUnitParam.u8Size == 0) - break; - /* save the SACCH L1 header in the lchan struct for RSL MEAS RES */ - if (data_ind->msgUnitParam.u8Size < 2) { - LOGP(DL1C, LOGL_NOTICE, "SACCH with size %u<2 !?!\n", - data_ind->msgUnitParam.u8Size); - break; - } - /* Some brilliant engineer decided that the ordering of - * fields on the Um interface is different from the - * order of fields in RLS. See TS 04.04 (Chapter 7.2) - * vs. TS 08.58 (Chapter 9.3.10). */ - lchan->meas.l1_info[0] = data_ind->msgUnitParam.u8Buffer[0] << 3; - lchan->meas.l1_info[0] |= ((data_ind->msgUnitParam.u8Buffer[0] >> 5) & 1) << 2; - lchan->meas.l1_info[1] = data_ind->msgUnitParam.u8Buffer[1]; - lchan->meas.flags |= LC_UL_M_F_L1_VALID; - /* fall-through */ - case GsmL1_Sapi_Sdcch: - case GsmL1_Sapi_FacchF: - case GsmL1_Sapi_FacchH: - /* Check and Re-check for the SACCH */ - if (data_ind->msgUnitParam.u8Size == 0) { - LOGP(DL1C, LOGL_NOTICE, "%s %s data is null.\n", - gsm_lchan_name(lchan), - get_value_string(femtobts_l1sapi_names, data_ind->sapi)); - break; - } - - /* if this is the first valid message after enabling Rx - * decryption, we have to enable Tx encryption */ - if (lchan->ciph_state == LCHAN_CIPH_RX_CONF) { - /* HACK: check if it's an I frame, in order to - * ignore some still buffered/queued UI frames received - * before decryption was enabled */ - if (data_ind->msgUnitParam.u8Buffer[0] == 0x01 && - (data_ind->msgUnitParam.u8Buffer[1] & 0x01) == 0) { - l1if_set_ciphering(fl1, lchan, 1); - lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; - } - } - - /* SDCCH, SACCH and FACCH all go to LAPDm */ - le = le_by_l1_sapi(&lchan->lapdm_ch, data_ind->sapi); - /* allocate and fill LAPDm primitive */ - msg = msgb_alloc_headroom(128, 64, "PH-DATA.ind"); - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA, - PRIM_OP_INDICATION, msg); - - /* copy over actual MAC block */ - msg->l2h = msgb_put(msg, data_ind->msgUnitParam.u8Size); - memcpy(msg->l2h, data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size); - - /* LAPDm requires those... */ - pp.u.data.chan_nr = gsm_lchan2chan_nr(lchan); - pp.u.data.link_id = gen_link_id(data_ind->sapi, 0); - - /* feed into the LAPDm code of libosmogsm */ - rc = lapdm_phsap_up(&pp.oph, le); - break; - case GsmL1_Sapi_TchF: - case GsmL1_Sapi_TchH: - /* TCH speech frame handling */ - rc = l1if_tch_rx(lchan, l1p_msg); - break; - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - /* drop incomplete UL block */ - if (!data_ind->msgUnitParam.u8Size - || data_ind->msgUnitParam.u8Buffer[0] - != GsmL1_PdtchPlType_Full) - break; - /* PDTCH / PACCH frame handling */ - rc = pcu_tx_data_ind(&trx->ts[data_ind->u8Tn], 0, - data_ind->u32Fn, data_ind->u16Arfcn, - data_ind->u8BlockNbr, - data_ind->msgUnitParam.u8Buffer + 1, - data_ind->msgUnitParam.u8Size - 1, - (int8_t) (data_ind->measParam.fRssi)); - break; - case GsmL1_Sapi_Ptcch: - /* PTCCH frame handling */ - rc = pcu_tx_data_ind(&trx->ts[data_ind->u8Tn], 1, - data_ind->u32Fn, data_ind->u16Arfcn, - data_ind->u8BlockNbr, - data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size, - (int8_t) (data_ind->measParam.fRssi)); - break; - default: - LOGP(DL1C, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %s\n", - get_value_string(femtobts_l1sapi_names, data_ind->sapi)); - break; - } - - return rc; + /* check for TCH */ + if (data_ind->sapi == GsmL1_Sapi_TchF + || data_ind->sapi == GsmL1_Sapi_TchH) { + /* TCH speech frame handling */ + return l1if_tch_rx(trx, chan_nr, l1p_msg); + } + + /* get data pointer and length */ + data = data_ind->msgUnitParam.u8Buffer; + len = data_ind->msgUnitParam.u8Size; + /* pull lower header part before data */ + msgb_pull(l1p_msg, data - l1p_msg->data); + /* trim remaining data to it's size, to get rid of upper header part */ + rc = msgb_trim(l1p_msg, len); + if (rc < 0) + MSGB_ABORT(l1p_msg, "No room for primitive data\n"); + l1p_msg->l2h = l1p_msg->data; + /* push new l1 header */ + l1p_msg->l1h = msgb_push(l1p_msg, sizeof(*l1sap)); + /* fill header */ + l1sap = msgb_l1sap_prim(l1p_msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_INDICATION, + l1p_msg); + l1sap->u.data.link_id = link_id; + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.fn = fn; + + return l1sap_up(trx, l1sap); }
-static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind) +static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, + struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts->role; - struct osmo_phsap_prim pp; - struct lapdm_channel *lc; - uint8_t acc_delay; + struct osmo_phsap_prim *l1sap; + uint32_t fn; + uint8_t ra, acc_delay; + int rc;
/* increment number of busy RACH slots, if required */ if (trx == bts->c0 && ra_ind->measParam.fRssi >= btsb->load.rach.busy_thresh) btsb->load.rach.busy++;
- if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach) + if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach) { + msgb_free(l1p_msg); return 0; + }
- /* increment number of RACH slots with valid RACH burst */ - if (trx == bts->c0) - btsb->load.rach.access++; - - DEBUGP(DL1C, "Rx PH-RA.ind"); dump_meas_res(LOGL_DEBUG, &ra_ind->measParam);
- lc = get_lapdm_chan_by_hl2(fl1->priv, ra_ind->hLayer2); - if (!lc) { - LOGP(DL1C, LOGL_ERROR, "unable to resolve LAPD channel by hLayer2\n"); - return -ENODEV; + if (ra_ind->msgUnitParam.u8Size != 1) { + LOGP(DL1C, LOGL_ERROR, "PH-RACH-INDICATION has %d bits\n", + ra_ind->sapi); + msgb_free(l1p_msg); + return 0; }
+ fn = ra_ind->u32Fn; + ra = ra_ind->msgUnitParam.u8Buffer[0]; /* check for under/overflow / sign */ if (ra_ind->measParam.i16BurstTiming < 0) acc_delay = 0; else acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - if (acc_delay > btsb->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } - - /* check for packet access */ - if (trx == bts->c0 - && (ra_ind->msgUnitParam.u8Buffer[0] & 0xf0) == 0x70) { - LOGP(DL1C, LOGL_INFO, "RACH for packet access\n"); - return pcu_tx_rach_ind(bts, ra_ind->measParam.i16BurstTiming, - ra_ind->msgUnitParam.u8Buffer[0], ra_ind->u32Fn); - } - - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_RACH, - PRIM_OP_INDICATION, NULL); - - pp.u.rach_ind.ra = ra_ind->msgUnitParam.u8Buffer[0]; - pp.u.rach_ind.fn = ra_ind->u32Fn; - pp.u.rach_ind.acc_delay = acc_delay; - - return lapdm_phsap_up(&pp.oph, &lc->lapdm_dcch); + rc = msgb_trim(l1p_msg, sizeof(*l1sap)); + if (rc < 0) + MSGB_ABORT(l1p_msg, "No room for primitive data\n"); + l1sap = msgb_l1sap_prim(l1p_msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, + l1p_msg); + l1sap->u.rach_ind.ra = ra; + l1sap->u.rach_ind.acc_delay = acc_delay; + l1sap->u.rach_ind.fn = fn; + + return l1sap_up(trx, l1sap); }
/* handle any random indication from the L1 */ @@ -885,21 +840,19 @@ static int l1if_handle_ind(struct femtol1_hdl *fl1, struct msgb *msg) case GsmL1_PrimId_PhConnectInd: break; case GsmL1_PrimId_PhReadyToSendInd: - rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd); + return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd, msg); break; case GsmL1_PrimId_PhDataInd: - rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); + return handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); break; case GsmL1_PrimId_PhRaInd: - rc = handle_ph_ra_ind(fl1, &l1p->u.phRaInd); + return handle_ph_ra_ind(fl1, &l1p->u.phRaInd, msg); break; default: break; }
- /* Special return value '1' means: do not free */ - if (rc != 1) - msgb_free(msg); + msgb_free(msg);
return rc; } @@ -1203,46 +1156,6 @@ int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags) return osmo_wqueue_enqueue(&hdl->write_q[MQ_SYS_WRITE], msg); }
-/* send packet data request to L1 */ -int l1if_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, - uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len) -{ - struct gsm_bts_trx *trx = ts->trx; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - struct msgb *msg; - GsmL1_Prim_t *l1p; - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; - struct gsm_time g_time; - - gsm_fn2gsmtime(&g_time, fn); - - DEBUGP(DL1P, "TX packet data %02u/%02u/%02u is_ptcch=%d trx=%d ts=%d " - "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2, - g_time.t3, is_ptcch, ts->trx->nr, ts->nr, block_nr, arfcn, len); - - msg = l1p_msgb_alloc(); - l1p = msgb_l1prim(msg); - l1p->id = GsmL1_PrimId_PhDataReq; - data_req = &l1p->u.phDataReq; - data_req->hLayer1 = fl1h->hLayer1; - data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch; - data_req->subCh = GsmL1_SubCh_NA; - data_req->u8BlockNbr = block_nr; - data_req->u8Tn = ts->nr; - data_req->u32Fn = fn; - msu_param = &data_req->msgUnitParam; - msu_param->u8Size = len; - memcpy(msu_param->u8Buffer, data, len); - - tx_to_gsmtap(fl1h, msg); - - /* transmit */ - osmo_wqueue_enqueue(&fl1h->write_q[MQ_L1_WRITE], msg); - - return 0; -} - struct femtol1_hdl *l1if_open(void *priv) { struct femtol1_hdl *fl1h; @@ -1290,10 +1203,6 @@ struct femtol1_hdl *l1if_open(void *priv) return NULL; }
- fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1); - if (fl1h->gsmtap) - gsmtap_source_add_sink(fl1h->gsmtap); - return fl1h; }
@@ -1304,8 +1213,3 @@ int l1if_close(struct femtol1_hdl *fl1h) return 0; }
-/* temporary stub to make this patch compile */ -int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) -{ - return -ENOTSUP; -} diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 7947ea2..388f1fb 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -50,9 +50,6 @@ struct femtol1_hdl { char *calib_path; struct llist_head wlc_list;
- struct gsmtap_inst *gsmtap; - uint32_t gsmtap_sapi_mask; - void *priv; /* user reference */
struct osmo_timer_list alive_timer; @@ -97,7 +94,9 @@ uint32_t l1if_lchan_to_hLayer(struct gsm_lchan *lchan); struct gsm_lchan *l1if_hLayer_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer);
/* tch.c */ -int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg); +void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len); +int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg); int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan);
@@ -106,6 +105,12 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h, struct gsm_lchan *lchan, int dir_downlink);
+/* channel control */ +int l1if_rsl_chan_act(struct gsm_lchan *lchan); +int l1if_rsl_chan_rel(struct gsm_lchan *lchan); +int l1if_rsl_deact_sacch(struct gsm_lchan *lchan); +int l1if_rsl_mode_modify(struct gsm_lchan *lchan); + /* calibration loading */ int calib_load(struct femtol1_hdl *fl1h);
diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 7e7f761..465f99d 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -45,6 +45,7 @@ #include <osmo-bts/vty.h> #include <osmo-bts/bts_model.h> #include <osmo-bts/pcu_if.h> +#include <osmo-bts/l1sap.h>
#define SYSMOBTS_RF_LOCK_PATH "/var/lock/bts_rf_lock"
@@ -254,6 +255,7 @@ int main(int argc, char **argv)
bts_log_init(NULL);
+ bts = gsm_bts_alloc(tall_bts_ctx); vty_init(&bts_vty_info); bts_vty_init(bts, &bts_log_info);
@@ -271,7 +273,6 @@ int main(int argc, char **argv) } }
- bts = gsm_bts_alloc(tall_bts_ctx); if (bts_init(bts) < 0) { fprintf(stderr, "unable to to open bts\n"); exit(1); diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index aeddad7..399576e 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -35,11 +35,27 @@ #include <osmo-bts/amr.h> #include <osmo-bts/bts.h> #include <osmo-bts/bts_model.h> +#include <osmo-bts/l1sap.h>
#include "l1_if.h" #include "femtobts.h" #include "utils.h"
+static int mph_info_chan_confirm(struct gsm_lchan *lchan, + enum osmo_mph_info_type type, uint8_t cause) +{ + struct osmo_phsap_prim l1sap; + + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, PRIM_OP_CONFIRM, + NULL); + l1sap.u.info.type = type; + l1sap.u.info.u.act_cnf.chan_nr = gsm_lchan2chan_nr(lchan); + l1sap.u.info.u.act_cnf.cause = cause; + + return l1sap_up(lchan->ts->trx, &l1sap); +} + enum sapi_cmd_type { SAPI_CMD_ACTIVATE, SAPI_CMD_CONFIG_CIPHERING, @@ -858,7 +874,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) if (status != GsmL1_Status_Success) { lchan_set_state(lchan, LCHAN_S_BROKEN); sapi_clear_queue(&lchan->sapi_cmds); - rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL); + mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_EQUIPMENT_FAIL); return -1; }
@@ -869,7 +885,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) return 0;
lchan_set_state(lchan, LCHAN_S_ACTIVE); - rsl_tx_chan_act_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, 0);
/* set the initial ciphering parameters for both directions */ l1if_set_ciphering(fl1h, lchan, 0); @@ -891,7 +907,6 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir)
int lchan_activate(struct gsm_lchan *lchan, enum gsm_lchan_state lchan_state) { - struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role; struct femtol1_hdl *fl1h = trx_femtol1_hdl(lchan->ts->trx); const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; unsigned int i; @@ -920,8 +935,6 @@ int lchan_activate(struct gsm_lchan *lchan, enum gsm_lchan_state lchan_state) #warning "FIXME: Should this be in sapi_activate_cb?" lchan_init_lapdm(lchan);
- lchan->s = btsb->radio_link_timeout; - return 0; }
@@ -1177,7 +1190,7 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h, return 0; }
-int bts_model_rsl_mode_modify(struct gsm_lchan *lchan) +int l1if_rsl_mode_modify(struct gsm_lchan *lchan) { if (lchan->state != LCHAN_S_ACTIVE) return -1; @@ -1286,7 +1299,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status) gsm_lchan_name(lchan)); lchan_set_state(lchan, LCHAN_S_BROKEN); sapi_clear_queue(&lchan->sapi_cmds); - rsl_tx_rf_rel_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); return -1; }
@@ -1298,7 +1311,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status) return 0;
lchan_set_state(lchan, LCHAN_S_NONE); - rsl_tx_rf_rel_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); return 0; }
@@ -1358,7 +1371,7 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan) LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n", gsm_lchan_name(lchan)); lchan_set_state(lchan, LCHAN_S_BROKEN); - rsl_tx_rf_rel_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); }
return res; @@ -1398,13 +1411,6 @@ static int lchan_deactivate_sacch(struct gsm_lchan *lchan) return 0; }
-struct gsm_time *bts_model_get_time(struct gsm_bts *bts) -{ - struct femtol1_hdl *fl1h = trx_femtol1_hdl(bts->c0); - - return &fl1h->gsm_time; -} - /* callback from OML */ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, struct tlv_parsed *old_attr, struct tlv_parsed *new_attr, @@ -1457,17 +1463,17 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, mo->nm_state.administrative = adm_state; return oml_mo_statechg_ack(mo); } -int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) + +int l1if_rsl_chan_act(struct gsm_lchan *lchan) { //uint8_t mode = *TLVP_VAL(tp, RSL_IE_CHAN_MODE); //uint8_t type = *TLVP_VAL(tp, RSL_IE_ACT_TYPE);
- lchan->sacch_deact = 0; lchan_activate(lchan, LCHAN_S_ACT_REQ); return 0; }
-int bts_model_rsl_chan_rel(struct gsm_lchan *lchan) +int l1if_rsl_chan_rel(struct gsm_lchan *lchan) { /* A duplicate RF Release Request, ignore it */ if (lchan->state == LCHAN_S_REL_REQ) @@ -1476,7 +1482,7 @@ int bts_model_rsl_chan_rel(struct gsm_lchan *lchan) return 0; }
-int bts_model_rsl_deact_sacch(struct gsm_lchan *lchan) +int l1if_rsl_deact_sacch(struct gsm_lchan *lchan) { /* Only de-activate the SACCH if the lchan is active */ if (lchan->state != LCHAN_S_ACTIVE) diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index 61deda4..998ed80 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -83,34 +83,6 @@ DEFUN(cfg_bts_no_auto_band, cfg_bts_no_auto_band_cmd, return CMD_SUCCESS; }
-DEFUN(cfg_trx_gsmtap_sapi, cfg_trx_gsmtap_sapi_cmd, - "HIDDEN", "HIDDEN") -{ - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int sapi; - - sapi = get_string_value(femtobts_l1sapi_names, argv[0]); - - fl1h->gsmtap_sapi_mask |= (1 << sapi); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, - "HIDDEN", "HIDDEN") -{ - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int sapi; - - sapi = get_string_value(femtobts_l1sapi_names, argv[0]); - - fl1h->gsmtap_sapi_mask &= ~(1 << sapi); - - return CMD_SUCCESS; -} - DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd, "clock-calibration default", "Set the clock calibration value\n" "Default Clock DAC value\n") @@ -397,44 +369,6 @@ DEFUN(set_tx_power, set_tx_power_cmd, return CMD_SUCCESS; }
-DEFUN(loopback, loopback_cmd, - "trx <0-0> <0-7> loopback <0-1>", - TRX_STR - "Timeslot number\n" - "Set TCH loopback\n" - "Logical Channel Number\n") -{ - int trx_nr = atoi(argv[0]); - int ts_nr = atoi(argv[1]); - int lchan_nr = atoi(argv[2]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); - struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; - struct gsm_lchan *lchan = &ts->lchan[lchan_nr]; - - lchan->loopback = 1; - - return CMD_SUCCESS; -} - -DEFUN(no_loopback, no_loopback_cmd, - "no trx <0-0> <0-7> loopback <0-1>", - NO_STR TRX_STR - "Timeslot number\n" - "Set TCH loopback\n" - "Logical Channel Number\n") -{ - int trx_nr = atoi(argv[0]); - int ts_nr = atoi(argv[1]); - int lchan_nr = atoi(argv[2]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); - struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; - struct gsm_lchan *lchan = &ts->lchan[lchan_nr]; - - lchan->loopback = 0; - - return CMD_SUCCESS; -} -
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) { @@ -447,7 +381,6 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int i;
vty_out(vty, " clock-calibration %d%s", fl1h->clk_cal, VTY_NEWLINE); @@ -463,14 +396,6 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); vty_out(vty, " min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f, VTY_NEWLINE); - - for (i = 0; i < 32; i++) { - if (fl1h->gsmtap_sapi_mask & (1 << i)) { - const char *name = get_value_string(femtobts_l1sapi_names, i); - vty_out(vty, " gsmtap-sapi %s%s", osmo_str_tolower(name), - VTY_NEWLINE); - } - } }
int bts_model_vty_init(struct gsm_bts *bts) @@ -492,20 +417,6 @@ int bts_model_vty_init(struct gsm_bts *bts) NO_STR TRX_STR DSP_TRACE_F_STR, "\n", "", 0);
- cfg_trx_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - "gsmtap-sapi (", - "|",")", VTY_DO_LOWER); - cfg_trx_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - "GSMTAP SAPI\n", - "\n", "", 0); - - cfg_trx_no_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - "no gsmtap-sapi (", - "|",")", VTY_DO_LOWER); - cfg_trx_no_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - NO_STR "GSMTAP SAPI\n", - "\n", "", 0); - install_element_ve(&show_dsp_trace_f_cmd); install_element_ve(&show_sys_info_cmd); install_element_ve(&show_trx_clksrc_cmd); @@ -515,9 +426,6 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(ENABLE_NODE, &activate_lchan_cmd); install_element(ENABLE_NODE, &set_tx_power_cmd);
- install_element(ENABLE_NODE, &loopback_cmd); - install_element(ENABLE_NODE, &no_loopback_cmd); - install_element(BTS_NODE, &cfg_bts_auto_band_cmd); install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd);
@@ -525,8 +433,6 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd); install_element(TRX_NODE, &cfg_trx_clksrc_cmd); install_element(TRX_NODE, &cfg_trx_cal_path_cmd); - install_element(TRX_NODE, &cfg_trx_gsmtap_sapi_cmd); - install_element(TRX_NODE, &cfg_trx_no_gsmtap_sapi_cmd); install_element(TRX_NODE, &cfg_trx_ul_power_target_cmd); install_element(TRX_NODE, &cfg_trx_min_qual_rach_cmd); install_element(TRX_NODE, &cfg_trx_min_qual_norm_cmd); diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index c6c782f..da62c84 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -39,6 +39,7 @@ #include <osmo-bts/bts.h> #include <osmo-bts/gsm_data.h> #include <osmo-bts/measurement.h> +#include <osmo-bts/l1sap.h>
#include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -416,7 +417,7 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload,
#define RTP_MSGB_ALLOC_SIZE 512
-/*! \brief call-back function for incoming RTP +/*! \brief function for incoming RTP via TCH.req * \param rs RTP Socket * \param[in] rtp_pl buffer containing RTP payload * \param[in] rtp_pl_len length of \a rtp_pl @@ -428,14 +429,9 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, * yet, as things like the frame number, etc. are unknown at the time we * pre-fill the primtive. */ -void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len) +void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len) { - struct gsm_lchan *lchan = rs->priv; - struct msgb *msg; - GsmL1_Prim_t *l1p; - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; uint8_t *payload_type; uint8_t *l1_payload; int rc; @@ -443,22 +439,8 @@ void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), osmo_hexdump(rtp_pl, rtp_pl_len));
- /* skip processing of incoming RTP frames if we are in loopback mode */ - if (lchan->loopback) - return; - - msg = l1p_msgb_alloc(); - if (!msg) { - LOGP(DRTP, LOGL_ERROR, "%s: Failed to allocate Rx payload.\n", - gsm_lchan_name(lchan)); - return; - } - - l1p = msgb_l1prim(msg); - data_req = &l1p->u.phDataReq; - msu_param = &data_req->msgUnitParam; - payload_type = &msu_param->u8Buffer[0]; - l1_payload = &msu_param->u8Buffer[1]; + payload_type = &data[0]; + l1_payload = &data[1];
switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_V1: @@ -493,40 +475,17 @@ void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, if (rc < 0) { LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n", gsm_lchan_name(lchan)); - msgb_free(msg); return; }
- msu_param->u8Size = rc + 1; + *len = rc + 1;
DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan), - osmo_hexdump(msu_param->u8Buffer, msu_param->u8Size)); - - /* make sure the number of entries in the dl_tch_queue is never - * more than 3 */ - { - struct msgb *tmp; - int count = 0; - - llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) - count++; - - DEBUGP(DL1C, "%s DL TCH queue length = %u\n", - gsm_lchan_name(lchan), count); - - while (count >= 2) { - tmp = msgb_dequeue(&lchan->dl_tch_queue); - msgb_free(tmp); - count--; - } - } - - /* enqueue msgb to be transmitted to L1 */ - msgb_enqueue(&lchan->dl_tch_queue, msg); + osmo_hexdump(data, *len)); }
/*! \brief receive a traffic L1 primitive for a given lchan */ -int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) +int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg) { GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg); GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd; @@ -534,50 +493,15 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) uint8_t *payload = data_ind->msgUnitParam.u8Buffer + 1; uint8_t payload_len; struct msgb *rmsg = NULL; + struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
if (data_ind->msgUnitParam.u8Size < 1) { - LOGP(DL1C, LOGL_ERROR, "%s Rx Payload size 0\n", - gsm_lchan_name(lchan)); + LOGP(DL1C, LOGL_ERROR, "chan_nr %d Rx Payload size 0\n", + chan_nr); return -EINVAL; } payload_len = data_ind->msgUnitParam.u8Size - 1;
- if (lchan->loopback) { - GsmL1_Prim_t *rl1p; - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; - - struct msgb *tmp; - int count = 0; - - /* generate a new msgb from the paylaod */ - rmsg = l1p_msgb_alloc(); - if (!rmsg) - return -ENOMEM; - - rl1p = msgb_l1prim(rmsg); - data_req = &rl1p->u.phDataReq; - msu_param = &data_req->msgUnitParam; - - memcpy(msu_param->u8Buffer, - data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size); - msu_param->u8Size = data_ind->msgUnitParam.u8Size; - - /* make sure the queue doesn't get too long */ - llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) - count++; - while (count >= 1) { - tmp = msgb_dequeue(&lchan->dl_tch_queue); - msgb_free(tmp); - count--; - } - - msgb_enqueue(&lchan->dl_tch_queue, rmsg); - - return 0; - } - switch (payload_type) { case GsmL1_TchPlType_Fr: #if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE) @@ -624,13 +548,20 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) }
if (rmsg) { + struct osmo_phsap_prim *l1sap; + LOGP(DL1C, LOGL_DEBUG, "%s Rx -> RTP: %s\n", gsm_lchan_name(lchan), osmo_hexdump(rmsg->data, rmsg->len)); - /* hand rmsg to RTP code for transmission */ - if (lchan->abis_ip.rtp_socket) - osmo_rtp_send_frame(lchan->abis_ip.rtp_socket, - rmsg->data, rmsg->len, 160); - msgb_free(rmsg); + + /* add l1sap header */ + rmsg->l2h = rmsg->data; + msgb_push(rmsg, sizeof(*l1sap)); + rmsg->l1h = rmsg->data; + l1sap = msgb_l1sap_prim(rmsg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, rmsg); + l1sap->u.tch.chan_nr = chan_nr; + + return l1sap_up(trx, l1sap); }
return 0;
--- src/osmo-bts-sysmo/main.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 465f99d..6ba3b85 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -37,6 +37,8 @@ #include <osmocom/core/application.h> #include <osmocom/vty/telnet_interface.h> #include <osmocom/vty/logging.h> +#include <osmocom/core/gsmtap_util.h> +#include <osmocom/core/gsmtap.h>
#include <osmo-bts/gsm_data.h> #include <osmo-bts/logging.h> @@ -59,6 +61,7 @@ static const char *config_file = "osmo-bts.cfg"; static int daemonize = 0; static unsigned int dsp_trace = 0x71c00020; static int rt_prio = -1; +static char *gsmtap_ip = 0;
int bts_model_init(struct gsm_bts *bts) { @@ -115,6 +118,7 @@ static void print_help() " -w --hw-version Print the targeted HW Version\n" " -M --pcu-direct Force PCU to access message queue for " "PDCH dchannel directly\n" + " -i --gsmtap-ip The destination IP used for GSMTAP.\n" ); }
@@ -146,10 +150,11 @@ static void handle_options(int argc, char **argv) { "hw-version", 0, 0, 'w' }, { "pcu-direct", 0, 0, 'M' }, { "realtime", 1, 0, 'r' }, + { "gsmtap-ip", 1, 0, 'i' }, { 0, 0, 0, 0 } };
- c = getopt_long(argc, argv, "hc:d:Dc:sTVe:p:w:Mr:", + c = getopt_long(argc, argv, "hc:d:Dc:sTVe:p:w:Mr:i:", long_options, &option_idx); if (c == -1) break; @@ -194,6 +199,9 @@ static void handle_options(int argc, char **argv) case 'r': rt_prio = atoi(optarg); break; + case 'i': + gsmtap_ip = optarg; + break; default: break; } @@ -273,6 +281,15 @@ int main(int argc, char **argv) } }
+ if (gsmtap_ip) { + gsmtap = gsmtap_source_init(gsmtap_ip, GSMTAP_UDP_PORT, 1); + if (!gsmtap) { + fprintf(stderr, "Failed during gsmtap_init()\n"); + exit(1); + } + gsmtap_source_add_sink(gsmtap); + } + if (bts_init(bts) < 0) { fprintf(stderr, "unable to to open bts\n"); exit(1);
SI 5*/6 require L2 header of 0x03,0x03. All SI might be less than 23 octets, so they need to be filled with 0x2b. --- src/common/rsl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/common/rsl.c b/src/common/rsl.c index 150f686..128990d 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -314,6 +314,7 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg) if (len > sizeof(sysinfo_buf_t)) len = sizeof(sysinfo_buf_t); bts->si_valid |= (1 << osmo_si); + memset(bts->si_buf[osmo_si], 0x2b, sizeof(sysinfo_buf_t)); memcpy(bts->si_buf[osmo_si], TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), len); LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s)\n", @@ -323,6 +324,7 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg) if (len > sizeof(sysinfo_buf_t)) len = sizeof(sysinfo_buf_t); bts->si_valid |= (1 << osmo_si); + memset(bts->si_buf[osmo_si], 0x2b, sizeof(sysinfo_buf_t)); memcpy(bts->si_buf[osmo_si], TLVP_VAL(&tp, RSL_IE_L3_INFO), len); LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s)\n", @@ -437,6 +439,7 @@ static int rsl_rx_sacch_fill(struct gsm_bts_trx *trx, struct msgb *msg) bts->si_valid |= (1 << osmo_si); bts->si_buf[osmo_si][0] = 0x03; /* C/R + EA */ bts->si_buf[osmo_si][1] = 0x03; /* UI frame */ + memset(bts->si_buf[osmo_si]+2, 0x2b, sizeof(sysinfo_buf_t)-2); memcpy(bts->si_buf[osmo_si]+2, TLVP_VAL(&tp, RSL_IE_L3_INFO), len); LOGP(DRSL, LOGL_INFO, " Rx RSL SACCH FILLING (SI%s)\n", @@ -727,8 +730,9 @@ static int rsl_rx_chan_activ(struct msgb *msg) if (copy_len > sizeof(sysinfo_buf_t)-2) copy_len = sizeof(sysinfo_buf_t)-2; lchan->si.valid |= (1 << osmo_si); - lchan->si.buf[osmo_si][0] = 0x00; + lchan->si.buf[osmo_si][0] = 0x03; lchan->si.buf[osmo_si][1] = 0x03; + memset(lchan->si.buf[osmo_si]+2, 0x2b, sizeof(sysinfo_buf_t)-2); memcpy(lchan->si.buf[osmo_si]+2, cur, copy_len);
cur += si_len; @@ -1046,8 +1050,9 @@ static int rsl_rx_sacch_inf_mod(struct msgb *msg) if (len > sizeof(sysinfo_buf_t)-2) len = sizeof(sysinfo_buf_t)-2; lchan->si.valid |= (1 << osmo_si); - lchan->si.buf[osmo_si][0] = 0x00; + lchan->si.buf[osmo_si][0] = 0x03; lchan->si.buf[osmo_si][1] = 0x03; + memset(lchan->si.buf[osmo_si]+2, 0x2b, sizeof(sysinfo_buf_t)-2); memcpy(lchan->si.buf[osmo_si]+2, TLVP_VAL(&tp, RSL_IE_L3_INFO), len); LOGP(DRSL, LOGL_INFO, "%s Rx RSL SACCH FILLING (SI%s)\n",
There are three transitions:
1. LCHAN_CIPH_NONE -> LCHAN_CIPH_RX_REQ -> LCHAN_CIPH_RX_CONF
It is used to enable ciphering in RX (uplink) direction only.
2. LCHAN_CIPH_RX_CONF -> LCHAN_CIPH_RX_CONF_TX_REQ -> LCHAN_CIPH_RXTX_CONF
It is used to additionally enable ciphering in TX (downlink) direction.
3. LCHAN_CIPH_NONE -> LCHAN_CIPH_RXTX_REQ -> LCHAN_CIPH_RX_CONF_TX_REQ -> LCHAN_CIPH_RXTX_CONF
It is used to enable ciphering in both TX and RX directions. This is used when the channel is activated with encryption already enabled. (assignment or handover)
In order to follow the order of these transitions, the RX direction must always be set before the TX direction.
If no cipher key is set (A5/0), ciphering is set to ALG 0, but lchan cipher state remains at LCHAN_CIPH_NONE. --- include/osmo-bts/gsm_data.h | 5 +++-- src/common/l1sap.c | 1 - src/common/rsl.c | 1 - src/osmo-bts-sysmo/l1_if.c | 9 ++++++--- src/osmo-bts-sysmo/oml.c | 19 +++++++++++++++---- 5 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index 980f8ef..3949292 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -69,8 +69,9 @@ enum lchan_ciph_state { LCHAN_CIPH_NONE, LCHAN_CIPH_RX_REQ, LCHAN_CIPH_RX_CONF, - LCHAN_CIPH_TXRX_REQ, - LCHAN_CIPH_TXRX_CONF, + LCHAN_CIPH_RXTX_REQ, + LCHAN_CIPH_RX_CONF_TX_REQ, + LCHAN_CIPH_RXTX_CONF, };
#define bts_role_bts(x) ((struct gsm_bts_role_bts *)(x)->role) diff --git a/src/common/l1sap.c b/src/common/l1sap.c index ad833ea..b6621e0 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -94,7 +94,6 @@ static int check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan, /* only do this if we are in the right state */ switch (lchan->ciph_state) { case LCHAN_CIPH_NONE: - case LCHAN_CIPH_RX_REQ: break; default: return 0; diff --git a/src/common/rsl.c b/src/common/rsl.c index 128990d..91e5099 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -890,7 +890,6 @@ static int rsl_rx_encr_cmd(struct msgb *msg) /* push a fake RLL DATA REQ header */ rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, dch->chan_nr, link_id, 1);
- #ifdef FAKE_CIPH_MODE_COMPL if (lchan->encr.alg_id != RSL_ENC_ALG_A5(0)) { struct ciph_mod_compl *cmc; diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index f2e4440..b262b28 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -442,14 +442,17 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) u8Tn = L1SAP_CHAN2TS(chan_nr); ss = l1sap_chan2ss(chan_nr); lchan = &trx->ts[u8Tn].lchan[ss]; - if (l1sap->u.info.u.ciph_req.downlink) { + if (l1sap->u.info.u.ciph_req.uplink) { l1if_set_ciphering(fl1, lchan, 1); lchan->ciph_state = LCHAN_CIPH_RX_REQ; } - if (l1sap->u.info.u.ciph_req.uplink) { + if (l1sap->u.info.u.ciph_req.downlink) { l1if_set_ciphering(fl1, lchan, 0); - lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + lchan->ciph_state = LCHAN_CIPH_RX_CONF_TX_REQ; } + if (l1sap->u.info.u.ciph_req.downlink + && l1sap->u.info.u.ciph_req.uplink) + lchan->ciph_state = LCHAN_CIPH_RXTX_REQ; break; case PRIM_INFO_ACTIVATE: case PRIM_INFO_DEACTIVATE: diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 399576e..c16f7c5 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -888,8 +888,12 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, 0);
/* set the initial ciphering parameters for both directions */ - l1if_set_ciphering(fl1h, lchan, 0); l1if_set_ciphering(fl1h, lchan, 1); + l1if_set_ciphering(fl1h, lchan, 0); + if (lchan->encr.alg_id) + lchan->ciph_state = LCHAN_CIPH_RXTX_REQ; + else + lchan->ciph_state = LCHAN_CIPH_NONE;
return 0; } @@ -1028,9 +1032,16 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg) LOGPC(DL1C, LOGL_INFO, "RX_REQ -> RX_CONF\n"); lchan->ciph_state = LCHAN_CIPH_RX_CONF; break; - case LCHAN_CIPH_TXRX_REQ: - LOGPC(DL1C, LOGL_INFO, "TX_REQ -> TX_CONF\n"); - lchan->ciph_state = LCHAN_CIPH_TXRX_CONF; + case LCHAN_CIPH_RX_CONF_TX_REQ: + LOGPC(DL1C, LOGL_INFO, "RX_CONF_TX_REQ -> RXTX_CONF\n"); + lchan->ciph_state = LCHAN_CIPH_RXTX_CONF; + break; + case LCHAN_CIPH_RXTX_REQ: + LOGPC(DL1C, LOGL_INFO, "RXTX_REQ -> RX_CONF_TX_REQ\n"); + lchan->ciph_state = LCHAN_CIPH_RX_CONF_TX_REQ; + break; + case LCHAN_CIPH_NONE: + LOGPC(DL1C, LOGL_INFO, "\n"); break; default: LOGPC(DL1C, LOGL_INFO, "unhandled state %u\n", lchan->ciph_state);
--- src/osmo-bts-sysmo/tch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index da62c84..901c48c 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -257,7 +257,7 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le if (!msg) return NULL;
-#if 0 +#if 1 uint8_t cmr_idx = l1_payload[1];
/* CMR == Unset means CMR was not transmitted at this TDMA */