aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-05-12 15:55:23 +0000
committerHarald Welte <laforge@gnumonks.org>2010-05-12 18:28:00 +0200
commit1194b584beb70b7c1ab30fa047f3af31bb3ea0ad (patch)
tree8e146d0ff9aea2558d40a5dd0f07c0b6c6d807d8 /openbsc/src
parentf6d67c04ee2872777a8d497103cf9f0989f5d16d (diff)
NS: Add support for persistent NS-VC configuration
With persistent NS-VC configuration (configured through VTY), we can respond properly to BSS with a somewhat strange NS implementation Such as the BSplus. It enables us to respond with a proper NS-RESET (including NSVCI/NSEI) when receiving a NS-ALIVE or other PDU for a BLOCKED/DEAD NS-VC after our end of the connection is rebooted.
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/gprs/gb_proxy_main.c13
-rw-r--r--openbsc/src/gprs/gb_proxy_vty.c25
-rw-r--r--openbsc/src/gprs/gprs_ns.c225
-rw-r--r--openbsc/src/gprs/osmo_gbproxy.cfg8
-rw-r--r--openbsc/src/vty/command.c1
5 files changed, 229 insertions, 43 deletions
diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c
index 7aeb5e41b..510abd09d 100644
--- a/openbsc/src/gprs/gb_proxy_main.c
+++ b/openbsc/src/gprs/gb_proxy_main.c
@@ -105,11 +105,6 @@ int main(int argc, char **argv)
log_set_all_filter(stderr_target, 1);
telnet_init(&dummy_network, 4246);
- rc = gbproxy_parse_config(config_file, &gbcfg);
- if (rc < 0) {
- LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n");
- exit(2);
- }
bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb);
if (!bssgp_nsi) {
@@ -117,7 +112,15 @@ int main(int argc, char **argv)
exit(1);
}
gbcfg.nsi = bssgp_nsi;
+ gprs_ns_vty_init(bssgp_nsi);
register_signal_handler(SS_NS, &gbprox_signal, NULL);
+
+ rc = gbproxy_parse_config(config_file, &gbcfg);
+ if (rc < 0) {
+ LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n");
+ exit(2);
+ }
+
nsip_listen(bssgp_nsi, gbcfg.nsip_listen_port);
/* 'establish' the outgoing connection to the SGSN */
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
index a40392b90..e0fcfba53 100644
--- a/openbsc/src/gprs/gb_proxy_vty.c
+++ b/openbsc/src/gprs/gb_proxy_vty.c
@@ -70,29 +70,6 @@ static int config_write_gbproxy(struct vty *vty)
return CMD_SUCCESS;
}
-DEFUN(show_ns, show_ns_cmd, "show ns",
- SHOW_STR "Display information about the NS protocol")
-{
- /* 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_gbproxy,
cfg_gbproxy_cmd,
"gbproxy",
@@ -173,10 +150,8 @@ DEFUN(cfg_nsip_sgsn_nsvci,
return CMD_SUCCESS;
}
-
int gbproxy_vty_init(void)
{
- install_element(VIEW_NODE, &show_ns_cmd);
install_element(VIEW_NODE, &show_gbproxy_cmd);
install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c
index 3d672fb8f..ed6421032 100644
--- a/openbsc/src/gprs/gprs_ns.c
+++ b/openbsc/src/gprs/gprs_ns.c
@@ -131,6 +131,14 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci)
return nsvc;
}
+static void nsvc_delete(struct gprs_nsvc *nsvc)
+{
+ if (bsc_timer_pending(&nsvc->timer))
+ bsc_del_timer(&nsvc->timer);
+ llist_del(&nsvc->list);
+ talloc_free(nsvc);
+}
+
static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal,
uint8_t cause)
{
@@ -592,15 +600,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
fake_nsvc.nsi = nsi;
fake_nsvc.ip.bts_addr = *saddr;
fake_nsvc.state = NSE_S_ALIVE;
-#if 0
return gprs_ns_tx_status(&fake_nsvc,
NS_CAUSE_PDU_INCOMP_PSTATE, 0,
msg);
-#else
- /* BS+ Gb implementation ignores STATUS, so we try
- * our luck with a RESET incompatible with the spec */
- return gprs_ns_tx_simple(&fake_nsvc, NS_PDUT_RESET);
-#endif
}
rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data,
msgb_l2len(msg), 0, 0);
@@ -628,9 +630,14 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg,
switch (nsh->pdu_type) {
case NS_PDUT_ALIVE:
- /* remote end inquires whether we're still alive,
- * we need to respond with ALIVE_ACK */
- rc = gprs_ns_tx_alive_ack(nsvc);
+ /* If we're dead and blocked and suddenly receive a
+ * NS-ALIVE out of the blue, we might have been re-started
+ * and should send a NS-RESET to make sure everything recovers
+ * fine. */
+ if (nsvc->state == NSE_S_BLOCKED)
+ rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE);
+ else
+ rc = gprs_ns_tx_alive_ack(nsvc);
break;
case NS_PDUT_ALIVE_ACK:
/* stop Tns-alive */
@@ -844,3 +851,203 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi,
return nsvc;
}
+
+#include <vty/vty.h>
+#include <vty/command.h>
+
+static struct gprs_ns_inst *vty_nsi = NULL;
+
+static struct cmd_node ns_node = {
+ NS_NODE,
+ "%s(ns)#",
+ 1,
+};
+
+static int config_write_ns(struct vty *vty)
+{
+ struct gprs_nsvc *nsvc;
+
+ vty_out(vty, "ns%s", VTY_NEWLINE);
+
+ llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) {
+ if (!nsvc->persistent)
+ continue;
+ vty_out(vty, " nse %u nsvci %u%s",
+ nsvc->nsei, nsvc->nsvci, VTY_NEWLINE);
+ vty_out(vty, " nse %u remote-role %s%s",
+ nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss",
+ VTY_NEWLINE);
+ if (nsvc->nsi->ll == GPRS_NS_LL_UDP) {
+ vty_out(vty, " nse %u remote-ip %s%s",
+ nsvc->nsei,
+ inet_ntoa(nsvc->ip.bts_addr.sin_addr),
+ VTY_NEWLINE);
+ vty_out(vty, " nse %u remote-port %u%s",
+ nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port),
+ VTY_NEWLINE);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ns, cfg_ns_cmd,
+ "ns",
+ "Configure the GPRS Network Service")
+{
+ vty->node = NS_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_ns, show_ns_cmd, "show ns",
+ SHOW_STR "Display information about the NS protocol")
+{
+ struct gprs_ns_inst *nsi = vty_nsi;
+ struct gprs_nsvc *nsvc;
+
+ llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
+ vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s",
+ nsvc->nsei, nsvc->nsvci,
+ nsvc->remote_end_is_sgsn ? "SGSN" : "BSS",
+ nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD",
+ nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED");
+ if (nsvc->nsi->ll == GPRS_NS_LL_UDP)
+ vty_out(vty, ", %15s:%u",
+ inet_ntoa(nsvc->ip.bts_addr.sin_addr),
+ ntohs(nsvc->ip.bts_addr.sin_port));
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n"
+
+DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,
+ "nse <0-65535> nsvci <0-65534>",
+ NSE_CMD_STR
+ "NS Virtual Connection\n"
+ "NS Virtual Connection ID (NSVCI)\n"
+ )
+{
+ uint16_t nsei = atoi(argv[0]);
+ uint16_t nsvci = atoi(argv[1]);
+ struct gprs_nsvc *nsvc;
+
+ nsvc = nsvc_by_nsei(vty_nsi, nsei);
+ if (!nsvc) {
+ nsvc = nsvc_create(vty_nsi, nsvci);
+ nsvc->nsei = nsei;
+ }
+ nsvc->nsvci = nsvci;
+ /* All NSVCs that are explicitly configured by VTY are
+ * marked as persistent so we can write them to the config
+ * file at some later point */
+ nsvc->persistent = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd,
+ "nse <0-65535> remote-ip A.B.C.D",
+ NSE_CMD_STR
+ "Remote IP Address\n"
+ "Remote IP Address\n")
+{
+ uint16_t nsei = atoi(argv[0]);
+ struct gprs_nsvc *nsvc;
+
+ nsvc = nsvc_by_nsei(vty_nsi, nsei);
+ if (!nsvc) {
+ vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr);
+
+ return CMD_SUCCESS;
+
+}
+
+DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd,
+ "nse <0-65535> remote-port <0-65535>",
+ NSE_CMD_STR
+ "Remote UDP Port\n"
+ "Remote UDP Port Number\n")
+{
+ uint16_t nsei = atoi(argv[0]);
+ uint16_t port = atoi(argv[1]);
+ struct gprs_nsvc *nsvc;
+
+ nsvc = nsvc_by_nsei(vty_nsi, nsei);
+ if (!nsvc) {
+ vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ nsvc->ip.bts_addr.sin_port = htons(port);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,
+ "nse <0-65535> remote-role (sgsn|bss)",
+ NSE_CMD_STR
+ "Remote NSE Role\n"
+ "Remote Peer is SGSN\n"
+ "Remote Peer is BSS\n")
+{
+ uint16_t nsei = atoi(argv[0]);
+ struct gprs_nsvc *nsvc;
+
+ nsvc = nsvc_by_nsei(vty_nsi, nsei);
+ if (!nsvc) {
+ vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[1], "sgsn"))
+ nsvc->remote_end_is_sgsn = 1;
+ else
+ nsvc->remote_end_is_sgsn = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_nse, cfg_no_nse_cmd,
+ "no nse <0-65535>",
+ "Delete NS Entity\n"
+ "Delete " NSE_CMD_STR)
+{
+ uint16_t nsei = atoi(argv[0]);
+ struct gprs_nsvc *nsvc;
+
+ nsvc = nsvc_by_nsei(vty_nsi, nsei);
+ if (!nsvc) {
+ vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ nsvc_delete(nsvc);
+
+ return CMD_SUCCESS;
+}
+
+int gprs_ns_vty_init(struct gprs_ns_inst *nsi)
+{
+ vty_nsi = nsi;
+
+ install_element(VIEW_NODE, &show_ns_cmd);
+
+ install_element(CONFIG_NODE, &cfg_ns_cmd);
+ install_node(&ns_node, config_write_ns);
+ install_default(NS_NODE);
+ install_element(NS_NODE, &cfg_nse_nsvci_cmd);
+ install_element(NS_NODE, &cfg_nse_remoteip_cmd);
+ install_element(NS_NODE, &cfg_nse_remoteport_cmd);
+ install_element(NS_NODE, &cfg_nse_remoterole_cmd);
+ install_element(NS_NODE, &cfg_no_nse_cmd);
+
+ return 0;
+}
diff --git a/openbsc/src/gprs/osmo_gbproxy.cfg b/openbsc/src/gprs/osmo_gbproxy.cfg
index f2ef1411f..d51b04a11 100644
--- a/openbsc/src/gprs/osmo_gbproxy.cfg
+++ b/openbsc/src/gprs/osmo_gbproxy.cfg
@@ -7,7 +7,7 @@ line vty
!
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
+ nsip sgsn remote ip 127.0.0.1
+ nsip sgsn remote port 7777
+ nsip sgsn nsei 101
+ nsip sgsn nsvci 101
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
index 67e6804fe..fe29824ba 100644
--- a/openbsc/src/vty/command.c
+++ b/openbsc/src/vty/command.c
@@ -2365,6 +2365,7 @@ gDEFUN(config_exit,
case MGCP_NODE:
case GBPROXY_NODE:
case SGSN_NODE:
+ case NS_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
default: