aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libabis/e1_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libabis/e1_input.c')
-rw-r--r--openbsc/src/libabis/e1_input.c689
1 files changed, 0 insertions, 689 deletions
diff --git a/openbsc/src/libabis/e1_input.c b/openbsc/src/libabis/e1_input.c
deleted file mode 100644
index eab418a24..000000000
--- a/openbsc/src/libabis/e1_input.c
+++ /dev/null
@@ -1,689 +0,0 @@
-/* OpenBSC Abis interface to E1 */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * 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 Affero 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 <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/fcntl.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <arpa/inet.h>
-#include <mISDNif.h>
-
-//#define AF_COMPATIBILITY_FUNC
-//#include <compat_af_isdn.h>
-#ifndef AF_ISDN
-#define AF_ISDN 34
-#define PF_ISDN AF_ISDN
-#endif
-
-#include <osmocom/core/select.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/rate_ctr.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/trau_mux.h>
-#include <openbsc/signal.h>
-#include <openbsc/misdn.h>
-
-#include "../../bscconfig.h"
-
-#define NUM_E1_TS 32
-
-/* list of all E1 drivers */
-LLIST_HEAD(e1inp_driver_list);
-
-/* list of all E1 lines */
-LLIST_HEAD(e1inp_line_list);
-
-static void *tall_sigl_ctx;
-
-static const struct rate_ctr_desc e1inp_ctr_d[] = {
- [E1I_CTR_HDLC_ABORT] = {
- "hdlc.abort", "HDLC abort"
- },
- [E1I_CTR_HDLC_BADFCS] = {
- "hdlc.bad_fcs", "HLDC Bad FCS"
- },
- [E1I_CTR_HDLC_OVERR] = {
- "hdlc.overrun", "HDLC Overrun"
- },
- [E1I_CTR_ALARM] = {
- "alarm", "Alarm"
- },
- [E1I_CTR_REMOVED] = {
- "removed", "Line removed"
- },
-};
-
-static const struct rate_ctr_group_desc e1inp_ctr_g_d = {
- .group_name_prefix = "e1inp",
- .group_description = "E1 Input subsystem",
- .num_ctr = ARRAY_SIZE(e1inp_ctr_d),
- .ctr_desc = e1inp_ctr_d,
-};
-
-/*
- * pcap writing of the misdn load
- * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
- */
-#define DLT_LINUX_LAPD 177
-#define PCAP_INPUT 0
-#define PCAP_OUTPUT 1
-
-struct pcap_hdr {
- uint32_t magic_number;
- uint16_t version_major;
- uint16_t version_minor;
- int32_t thiszone;
- uint32_t sigfigs;
- uint32_t snaplen;
- uint32_t network;
-} __attribute__((packed));
-
-struct pcaprec_hdr {
- uint32_t ts_sec;
- uint32_t ts_usec;
- uint32_t incl_len;
- uint32_t orig_len;
-} __attribute__((packed));
-
-struct fake_linux_lapd_header {
- uint16_t pkttype;
- uint16_t hatype;
- uint16_t halen;
- uint64_t addr;
- int16_t protocol;
-} __attribute__((packed));
-
-struct lapd_header {
- uint8_t ea1 : 1;
- uint8_t cr : 1;
- uint8_t sapi : 6;
- uint8_t ea2 : 1;
- uint8_t tei : 7;
- uint8_t control_foo; /* fake UM's ... */
-} __attribute__((packed));
-
-osmo_static_assert(offsetof(struct fake_linux_lapd_header, hatype) == 2, hatype_offset);
-osmo_static_assert(offsetof(struct fake_linux_lapd_header, halen) == 4, halen_offset);
-osmo_static_assert(offsetof(struct fake_linux_lapd_header, addr) == 6, addr_offset);
-osmo_static_assert(offsetof(struct fake_linux_lapd_header, protocol) == 14, proto_offset);
-osmo_static_assert(sizeof(struct fake_linux_lapd_header) == 16, lapd_header_size);
-
-
-static int pcap_fd = -1;
-
-void e1_set_pcap_fd(int fd)
-{
- int ret;
- struct pcap_hdr header = {
- .magic_number = 0xa1b2c3d4,
- .version_major = 2,
- .version_minor = 4,
- .thiszone = 0,
- .sigfigs = 0,
- .snaplen = 65535,
- .network = DLT_LINUX_LAPD,
- };
-
- pcap_fd = fd;
- ret = write(pcap_fd, &header, sizeof(header));
-}
-
-/* This currently only works for the D-Channel */
-static void write_pcap_packet(int direction, int sapi, int tei,
- struct msgb *msg) {
- if (pcap_fd < 0)
- return;
-
- int ret;
- time_t cur_time;
- struct tm *tm;
-
- struct fake_linux_lapd_header header = {
- .pkttype = 4,
- .hatype = 0,
- .halen = 0,
- .addr = direction == PCAP_OUTPUT ? 0x0 : 0x1,
- .protocol = ntohs(48),
- };
-
- struct lapd_header lapd_header = {
- .ea1 = 0,
- .cr = direction == PCAP_OUTPUT ? 1 : 0,
- .sapi = sapi & 0x3F,
- .ea2 = 1,
- .tei = tei & 0x7F,
- .control_foo = 0x03 /* UI */,
- };
-
- struct pcaprec_hdr payload_header = {
- .ts_sec = 0,
- .ts_usec = 0,
- .incl_len = msgb_l2len(msg) + sizeof(struct fake_linux_lapd_header)
- + sizeof(struct lapd_header),
- .orig_len = msgb_l2len(msg) + sizeof(struct fake_linux_lapd_header)
- + sizeof(struct lapd_header),
- };
-
-
- cur_time = time(NULL);
- tm = localtime(&cur_time);
- payload_header.ts_sec = mktime(tm);
-
- ret = write(pcap_fd, &payload_header, sizeof(payload_header));
- ret = write(pcap_fd, &header, sizeof(header));
- ret = write(pcap_fd, &lapd_header, sizeof(lapd_header));
- ret = write(pcap_fd, msg->l2h, msgb_l2len(msg));
-}
-
-static const char *sign_types[] = {
- [E1INP_SIGN_NONE] = "None",
- [E1INP_SIGN_OML] = "OML",
- [E1INP_SIGN_RSL] = "RSL",
-};
-const char *e1inp_signtype_name(enum e1inp_sign_type tp)
-{
- if (tp >= ARRAY_SIZE(sign_types))
- return "undefined";
- return sign_types[tp];
-}
-
-static const char *ts_types[] = {
- [E1INP_TS_TYPE_NONE] = "None",
- [E1INP_TS_TYPE_SIGN] = "Signalling",
- [E1INP_TS_TYPE_TRAU] = "TRAU",
-};
-
-const char *e1inp_tstype_name(enum e1inp_ts_type tp)
-{
- if (tp >= ARRAY_SIZE(ts_types))
- return "undefined";
- return ts_types[tp];
-}
-
-/* callback when a TRAU frame was received */
-static int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len,
- void *_priv)
-{
- struct e1inp_ts *e1i_ts = _priv;
- struct gsm_e1_subslot src_ss;
-
- src_ss.e1_nr = e1i_ts->line->num;
- src_ss.e1_ts = e1i_ts->num;
- src_ss.e1_ts_ss = ch;
-
- return trau_mux_input(&src_ss, data, len);
-}
-
-int abis_sendmsg(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = msg->dst;
- struct e1inp_driver *e1inp_driver;
- struct e1inp_ts *e1i_ts;
-
- msg->l2h = msg->data;
-
- /* don't know how to route this message. */
- if (sign_link == NULL) {
- LOGP(DLINP, LOGL_ERROR, "abis_sendmsg: msg->dst == NULL: %s\n",
- osmo_hexdump(msg->data, msg->len));
- talloc_free(msg);
- return -EINVAL;
- }
- e1i_ts = sign_link->ts;
- if (!osmo_timer_pending(&e1i_ts->sign.tx_timer)) {
- /* notify the driver we have something to write */
- e1inp_driver = sign_link->ts->line->driver;
- e1inp_driver->want_write(e1i_ts);
- }
- msgb_enqueue(&sign_link->tx_list, msg);
-
- /* dump it */
- write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg);
-
- return 0;
-}
-
-int abis_rsl_sendmsg(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
- struct e1inp_driver *e1inp_driver;
- struct e1inp_ts *e1i_ts;
-
- msg->l2h = msg->data;
-
- if (!sign_link) {
- LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->dst == NULL: %s\n",
- osmo_hexdump(msg->data, msg->len));
- talloc_free(msg);
- return -EINVAL;
- }
- e1i_ts = sign_link->ts;
- if (!osmo_timer_pending(&e1i_ts->sign.tx_timer)) {
- /* notify the driver we have something to write */
- e1inp_driver = sign_link->ts->line->driver;
- e1inp_driver->want_write(e1i_ts);
- }
- msgb_enqueue(&sign_link->tx_list, msg);
-
- /* dump it */
- write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg);
-
- return 0;
-}
-
-int _abis_nm_sendmsg(struct msgb *msg, int to_trx_oml)
-{
- struct e1inp_sign_link *sign_link = msg->dst;
-
- msg->l2h = msg->data;
-
- if (!msg->dst) {
- LOGP(DNM, LOGL_ERROR, "_abis_nm_sendmsg: msg->dst == NULL\n");
- return -EINVAL;
- }
-
- /* Check for TRX-specific OML link first */
- if (to_trx_oml) {
- if (!sign_link->trx->oml_link)
- return -ENODEV;
- msg->dst = sign_link->trx->oml_link;
- }
- return abis_sendmsg(msg);
-}
-
-/* Timeslot */
-
-/* configure and initialize one e1inp_ts */
-int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line,
- enum e1inp_ts_type type)
-{
- if (ts->type == type && ts->line && line)
- return 0;
-
- ts->type = type;
- ts->line = line;
-
- switch (type) {
- case E1INP_TS_TYPE_SIGN:
- if (line && line->driver)
- ts->sign.delay = line->driver->default_delay;
- else
- ts->sign.delay = 100000;
- INIT_LLIST_HEAD(&ts->sign.sign_links);
- break;
- case E1INP_TS_TYPE_TRAU:
- subchan_mux_init(&ts->trau.mux);
- ts->trau.demux.out_cb = subch_cb;
- ts->trau.demux.data = ts;
- subch_demux_init(&ts->trau.demux);
- break;
- default:
- LOGP(DMI, LOGL_ERROR, "unsupported E1 timeslot type %u\n",
- ts->type);
- return -EINVAL;
- }
- return 0;
-}
-
-struct e1inp_line *e1inp_line_get(uint8_t e1_nr)
-{
- struct e1inp_line *e1i_line;
-
- /* iterate over global list of e1 lines */
- llist_for_each_entry(e1i_line, &e1inp_line_list, list) {
- if (e1i_line->num == e1_nr)
- return e1i_line;
- }
- return NULL;
-}
-
-struct e1inp_line *e1inp_line_create(uint8_t e1_nr, const char *driver_name)
-{
- struct e1inp_driver *driver;
- struct e1inp_line *line;
- int i;
-
- line = e1inp_line_get(e1_nr);
- if (line) {
- LOGP(DINP, LOGL_ERROR, "E1 Line %u already exists\n",
- e1_nr);
- return NULL;
- }
-
- driver = e1inp_driver_find(driver_name);
- if (!driver) {
- LOGP(DINP, LOGL_ERROR, "No such E1 driver '%s'\n",
- driver_name);
- return NULL;
- }
-
- line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
- if (!line)
- return NULL;
-
- line->driver = driver;
- line->num = e1_nr;
-
- line->rate_ctr = rate_ctr_group_alloc(line, &e1inp_ctr_g_d, line->num);
-
- for (i = 0; i < NUM_E1_TS; i++) {
- line->ts[i].num = i+1;
- line->ts[i].line = line;
- }
- llist_add_tail(&line->list, &e1inp_line_list);
-
- return line;
-}
-
-#if 0
-struct e1inp_line *e1inp_line_get_create(uint8_t e1_nr)
-{
- struct e1inp_line *line;
- int i;
-
- line = e1inp_line_get(e1_nr);
- if (line)
- return line;
-
- line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
- if (!line)
- return NULL;
-
- line->num = e1_nr;
- for (i = 0; i < NUM_E1_TS; i++) {
- line->ts[i].num = i+1;
- line->ts[i].line = line;
- }
- llist_add_tail(&line->list, &e1inp_line_list);
-
- return line;
-}
-#endif
-
-static struct e1inp_ts *e1inp_ts_get(uint8_t e1_nr, uint8_t ts_nr)
-{
- struct e1inp_line *e1i_line;
-
- e1i_line = e1inp_line_get(e1_nr);
- if (!e1i_line)
- return NULL;
-
- return &e1i_line->ts[ts_nr-1];
-}
-
-struct subch_mux *e1inp_get_mux(uint8_t e1_nr, uint8_t ts_nr)
-{
- struct e1inp_ts *e1i_ts = e1inp_ts_get(e1_nr, ts_nr);
-
- if (!e1i_ts)
- return NULL;
-
- return &e1i_ts->trau.mux;
-}
-
-/* Signalling Link */
-
-struct e1inp_sign_link *e1inp_lookup_sign_link(struct e1inp_ts *e1i,
- uint8_t tei, uint8_t sapi)
-{
- struct e1inp_sign_link *link;
-
- llist_for_each_entry(link, &e1i->sign.sign_links, list) {
- if (link->sapi == sapi && link->tei == tei)
- return link;
- }
-
- return NULL;
-}
-
-/* create a new signalling link in a E1 timeslot */
-
-struct e1inp_sign_link *
-e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
- struct gsm_bts_trx *trx, uint8_t tei,
- uint8_t sapi)
-{
- struct e1inp_sign_link *link;
-
- if (ts->type != E1INP_TS_TYPE_SIGN)
- return NULL;
-
- link = talloc_zero(tall_sigl_ctx, struct e1inp_sign_link);
- if (!link)
- return NULL;
-
- link->ts = ts;
- link->type = type;
- INIT_LLIST_HEAD(&link->tx_list);
- link->trx = trx;
- link->tei = tei;
- link->sapi = sapi;
-
- llist_add_tail(&link->list, &ts->sign.sign_links);
-
- return link;
-}
-
-void e1inp_sign_link_destroy(struct e1inp_sign_link *link)
-{
- struct msgb *msg;
-
- llist_del(&link->list);
- while (!llist_empty(&link->tx_list)) {
- msg = msgb_dequeue(&link->tx_list);
- msgb_free(msg);
- }
-
- if (link->ts->type == E1INP_TS_TYPE_SIGN)
- osmo_timer_del(&link->ts->sign.tx_timer);
-
- talloc_free(link);
-}
-
-/* the E1 driver tells us he has received something on a TS */
-int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
- uint8_t tei, uint8_t sapi)
-{
- struct e1inp_sign_link *link;
- struct gsm_bts *bts;
- int ret;
-
- switch (ts->type) {
- case E1INP_TS_TYPE_SIGN:
- /* consult the list of signalling links */
- write_pcap_packet(PCAP_INPUT, sapi, tei, msg);
- link = e1inp_lookup_sign_link(ts, tei, sapi);
- if (!link) {
- LOGP(DMI, LOGL_ERROR, "didn't find signalling link for "
- "tei %d, sapi %d\n", tei, sapi);
- return -EINVAL;
- }
-
- log_set_context(BSC_CTX_BTS, link->trx->bts);
- switch (link->type) {
- case E1INP_SIGN_OML:
- msg->dst = link;
- bts = link->trx->bts;
- ret = bts->model->oml_rcvmsg(msg);
- break;
- case E1INP_SIGN_RSL:
- msg->dst = link;
- ret = abis_rsl_rcvmsg(msg);
- break;
- default:
- ret = -EINVAL;
- LOGP(DMI, LOGL_ERROR, "unknown link type %u\n", link->type);
- break;
- }
- break;
- case E1INP_TS_TYPE_TRAU:
- ret = subch_demux_in(&ts->trau.demux, msg->l2h, msgb_l2len(msg));
- break;
- default:
- ret = -EINVAL;
- LOGP(DMI, LOGL_ERROR, "unknown TS type %u\n", ts->type);
- break;
- }
-
- return ret;
-}
-
-#define TSX_ALLOC_SIZE 4096
-
-/* called by driver if it wants to transmit on a given TS */
-struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
- struct e1inp_sign_link **sign_link)
-{
- struct e1inp_sign_link *link;
- struct msgb *msg = NULL;
- int len;
-
- switch (e1i_ts->type) {
- case E1INP_TS_TYPE_SIGN:
- /* FIXME: implement this round robin */
- llist_for_each_entry(link, &e1i_ts->sign.sign_links, list) {
- msg = msgb_dequeue(&link->tx_list);
- if (msg) {
- if (sign_link)
- *sign_link = link;
- break;
- }
- }
- break;
- case E1INP_TS_TYPE_TRAU:
- msg = msgb_alloc(TSX_ALLOC_SIZE, "TRAU_TX");
- if (!msg)
- return NULL;
- len = subchan_mux_out(&e1i_ts->trau.mux, msg->data, 40);
- msgb_put(msg, 40);
- break;
- default:
- LOGP(DMI, LOGL_ERROR, "unsupported E1 TS type %u\n", e1i_ts->type);
- return NULL;
- }
- return msg;
-}
-
-/* called by driver in case some kind of link state event */
-int e1inp_event(struct e1inp_ts *ts, int evt, uint8_t tei, uint8_t sapi)
-{
- struct e1inp_sign_link *link;
- struct input_signal_data isd;
-
- link = e1inp_lookup_sign_link(ts, tei, sapi);
- if (!link)
- return -EINVAL;
-
- isd.line = ts->line;
- isd.link_type = link->type;
- isd.trx = link->trx;
- isd.tei = tei;
- isd.sapi = sapi;
-
- /* report further upwards */
- osmo_signal_dispatch(SS_INPUT, evt, &isd);
- return 0;
-}
-
-/* register a driver with the E1 core */
-int e1inp_driver_register(struct e1inp_driver *drv)
-{
- llist_add_tail(&drv->list, &e1inp_driver_list);
- return 0;
-}
-
-struct e1inp_driver *e1inp_driver_find(const char *name)
-{
- struct e1inp_driver *drv;
-
- llist_for_each_entry(drv, &e1inp_driver_list, list) {
- if (!strcasecmp(name, drv->name))
- return drv;
- }
- return NULL;
-}
-
-int e1inp_line_update(struct e1inp_line *line)
-{
- struct input_signal_data isd;
- int rc;
-
- if (line->driver && line->driver->line_update)
- rc = line->driver->line_update(line);
- else
- rc = 0;
-
- /* Send a signal to anyone who is interested in new lines being
- * configured */
- memset(&isd, 0, sizeof(isd));
- isd.line = line;
- osmo_signal_dispatch(SS_INPUT, S_INP_LINE_INIT, &isd);
-
- return rc;
-}
-
-static int e1i_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- if (subsys != SS_GLOBAL ||
- signal != S_GLOBAL_SHUTDOWN)
- return 0;
-
- if (pcap_fd) {
- close(pcap_fd);
- pcap_fd = -1;
- }
-
- return 0;
-}
-
-void e1inp_misdn_init(void);
-void e1inp_dahdi_init(void);
-void e1inp_ipaccess_init(void);
-void e1inp_hsl_init(void);
-
-void e1inp_init(void)
-{
- tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1,
- "e1inp_sign_link");
- osmo_signal_register_handler(SS_GLOBAL, e1i_sig_cb, NULL);
-
- e1inp_misdn_init();
-#ifdef HAVE_DAHDI_USER_H
- e1inp_dahdi_init();
-#endif
- e1inp_ipaccess_init();
- e1inp_hsl_init();
-}