aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/e1_input.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-03-03 23:29:05 +0100
committerHarald Welte <laforge@gnumonks.org>2011-03-03 23:29:05 +0100
commit31c00f7d6fa63937f2c973157d196a427f6eef95 (patch)
tree6b7c81d92b6a8b83d0588b2b59d47fd0cca7a052 /openbsc/src/e1_input.c
parent9349d7ff7c5866110a1f2421ccc68a487e4030be (diff)
re-structure the OpenBSC directory layout
The new structure divides the code into a number of libraries for the BSC core functionality, MSC core functionality, Abis transport, TRAU and other bits. This doesn't introduce any functional code change but simply moves around files and alters Makefile.am accordingly. Next step would be to disentangle a lot of the inter-library dependencies and make the individual bits of code more independent.
Diffstat (limited to 'openbsc/src/e1_input.c')
-rw-r--r--openbsc/src/e1_input.c649
1 files changed, 0 insertions, 649 deletions
diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c
deleted file mode 100644
index e5dd11b94..000000000
--- a/openbsc/src/e1_input.c
+++ /dev/null
@@ -1,649 +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/types.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 <osmocore/select.h>
-#include <osmocore/msgb.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 <osmocore/linuxlist.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/trau_mux.h>
-#include <osmocore/talloc.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;
-
-/*
- * 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 {
- u_int32_t magic_number;
- u_int16_t version_major;
- u_int16_t version_minor;
- int32_t thiszone;
- u_int32_t sigfigs;
- u_int32_t snaplen;
- u_int32_t network;
-} __attribute__((packed));
-
-struct pcaprec_hdr {
- u_int32_t ts_sec;
- u_int32_t ts_usec;
- u_int32_t incl_len;
- u_int32_t orig_len;
-} __attribute__((packed));
-
-struct fake_linux_lapd_header {
- u_int16_t pkttype;
- u_int16_t hatype;
- u_int16_t halen;
- u_int64_t addr;
- int16_t protocol;
-} __attribute__((packed));
-
-struct lapd_header {
- u_int8_t ea1 : 1;
- u_int8_t cr : 1;
- u_int8_t sapi : 6;
- u_int8_t ea2 : 1;
- u_int8_t tei : 7;
- u_int8_t control_foo; /* fake UM's ... */
-} __attribute__((packed));
-
-static_assert(offsetof(struct fake_linux_lapd_header, hatype) == 2, hatype_offset);
-static_assert(offsetof(struct fake_linux_lapd_header, halen) == 4, halen_offset);
-static_assert(offsetof(struct fake_linux_lapd_header, addr) == 6, addr_offset);
-static_assert(offsetof(struct fake_linux_lapd_header, protocol) == 14, proto_offset);
-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, u_int8_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_rsl_sendmsg(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link;
- struct e1inp_driver *e1inp_driver;
- struct e1inp_ts *e1i_ts;
-
- msg->l2h = msg->data;
-
- if (!msg->trx) {
- LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL: %s\n",
- hexdump(msg->data, msg->len));
- talloc_free(msg);
- return -EINVAL;
- } else if (!msg->trx->rsl_link) {
- LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx->rsl_link == NULL: %s\n",
- hexdump(msg->data, msg->len));
- talloc_free(msg);
- return -EIO;
- }
-
- sign_link = msg->trx->rsl_link;
- e1i_ts = sign_link->ts;
- if (!bsc_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;
- struct e1inp_driver *e1inp_driver;
- struct e1inp_ts *e1i_ts;
-
- msg->l2h = msg->data;
-
- if (!msg->trx || !msg->trx->bts || !msg->trx->bts->oml_link) {
- LOGP(DNM, LOGL_ERROR, "nm_sendmsg: msg->trx == NULL\n");
- return -EINVAL;
- }
-
- /* Check for TRX-specific OML link first */
- if (to_trx_oml) {
- if (!msg->trx->oml_link)
- return -ENODEV;
- sign_link = msg->trx->oml_link;
- } else
- sign_link = msg->trx->bts->oml_link;
-
- e1i_ts = sign_link->ts;
- if (!bsc_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;
-}
-
-/* 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(u_int8_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(u_int8_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;
- 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(u_int8_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(u_int8_t e1_nr, u_int8_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(u_int8_t e1_nr, u_int8_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,
- u_int8_t tei, u_int8_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, u_int8_t tei,
- u_int8_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)
- bsc_del_timer(&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,
- u_int8_t tei, u_int8_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->trx = link->trx;
- bts = msg->trx->bts;
- ret = bts->model->oml_rcvmsg(msg);
- break;
- case E1INP_SIGN_RSL:
- msg->trx = link->trx;
- 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, u_int8_t tei, u_int8_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.link_type = link->type;
- isd.trx = link->trx;
- isd.tei = tei;
- isd.sapi = sapi;
-
- /* report further upwards */
- dispatch_signal(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;
- dispatch_signal(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_init(void)
-{
- tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1,
- "e1inp_sign_link");
- register_signal_handler(SS_GLOBAL, e1i_sig_cb, NULL);
-
- e1inp_misdn_init();
-#ifdef HAVE_DAHDI_USER_H
- e1inp_dahdi_init();
-#endif
-}