diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h new file mode 100644 index 000000000..2dc53c13d --- /dev/null +++ b/openbsc/include/openbsc/sgsn.h @@ -0,0 +1,30 @@ +#ifndef _SGSN_H +#define _SGSN_H + +#include + +#include + +#include + +struct sgsn_config { + /* parsed from config file */ + u_int32_t nsip_listen_ip; + u_int16_t nsip_listen_port; + + /* misc */ + struct gprs_ns_inst *nsi; +}; + + +/* sgsn_vty.c */ + +int sgsn_vty_init(void); +int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg); + +/* sgsn.c */ + +/* Main input function for Gb proxy */ +int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci); + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6e4e506ff..18245ed5e 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 osmo-gb_proxy + isdnsync bsc_mgcp ipaccess-proxy osmo-gbproxy osmo-sgsn noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libsgsn.a noinst_HEADERS = vty/cardshell.h @@ -33,7 +33,7 @@ libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c \ libsccp_a_SOURCES = sccp/sccp.c bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c -bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libsgsn.a libvty.a -ldl -ldbi $(LIBCRYPT) +bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \ rs232.c bts_siemens_bs11.c @@ -51,6 +51,10 @@ 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 gb_proxy_vty.c \ +osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ gprs_ns.c socket.c debug.c -osmo_gb_proxy_LDADD = libvty.a +osmo_gbproxy_LDADD = libvty.a + +osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ + socket.c debug.c +osmo_sgsn_LDADD = libvty.a libsgsn.a diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c index 8f0306091..fe72e0214 100644 --- a/openbsc/src/gb_proxy_main.c +++ b/openbsc/src/gb_proxy_main.c @@ -64,7 +64,7 @@ const char *openbsc_copyright = "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 = "gb_proxy.cfg"; +static char *config_file = "osmo_gbproxy.cfg"; static struct gbproxy_config gbcfg; /* Pointer to the SGSN peer */ diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index a2181b124..ab6d1a098 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -138,6 +138,25 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } +/* Chapter 8.4 BVC-Reset Procedure */ +static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, + uint16_t ns_bvci) +{ + uint8_t bvci; + int rc; + + bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); + + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS + * informs us about its RAC + Cell ID, so we can create a mapping */ + + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + msgb_nsei(msg), bvci, ns_bvci); + return 0; +} + /* Uplink unit-data */ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { @@ -157,10 +176,12 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; +#if 0 //FIXME /* Determine the BTS based on the Cell ID */ bts = gsm48_bts_by_ra_id(bsc_gsmnet, TLVP_VAL(&tp, BSSGP_IE_CELL_ID), TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); +#endif if (bts) msg->trx = bts->c0; @@ -229,6 +250,7 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); } + /* We expect msg->l3h to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) { @@ -311,11 +333,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, - bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - msgb_nsei(msg), bvci, ns_bvci); + rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci); break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ diff --git a/openbsc/src/gprs_sgsn.c b/openbsc/src/gprs_sgsn.c index 3f7f61e20..9844f8808 100644 --- a/openbsc/src/gprs_sgsn.c +++ b/openbsc/src/gprs_sgsn.c @@ -94,35 +94,3 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, return ctx; } - -/* call-back function for the NS protocol */ -static int gprs_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: - /* hand the message into the BSSGP implementation */ - rc = gprs_bssgp_rcvmsg(msg, 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 sgsn_init(void) -{ - struct gprs_ns_inst *nsi; - - nsi = gprs_ns_instantiate(&gprs_ns_cb); - if (!nsi) - return -EIO; - - return nsip_listen(nsi, 23000); -} diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index ffc3303a3..db439daa7 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -153,7 +153,7 @@ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) aa->att_result = 1; /* GPRS only */ aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; aa->radio_prio = 4; /* lowest */ - gsm48_ra_id_by_bts(aa->ra_id.digits, old_msg->trx->bts); + //FIXME gsm48_ra_id_by_bts(aa->ra_id.digits, old_msg->trx->bts); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ return gsm48_gmm_sendmsg(msg, 0); @@ -227,7 +227,7 @@ static int gsm48_rx_gmm_id_resp(struct msgb *msg) DEBUGP(DMM, "GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", mi_type, mi_string); - gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + //FIXME gprs_ra_id_by_bts(&ra_id, msg->trx->bts); ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); if (!ctx) { DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); @@ -289,7 +289,7 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + //FIXME gprs_ra_id_by_bts(&ra_id, msg->trx->bts); /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -391,7 +391,7 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) rua->force_stby = 0; /* not indicated */ rua->upd_result = 0; /* RA updated */ rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; - gsm48_ra_id_by_bts(rua->ra_id.digits, old_msg->trx->bts); + //FIXME gsm48_ra_id_by_bts(rua->ra_id.digits, old_msg->trx->bts); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ return gsm48_gmm_sendmsg(msg, 0); diff --git a/openbsc/src/osmo_gbproxy.cfg b/openbsc/src/osmo_gbproxy.cfg new file mode 100644 index 000000000..f2ef1411f --- /dev/null +++ b/openbsc/src/osmo_gbproxy.cfg @@ -0,0 +1,13 @@ +! +! OpenBSC configuration saved from vty +! ! +! +line vty + no login +! +gbproxy + nsip bss local port 23000 + nsip sgsn remote ip 192.168.100.239 + nsip sgsn remote port 23000 + nsip sgsn nsei 1 + nsip sgsn nsvci 11 diff --git a/openbsc/src/osmo_sgsn.cfg b/openbsc/src/osmo_sgsn.cfg new file mode 100644 index 000000000..f39e8536f --- /dev/null +++ b/openbsc/src/osmo_sgsn.cfg @@ -0,0 +1,9 @@ +! +! OpenBSC configuration saved from vty +! ! +! +line vty + no login +! +sgsn + nsip local port 23000 diff --git a/openbsc/src/sgsn_main.c b/openbsc/src/sgsn_main.c new file mode 100644 index 000000000..5c56ca7ff --- /dev/null +++ b/openbsc/src/sgsn_main.c @@ -0,0 +1,141 @@ +/* GPRS SGSN Implementation */ + +/* (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 +#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 *sgsn_nsi; + +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 = "osmo_sgsn.cfg"; +static struct sgsn_config sgcfg; + +/* call-back function for the NS protocol */ +static int sgsn_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: + /* hand the message into the BSSGP implementation */ + rc = gprs_bssgp_rcvmsg(msg, 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, "osmo_sgsn"); + + 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, 4245); + rc = sgsn_parse_config(config_file, &sgcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } + + sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb); + if (!sgsn_nsi) { + LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); + exit(1); + } + sgcfg.nsi = sgsn_nsi; + nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port); + + 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(); + sgsn_vty_init(); + return 0; +} + diff --git a/openbsc/src/sgsn_vty.c b/openbsc/src/sgsn_vty.c new file mode 100644 index 000000000..ec18fcbf9 --- /dev/null +++ b/openbsc/src/sgsn_vty.c @@ -0,0 +1,146 @@ +/* + * (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 + +static struct sgsn_config *g_cfg = NULL; + +static struct cmd_node sgsn_node = { + SGSN_NODE, + "%s(sgsn)#", + 1, +}; + +static int config_write_sgsn(struct vty *vty) +{ + struct in_addr ia; + + vty_out(vty, "sgsn%s", VTY_NEWLINE); + + if (g_cfg->nsip_listen_ip) { + ia.s_addr = htonl(g_cfg->nsip_listen_ip); + vty_out(vty, " nsip local ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + } + vty_out(vty, " nsip local port %u%s", g_cfg->nsip_listen_port, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", + SHOW_STR "Display information about the SGSN") +{ + /* FIXME: iterate over list of NS-VC's and display their state */ + struct gprs_ns_inst *nsi = g_cfg->nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, " remote peer %s:%u%s", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_sgsn, + cfg_sgsn_cmd, + "sgsn", + "Configure the SGSN") +{ + vty->node = SGSN_NODE; + return CMD_SUCCESS; +} + + +DEFUN(cfg_nsip_local_ip, + cfg_nsip_local_ip_cmd, + "nsip local ip A.B.C.D", + "Set the IP address on which we listen for BSS connects") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_listen_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_local_port, + cfg_nsip_local_port_cmd, + "nsip local port <0-65534>", + "Set the UDP port on which we listen for BSS connects") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_listen_port = port; + return CMD_SUCCESS; +} + + + + +int sgsn_vty_init(void) +{ + install_element(VIEW_NODE, &show_sgsn_cmd); + + install_element(CONFIG_NODE, &cfg_sgsn_cmd); + install_node(&sgsn_node, config_write_sgsn); + install_default(SGSN_NODE); + install_element(SGSN_NODE, &cfg_nsip_local_ip_cmd); + install_element(SGSN_NODE, &cfg_nsip_local_port_cmd); + + return 0; +} + +int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg) +{ + int rc; + + g_cfg = cfg; + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + return 0; +}