From 9f75c35eb3cf796366b7452538a1d3113cd6b546 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 20:26:32 +0200 Subject: GPRS: Introduce a GPRS Gb Proxy The ida of the Gb proxy is to aggregate Gb links with a number of BSS and then present all the BSSGP-VC's together inside one NS-VC to the actual SGSN. The code is not yet expected to be complete. --- openbsc/src/Makefile.am | 9 +- openbsc/src/gb_proxy.c | 315 +++++++++++++++++++++++++++++++++++++++++++ openbsc/src/gb_proxy_main.c | 140 +++++++++++++++++++ openbsc/src/gprs_bssgp.c | 7 +- openbsc/src/gprs_ns.c | 47 +++---- openbsc/src/input/ipaccess.c | 52 ------- openbsc/src/socket.c | 94 +++++++++++++ 7 files changed, 579 insertions(+), 85 deletions(-) create mode 100644 openbsc/src/gb_proxy.c create mode 100644 openbsc/src/gb_proxy_main.c create mode 100644 openbsc/src/socket.c (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 718252f77..ac418707a 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -3,7 +3,7 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess-proxy + isdnsync bsc_mgcp ipaccess-proxy osmo-gb_proxy noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libsgsn.a noinst_HEADERS = vty/cardshell.h @@ -11,7 +11,7 @@ bscdir = $(libdir) bsc_LIBRARIES = libsccp.a libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ - chan_alloc.c debug.c \ + chan_alloc.c debug.c socket.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \ input/misdn.c input/ipaccess.c \ @@ -50,3 +50,8 @@ bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgc bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c + +osmo_gb_proxy_SOURCES = gb_proxy.c gb_proxy_main.c \ + gprs_ns.c \ + socket.c debug.c telnet_interface.c vty_interface_cmds.c +osmo_gb_proxy_LDADD = libvty.a diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c new file mode 100644 index 000000000..77cc8caf9 --- /dev/null +++ b/openbsc/src/gb_proxy.c @@ -0,0 +1,315 @@ +/* NS-over-IP proxy */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 + +struct gbprox_peer { + struct llist_head list; + + /* NS-VC over which we send/receive data to this BVC */ + struct gprs_nsvc *nsvc; + + /* BVCI used for Point-to-Point to this peer */ + uint16_t bvci; + + /* Routeing Area that this peer is part of (raw 04.08 encoding) */ + uint8_t ra[6]; +}; + +/* Linked list of all Gb peers (except SGSN) */ +static LLIST_HEAD(gbprox_bts_peers); + +/* Pointer to the SGSN peer */ +struct gbprox_peer *gbprox_peer_sgsn; + +/* The NS protocol stack instance we're using */ +extern struct gprs_ns_inst *gbprox_nsi; + +/* Find the gbprox_peer by its BVCI */ +static struct gbprox_peer *peer_by_bvci(uint16_t bvci) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (peer->bvci == bvci) + return peer; + } + return NULL; +} + +static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (peer->nsvc == nsvc) + return peer; + } + return NULL; +} + +/* look-up a peer by its Routeing Area Code (RAC) */ +static struct gbprox_peer *peer_by_rac(uint8_t *ra) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (!memcmp(&peer->ra, ra, 6)) + return peer; + } + return NULL; +} + +/* look-up a peer by its Location Area Code (LAC) */ +static struct gbprox_peer *peer_by_lac(uint8_t *la) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (!memcmp(&peer->ra, la, 5)) + return peer; + } + return NULL; +} + +static struct gbprox_peer *peer_alloc(uint16_t bvci) +{ + struct gbprox_peer *peer; + + peer = talloc_zero(tall_bsc_ctx, struct gbprox_peer); + if (!peer) + return NULL; + + peer->bvci = bvci; + llist_add(&peer->list, &gbprox_bts_peers); + + return peer; +} + +static void peer_free(struct gbprox_peer *peer) +{ + llist_del(&peer->list); + talloc_free(peer); +} + +/* feed a message down the NS-VC associated with the specified peer */ +static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer, + uint16_t ns_bvci) +{ + msgb_bvci(msg) = ns_bvci; + msgb_nsei(msg) = peer->nsvc->nsei; + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + +/* Send a message to a peer identified by ptp_bvci but using ns_bvci + * in the NS hdr */ +static int gbprox_tx2bvci(struct msgb *msg, uint16_t ptp_bvci, + uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + peer = peer_by_bvci(ptp_bvci); + if (!peer) + return -ENOENT; + + return gbprox_tx2peer(msg, peer, ns_bvci); +} + +/* Receive an incoming signalling message from a BSS-side NS-VC */ +static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, + uint16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct gbprox_peer *from_peer; + + if (ns_bvci != 0) { + LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci); + return -EINVAL; + } + + /* we actually should never see those two for BVCI == 0, but double-check + * just to make sure */ + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n"); + return -EINVAL; + } + + bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_SUSPEND: + case BSSGP_PDUT_RESUME: + /* RAC snooping for SUSPEND/RESUME */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + goto err_mand_ie; + from_peer = peer_by_nsvc(nsvc); + if (!from_peer) + goto err_no_peer; + memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), + sizeof(&from_peer->ra)); + /* FIXME: This only supports one BSS per RA */ + break; + } + + /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ + return gbprox_tx2peer(msg, gbprox_peer_sgsn, ns_bvci); +err_no_peer: +err_mand_ie: + /* FIXME: do something */ + ; +} + +/* Receive paging request from SGSN, we need to relay to proper BSS */ +static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, + struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + return gbprox_tx2bvci(msg, bvci, ns_bvci); + } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { + peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); + return gbprox_tx2peer(msg, peer, ns_bvci); + } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { + peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); + return gbprox_tx2peer(msg, peer, ns_bvci); + } else + return -EINVAL; +} + +/* Receive an incoming signalling message from the SGSN-side NS-VC */ +static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, + uint16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct gbprox_peer *peer; + uint16_t bvci; + int rc = 0; + + if (ns_bvci != 0) { + LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci); + return -EINVAL; + } + + /* we actually should never see those two for BVCI == 0, but double-check + * just to make sure */ + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n"); + return -EINVAL; + } + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_FLUSH_LL: + case BSSGP_PDUT_BVC_BLOCK_ACK: + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + case BSSGP_PDUT_BVC_RESET: + case BSSGP_PDUT_BVC_RESET_ACK: + /* simple case: BVCI IE is mandatory */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + rc = gbprox_tx2bvci(msg, bvci, ns_bvci); + break; + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: + /* process the paging request (LAC/RAC lookup) */ + rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* FIXME: Some exception has occurred */ + LOGP(DGPRS, LOGL_NOTICE, "STATUS not implemented yet\n"); + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_SUSPEND_ACK: + case BSSGP_PDUT_SUSPEND_NACK: + case BSSGP_PDUT_RESUME_ACK: + case BSSGP_PDUT_RESUME_NACK: + /* RAC IE is mandatory */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + goto err_mand_ie; + peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); + if (!peer) + goto err_no_peer; + rc = gbprox_tx2peer(msg, peer, ns_bvci); + break; + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + LOGP(DGPRS, LOGL_ERROR, "SGSN INVOKE TRACE not supported\n"); + break; + default: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + break; + } + + return rc; +err_mand_ie: + ; /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ + //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); +err_no_peer: + ; /* FIXME */ +} + +/* Main input function for Gb proxy */ +int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + /* Only BVCI=0 messages need special treatment */ + if (ns_bvci == 0 || ns_bvci == 1) { + if (nsvc->remote_end_is_sgsn) + return gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci); + else + return gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); + } + + /* All other BVCI are PTP and thus can be simply forwarded */ + peer = peer_by_bvci(ns_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for BVCI %u\n", ns_bvci); + return -EIO; + } + + return gbprox_tx2peer(msg, peer, ns_bvci); +} diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c new file mode 100644 index 000000000..c624cf8a4 --- /dev/null +++ b/openbsc/src/gb_proxy_main.c @@ -0,0 +1,140 @@ +/* NS-over-IP proxy */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 + +#include "../bscconfig.h" + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } + +#define _GNU_SOURCE +#include + +void *tall_bsc_ctx; + +struct gprs_ns_inst *gbprox_nsi; +static u_int16_t nsip_listen_port; + +const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2010 Harald Welte and On-Waves\n" + "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" + "License GPLv2+: GNU GPL version 2 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; + +static char *config_file = "nsip_proxy.cfg"; + +/* Pointer to the SGSN peer */ +extern struct gbprox_peer *gbprox_peer_sgsn; + +/* call-back function for the NS protocol */ +static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci) +{ + int rc = 0; + + switch (event) { + case GPRS_NS_EVT_UNIT_DATA: + rc = gbprox_rcvmsg(msg, nsvc, bvci); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); + if (msg) + talloc_free(msg); + rc = -EIO; + break; + } + return rc; +} + + +int main(int argc, char **argv) +{ + struct gsm_network dummy_network; + struct log_target *stderr_target; + struct sockaddr_in sin; + int rc; + + tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy"); + + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + + telnet_init(&dummy_network, 4244); + + gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); + if (!gbprox_nsi) { + LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); + exit(1); + } + nsip_listen(gbprox_nsi, nsip_listen_port); + + /* 'establish' the outgoing connection to the SGSN */ + sin.sin_port = ntohs(23000); + inet_aton("192.168.100.239", &sin.sin_addr); + gbprox_peer_sgsn = nsip_connect(gbprox_nsi, &sin, 2342); + + while (1) { + rc = bsc_select_main(0); + if (rc < 0) + exit(3); + } + + exit(0); +} + +struct gsm_network; +int bsc_vty_init(struct gsm_network *dummy) +{ + cmd_init(1); + vty_init(); + + openbsc_vty_add_cmds(); + //mgcp_vty_init(); + return 0; +} + diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 650d7d45d..a2181b124 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -74,11 +74,6 @@ static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) return "undefined"; } -static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) -{ - return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); -} - static inline struct msgb *bssgp_msgb_alloc(void) { return msgb_alloc_headroom(4096, 128, "BSSGP"); @@ -120,7 +115,7 @@ static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) } /* Chapter 10.4.14: Status */ -static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 6c495b01e..3bb0bf94d 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -72,30 +72,6 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; -#define NSE_S_BLOCKED 0x0001 -#define NSE_S_ALIVE 0x0002 - -struct gprs_nsvc { - struct llist_head list; - struct gprs_ns_inst *nsi; - - u_int16_t nsei; /* end-to-end significance */ - u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ - - u_int32_t state; - u_int32_t remote_state; - - struct timer_list alive_timer; - int timer_is_tns_alive; - int alive_retries; - - union { - struct { - struct sockaddr_in bts_addr; - } ip; - }; -}; - enum gprs_ns_ll { GPRS_NS_LL_UDP, GPRS_NS_LL_E1, @@ -474,7 +450,7 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); - return NULL; + return nsi; } void gprs_ns_destroy(struct gprs_ns_inst *nsi) @@ -586,3 +562,24 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) return ret; } + +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, uint16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_rem_addr(nsi, dest); + if (!nsvc) { + nsvc = nsvc_create(nsi, nsvci); + nsvc->ip.bts_addr = *dest; + } + nsvc->remote_end_is_sgsn = 1; + + /* Initiate a RESET procedure */ + if (gprs_ns_tx_simple(nsvc, NS_PDUT_RESET) < 0) + return NULL; + /* FIXME: should we run a timer and re-transmit the reset request? */ + + return nsvc; +} diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2b5bf21a6..721cadd23 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -707,58 +707,6 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return 0; } -int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, - int (*cb)(struct bsc_fd *fd, unsigned int what)) -{ - struct sockaddr_in addr; - int ret, on = 1; - int type = SOCK_STREAM; - - if (proto == IPPROTO_UDP) - type = SOCK_DGRAM; - - bfd->fd = socket(AF_INET, type, proto); - bfd->cb = cb; - bfd->when = BSC_FD_READ; - //bfd->data = line; - - if (bfd->fd < 0) { - LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n"); - return -EIO; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - - setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); - if (ret < 0) { - LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n", - strerror(errno)); - close(bfd->fd); - return -EIO; - } - - if (proto != IPPROTO_UDP) { - ret = listen(bfd->fd, 1); - if (ret < 0) { - perror("listen"); - return ret; - } - } - - ret = bsc_register_fd(bfd); - if (ret < 0) { - perror("register_listen_fd"); - close(bfd->fd); - return ret; - } - return 0; -} - /* Actively connect to a BTS. Currently used by ipaccess-config.c */ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa) { diff --git a/openbsc/src/socket.c b/openbsc/src/socket.c new file mode 100644 index 000000000..3ed4d425a --- /dev/null +++ b/openbsc/src/socket.c @@ -0,0 +1,94 @@ +/* OpenBSC sokcet code, taken from Abis input driver for ip.access */ + +/* (C) 2009 by Harald Welte + * (C) 2010 by Holger Hans Peter Freyther + * (C) 2010 by On-Waves + * + * 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 + +int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, + int (*cb)(struct bsc_fd *fd, unsigned int what)) +{ + struct sockaddr_in addr; + int ret, on = 1; + int type = SOCK_STREAM; + + if (proto == IPPROTO_UDP) + type = SOCK_DGRAM; + + bfd->fd = socket(AF_INET, type, proto); + bfd->cb = cb; + bfd->when = BSC_FD_READ; + //bfd->data = line; + + if (bfd->fd < 0) { + LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n"); + return -EIO; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n", + strerror(errno)); + close(bfd->fd); + return -EIO; + } + + if (proto != IPPROTO_UDP) { + ret = listen(bfd->fd, 1); + if (ret < 0) { + perror("listen"); + return ret; + } + } + + ret = bsc_register_fd(bfd); + if (ret < 0) { + perror("register_listen_fd"); + close(bfd->fd); + return ret; + } + return 0; +} -- cgit v1.2.3