diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index c74546a8b..60051d13b 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -140,7 +140,8 @@ struct gprs_nsvc { enum nsvc_timer_mode timer_mode; int alive_retries; - int remote_end_is_sgsn; + unsigned int remote_end_is_sgsn:1; + unsigned int persistent:1; union { struct { @@ -178,4 +179,8 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci); + +/* Add NS-specific VTY stuff */ +int gprs_ns_vty_init(struct gprs_ns_inst *nsi); + #endif diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 5f7c819bb..99fba47d9 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -109,6 +109,7 @@ enum node_type { MGCP_NODE, GBPROXY_NODE, SGSN_NODE, + NS_NODE, }; /* Node which has some commands and prompt string and configuration 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 +#include + +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: