[gprs] Build the SGSN stand-alone and not as part of bsc_hack

Instead of continuing to add more and more functionality to the
bsc_hack binary, we should have the new SGSN code run as a separate
executable.

After this commit we now build a 'osmo_sgsn' executable, using its
own osmo_sgsn.cfg config file.

However, the SGSN is not yet functional, mainly due to the fact that
the BSSGP and GMM code are written with the assumption that there
is a msgb->trx->bts and the according 'sturct gsm_bts' data model
around - which clearly is no longer the case outside of bsc_hack.
This commit is contained in:
Harald Welte 2010-05-01 16:48:27 +02:00
parent a67cbd6f06
commit 288be16587
10 changed files with 375 additions and 46 deletions

View File

@ -0,0 +1,30 @@
#ifndef _SGSN_H
#define _SGSN_H
#include <sys/types.h>
#include <osmocore/msgb.h>
#include <openbsc/gprs_ns.h>
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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -0,0 +1,9 @@
!
! OpenBSC configuration saved from vty
! !
!
line vty
no login
!
sgsn
nsip local port 23000

141
openbsc/src/sgsn_main.c Normal file
View File

@ -0,0 +1,141 @@
/* GPRS SGSN Implementation */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (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 <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osmocore/talloc.h>
#include <osmocore/select.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <openbsc/telnet_interface.h>
#include <openbsc/vty.h>
#include <openbsc/sgsn.h>
#include <openbsc/gprs_ns.h>
#include <openbsc/gprs_bssgp.h>
#include "../bscconfig.h"
/* this is here for the vty... it will never be called */
void subscr_put() { abort(); }
#define _GNU_SOURCE
#include <getopt.h>
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 <http://gnu.org/licenses/gpl.html>\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;
}

146
openbsc/src/sgsn_vty.c Normal file
View File

@ -0,0 +1,146 @@
/*
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osmocore/talloc.h>
#include <openbsc/debug.h>
#include <openbsc/sgsn.h>
#include <openbsc/gprs_ns.h>
#include <vty/command.h>
#include <vty/vty.h>
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;
}