From 5fd8a545c806cec8af4fecd2a812cfebebee45e1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Feb 2009 02:43:36 +0000 Subject: preliminary ip.access BTS support, as of now only OML singalling works --- include/openbsc/e1_input.h | 5 + src/Makefile.am | 2 +- src/e1_config.c | 29 ++++ src/input/ipaccess.c | 370 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 src/input/ipaccess.c diff --git a/include/openbsc/e1_input.h b/include/openbsc/e1_input.h index 29c29d081..68b8d634a 100644 --- a/include/openbsc/e1_input.h +++ b/include/openbsc/e1_input.h @@ -75,6 +75,11 @@ struct e1inp_ts { /* mISDN driver has one fd for each ts */ struct bsc_fd fd; } misdn; + struct { + /* ip.access driver has one fd for each ts */ + struct bsc_fd fd; + } ipaccess; + } driver; }; diff --git a/src/Makefile.am b/src/Makefile.am index ae5715cb1..6664a1c85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ bsc_hack_SOURCES = bsc_hack.c abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c \ gsm_subscriber.c msgb.c select.c chan_alloc.c timer.c debug.c db.c \ gsm_04_11.c telnet_interface.c telnet_parser.l subchan_demux.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \ - input/misdn.c + input/misdn.c input/ipaccess.c bsc_hack_LDADD = -ldl -ldbi bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c select.c timer.c rs232.c diff --git a/src/e1_config.c b/src/e1_config.c index 250d6c2a1..9863c9e47 100644 --- a/src/e1_config.c +++ b/src/e1_config.c @@ -66,3 +66,32 @@ int e1_config(struct gsm_bts *bts) return mi_setup(0, line, NULL); } + +/* do some compiled-in configuration for our BTS/E1 setup */ +int ia_config(struct gsm_bts *bts) +{ + struct e1inp_line *line; + struct e1inp_ts *sign_ts; + struct e1inp_sign_link *oml_link, *rsl_link; + + line = malloc(sizeof(*line)); + if (!line) + return -ENOMEM; + memset(line, 0, sizeof(*line)); + + /* create E1 timeslots for signalling and TRAU frames */ + e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN); + + /* create signalling links for TS1 */ + sign_ts = &line->ts[1-1]; + oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, + bts->c0, 0, 0xff); + rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, + bts->c0, 0, 0); + + /* create back-links from bts/trx */ + bts->oml_link = oml_link; + bts->c0->rsl_link = rsl_link; + + return ipaccess_setup(line); +} diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c new file mode 100644 index 000000000..f2964d88b --- /dev/null +++ b/src/input/ipaccess.c @@ -0,0 +1,370 @@ +/* OpenBSC Abis input driver for ip.access */ + +/* (C) 2009 by Harald Welte + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* data structure for one E1 interface with A-bis */ +struct ia_e1_handle { + struct bsc_fd listen_fd; +}; + +#define TS1_ALLOC_SIZE 300 + +struct ipaccess_head { + u_int8_t zero; + u_int8_t len; + u_int8_t proto; + u_int8_t data[0]; +} __attribute__ ((packed)); + +enum ipaccess_proto { + PROTO_RSL = 0x00, + PROTO_IPACCESS = 0xfe, + PROTO_OML = 0xff, +}; + +enum ipaccess_msg_type { + MSGT_PING = 0x00, + MSGT_PONG = 0x01, + MSGT_IDENTITY_GET = 0x04, + MSGT_IDENTITY_RESP = 0x05, + MSGT_IDENTITY_ACK = 0x06, +}; + +static const u_int8_t pong[] = { 0, 1, PROTO_IPACCESS, MSGT_PONG }; +static const u_int8_t id_ack[] = { 0, 1, PROTO_IPACCESS, MSGT_IDENTITY_ACK }; + +static int ipaccess_rcvmsg(struct msgb *msg, int fd) +{ + u_int8_t msg_type = *(msg->l2h); + + printf("msg_type=0x%02x\n", msg_type); + switch (msg_type) { + case MSGT_PING: + DEBUGP(DMI, "PING?\n"); + write(fd, pong, sizeof(pong)); + break; + case MSGT_PONG: + DEBUGP(DMI, "PONG!\n"); + break; + case MSGT_IDENTITY_RESP: + DEBUGP(DMI, "ID_RESP\n"); + break; + case MSGT_IDENTITY_ACK: + DEBUGP(DMI, "ID_ACK\n"); + write(fd, id_ack, sizeof(id_ack)); + break; + } + + msgb_free(msg); + return 0; +} + +static int handle_ts1_read(struct bsc_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct e1inp_sign_link *link; + struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE); + struct ipaccess_head *hh; + int ret; + + if (!msg) + return -ENOMEM; + + /* first read our 3-byte header */ + hh = (struct ipaccess_head *) msg->data; + ret = recv(bfd->fd, msg->data, 3, 0); + if (ret < 0) { + fprintf(stderr, "recv error %s\n", strerror(errno)); + return ret; + } + if (ret == 0) { + fprintf(stderr, "BTS disappeared, dead socket\n"); + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + } + msgb_put(msg, ret); + + /* then read te length as specified in header */ + msg->l2h = msg->data + sizeof(*hh); + ret = recv(bfd->fd, msg->l2h, hh->len, 0); + if (ret < hh->len) { + fprintf(stderr, "short read!\n"); + //msgb_free(msg); + //return -EIO; + } + msgb_put(msg, ret); + DEBUGP(DMI, "<= ret=%d, len=%d, proto=0x%02x\n", ret, hh->len, hh->proto); + + if (hh->proto == PROTO_IPACCESS) + return ipaccess_rcvmsg(msg, bfd->fd); + + if (debug_mask & DMI) { + fprintf(stdout, "RX: "); + hexdump(msgb_l2(msg), ret); + } + + link = e1inp_lookup_sign_link(e1i_ts, 0, hh->proto); + if (!link) { + printf("no matching signalling link for hh->proto=0x%02x\n", hh->proto); + msgb_free(msg); + return -EIO; + } + msg->trx = link->trx; + + switch (hh->proto) { + case PROTO_RSL: + ret = abis_rsl_rcvmsg(msg); + break; + case PROTO_OML: + ret = abis_nm_rcvmsg(msg); + break; + default: + msgb_free(msg); + break; + } + return ret; +} + +static int handle_ts1_write(struct bsc_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct e1inp_sign_link *sign_link; + struct msgb *msg; + struct ipaccess_head *hh; + u_int8_t *l2_data; + int ret; + + /* get the next msg for this timeslot */ + msg = e1inp_tx_ts(e1i_ts, &sign_link); + if (!msg) { + bfd->when &= ~BSC_FD_WRITE; + return 0; + } + + l2_data = msg->data; + + /* prepend the mISDNhead */ + hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh)); + hh->zero = 0; + hh->len = msg->len - sizeof(*hh); + + switch (sign_link->type) { + case E1INP_SIGN_OML: + hh->proto = PROTO_OML; + break; + case E1INP_SIGN_RSL: + hh->proto = PROTO_RSL; + break; + default: + msgb_free(msg); + return -EINVAL; + } + + if (debug_mask & DMI) { + fprintf(stdout, "TX proto=0x%x: ", hh->proto); + hexdump(l2_data, hh->len); + } + + ret = send(bfd->fd, msg->data, msg->len, 0); + msgb_free(msg); + + return ret; +} + + +/* callback from select.c in case one of the fd's can be read/written */ +static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + unsigned int idx = ts_nr-1; + struct e1inp_ts *e1i_ts = &line->ts[idx]; + int rc = 0; + + switch (e1i_ts->type) { + case E1INP_TS_TYPE_SIGN: + if (what & BSC_FD_READ) + rc = handle_ts1_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_ts1_write(bfd); + break; +#if 0 + case E1INP_TS_TYPE_TRAU: + if (what & BSC_FD_READ) + rc = handle_tsX_read(bfd); + /* We never include the mISDN B-Channel FD into the + * writeset, since it doesn't support poll() based + * write flow control */ + break; +#endif + default: + fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type); + break; + } + + return rc; +} + + +static int ts_want_write(struct e1inp_ts *e1i_ts) +{ + /* We never include the mISDN B-Channel FD into the + * writeset, since it doesn't support poll() based + * write flow control */ + if (e1i_ts->type == E1INP_TS_TYPE_TRAU) + return 0; + + e1i_ts->driver.ipaccess.fd.when |= BSC_FD_WRITE; + + return 0; +} + +struct e1inp_driver ipaccess_driver = { + .name = "ip.access", + .want_write = ts_want_write, +}; + +static int ia_e1_setup(struct e1inp_line *line) +{ + return 0; +} + +static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) +{ + struct e1inp_line *line = listen_bfd->data; + int ret; + + if (what & BSC_FD_READ) { + int idx = 0; + struct e1inp_ts *e1i_ts = &line->ts[idx]; + struct bsc_fd *bfd = &e1i_ts->driver.ipaccess.fd; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + if (bfd->fd) { + printf("dumping old fd\n"); + if (bfd->fd != -1) { + bsc_unregister_fd(bfd); + close(bfd->fd); + } + } + bfd->fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len); + if (bfd->fd < 0) { + perror("accept"); + return bfd->fd; + } + printf("accept()ed new RSL/OML fd\n"); + bfd->data = line; + bfd->priv_nr = 1; + bfd->cb = ipaccess_fd_cb; + bfd->when = BSC_FD_READ; + ret = bsc_register_fd(bfd); + if (ret < 0) { + fprintf(stderr, "could not register FD\n"); + return ret; + } + } + return 0; +} + +int ipaccess_setup(struct e1inp_line *line) +{ + struct sockaddr_in addr; + struct ia_e1_handle *e1h; + int sk, ret, on = 1; + + /* register the driver with the core */ + /* FIXME: do this in the plugin initializer function */ + ret = e1inp_driver_register(&ipaccess_driver); + if (ret) + return ret; + + /* create the actual line instance */ + /* FIXME: do this independent of driver registration */ + e1h = malloc(sizeof(*e1h)); + memset(e1h, 0, sizeof(*e1h)); + + line->driver = &ipaccess_driver; + line->driver_data = e1h; + + e1h->listen_fd.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + e1h->listen_fd.cb = listen_fd_cb; + e1h->listen_fd.when = BSC_FD_READ; + e1h->listen_fd.data = line; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(3002); + addr.sin_addr.s_addr = INADDR_ANY; + + setsockopt(e1h->listen_fd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = bind(e1h->listen_fd.fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + fprintf(stderr, "could not bind l2 socket %s\n", + strerror(errno)); + return -EIO; + } + + ret = listen(e1h->listen_fd.fd, 1); + if (ret < 0) { + perror("listen"); + return ret; + } + + ret = bsc_register_fd(&e1h->listen_fd); + if (ret < 0) { + perror("register_listen_fd"); + return ret; + } + + ret = ia_e1_setup(line); + if (ret) + return ret; + + return e1inp_line_register(line); +} -- cgit v1.2.3