blob: c20016aa51d4a78e22032989fdfe9875c1d2f69c [file] [log] [blame]
Harald Welte144e0292010-05-13 11:45:07 +02001/* VTY interface for our GPRS Networks Service (NS) implementation */
2
3/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <stdlib.h>
24#include <unistd.h>
25#include <errno.h>
26#include <stdint.h>
27
28#include <arpa/inet.h>
29
30#include <openbsc/gsm_data.h>
31#include <osmocore/msgb.h>
32#include <osmocore/tlv.h>
33#include <osmocore/talloc.h>
34#include <osmocore/select.h>
35#include <osmocore/rate_ctr.h>
36#include <openbsc/debug.h>
37#include <openbsc/signal.h>
38#include <openbsc/gprs_ns.h>
39#include <openbsc/gprs_bssgp.h>
Harald Welte91f7f4b2010-05-15 23:52:02 +020040#include <openbsc/telnet_interface.h>
Harald Welte804fc812010-05-14 18:59:17 +020041#include <openbsc/vty.h>
Harald Welte144e0292010-05-13 11:45:07 +020042
43#include <vty/vty.h>
44#include <vty/command.h>
45
46static struct gprs_ns_inst *vty_nsi = NULL;
47
48/* FIXME: this should go to some common file as it is copied
49 * in vty_interface.c of the BSC */
50static const struct value_string gprs_ns_timer_strs[] = {
51 { 0, "tns-block" },
52 { 1, "tns-block-retries" },
53 { 2, "tns-reset" },
54 { 3, "tns-reset-retries" },
55 { 4, "tns-test" },
56 { 5, "tns-alive" },
57 { 6, "tns-alive-retries" },
58 { 0, NULL }
59};
60
61static struct cmd_node ns_node = {
62 NS_NODE,
63 "%s(ns)#",
64 1,
65};
66
67static int config_write_ns(struct vty *vty)
68{
69 struct gprs_nsvc *nsvc;
70 unsigned int i;
71
72 vty_out(vty, "ns%s", VTY_NEWLINE);
73
74 llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) {
75 if (!nsvc->persistent)
76 continue;
77 vty_out(vty, " nse %u nsvci %u%s",
78 nsvc->nsei, nsvc->nsvci, VTY_NEWLINE);
79 vty_out(vty, " nse %u remote-role %s%s",
80 nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss",
81 VTY_NEWLINE);
82 if (nsvc->nsi->ll == GPRS_NS_LL_UDP) {
83 vty_out(vty, " nse %u remote-ip %s%s",
84 nsvc->nsei,
85 inet_ntoa(nsvc->ip.bts_addr.sin_addr),
86 VTY_NEWLINE);
87 vty_out(vty, " nse %u remote-port %u%s",
88 nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port),
89 VTY_NEWLINE);
90 }
91 }
92
93 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
94 vty_out(vty, " timer %s %u%s",
95 get_value_string(gprs_ns_timer_strs, i),
96 vty_nsi->timeout[i], VTY_NEWLINE);
97
98 return CMD_SUCCESS;
99}
100
101DEFUN(cfg_ns, cfg_ns_cmd,
102 "ns",
103 "Configure the GPRS Network Service")
104{
105 vty->node = NS_NODE;
106 return CMD_SUCCESS;
107}
108
Harald Welte92883342010-05-15 23:04:03 +0200109static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats)
110{
111 vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s",
112 nsvc->nsei, nsvc->nsvci,
113 nsvc->remote_end_is_sgsn ? "SGSN" : "BSS",
114 nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD",
115 nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED");
116 if (nsvc->nsi->ll == GPRS_NS_LL_UDP)
117 vty_out(vty, ", %15s:%u",
118 inet_ntoa(nsvc->ip.bts_addr.sin_addr),
119 ntohs(nsvc->ip.bts_addr.sin_port));
120 vty_out(vty, "%s", VTY_NEWLINE);
121 if (stats)
122 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
123}
124
Harald Welteaf1d4cb2010-05-13 12:32:30 +0200125static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats)
Harald Welte144e0292010-05-13 11:45:07 +0200126{
Harald Welte144e0292010-05-13 11:45:07 +0200127 struct gprs_nsvc *nsvc;
128
129 llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
Harald Weltedd1c83c2010-05-13 13:58:08 +0200130 if (nsvc == nsi->unknown_nsvc)
131 continue;
Harald Welte92883342010-05-15 23:04:03 +0200132 dump_nse(vty, nsvc, stats);
Harald Welte144e0292010-05-13 11:45:07 +0200133 }
Harald Welteaf1d4cb2010-05-13 12:32:30 +0200134}
Harald Welte144e0292010-05-13 11:45:07 +0200135
Harald Welteaf1d4cb2010-05-13 12:32:30 +0200136DEFUN(show_ns, show_ns_cmd, "show ns",
137 SHOW_STR "Display information about the NS protocol")
138{
139 struct gprs_ns_inst *nsi = vty_nsi;
140 dump_ns(vty, nsi, 0);
Harald Welte144e0292010-05-13 11:45:07 +0200141 return CMD_SUCCESS;
142}
143
Harald Welteaf1d4cb2010-05-13 12:32:30 +0200144DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats",
145 SHOW_STR
146 "Display information about the NS protocol\n"
147 "Include statistics\n")
148{
149 struct gprs_ns_inst *nsi = vty_nsi;
150 dump_ns(vty, nsi, 1);
151 return CMD_SUCCESS;
152}
Harald Welte144e0292010-05-13 11:45:07 +0200153
Harald Welte92883342010-05-15 23:04:03 +0200154DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
155 SHOW_STR "Display information about the NS protocol\n"
156 "Select one NSE by its NSE Identifier\n"
157 "Select one NSE by its NS-VC Identifier\n"
158 "The Identifier of selected type\n"
159 "Include Statistics\n")
160{
161 struct gprs_ns_inst *nsi = vty_nsi;
162 struct gprs_nsvc *nsvc;
163 uint16_t id = atoi(argv[1]);
164 int show_stats = 0;
165
166 if (!strcmp(argv[0], "nsei"))
167 nsvc = nsvc_by_nsei(nsi, id);
168 else
169 nsvc = nsvc_by_nsvci(nsi, id);
170
171 if (!nsvc) {
172 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
173 return CMD_WARNING;
174 }
175
176 if (argc >= 3)
177 show_stats = 1;
178
179 dump_nse(vty, nsvc, show_stats);
180 return CMD_SUCCESS;
181}
182
Harald Welte24133c32010-05-15 23:06:26 +0200183#define NSE_CMD_STR "Persistent NS Entity\n" "NS Entity ID (NSEI)\n"
Harald Welte144e0292010-05-13 11:45:07 +0200184
185DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,
186 "nse <0-65535> nsvci <0-65534>",
187 NSE_CMD_STR
188 "NS Virtual Connection\n"
189 "NS Virtual Connection ID (NSVCI)\n"
190 )
191{
192 uint16_t nsei = atoi(argv[0]);
193 uint16_t nsvci = atoi(argv[1]);
194 struct gprs_nsvc *nsvc;
195
196 nsvc = nsvc_by_nsei(vty_nsi, nsei);
197 if (!nsvc) {
198 nsvc = nsvc_create(vty_nsi, nsvci);
199 nsvc->nsei = nsei;
200 }
201 nsvc->nsvci = nsvci;
202 /* All NSVCs that are explicitly configured by VTY are
203 * marked as persistent so we can write them to the config
204 * file at some later point */
205 nsvc->persistent = 1;
206
207 return CMD_SUCCESS;
208}
209
210DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd,
211 "nse <0-65535> remote-ip A.B.C.D",
212 NSE_CMD_STR
213 "Remote IP Address\n"
214 "Remote IP Address\n")
215{
216 uint16_t nsei = atoi(argv[0]);
217 struct gprs_nsvc *nsvc;
218
219 nsvc = nsvc_by_nsei(vty_nsi, nsei);
220 if (!nsvc) {
221 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
222 return CMD_WARNING;
223 }
224 inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr);
225
226 return CMD_SUCCESS;
227
228}
229
230DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd,
231 "nse <0-65535> remote-port <0-65535>",
232 NSE_CMD_STR
233 "Remote UDP Port\n"
234 "Remote UDP Port Number\n")
235{
236 uint16_t nsei = atoi(argv[0]);
237 uint16_t port = atoi(argv[1]);
238 struct gprs_nsvc *nsvc;
239
240 nsvc = nsvc_by_nsei(vty_nsi, nsei);
241 if (!nsvc) {
242 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
243 return CMD_WARNING;
244 }
245
246 nsvc->ip.bts_addr.sin_port = htons(port);
247
248 return CMD_SUCCESS;
249}
250
251DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,
252 "nse <0-65535> remote-role (sgsn|bss)",
253 NSE_CMD_STR
254 "Remote NSE Role\n"
255 "Remote Peer is SGSN\n"
256 "Remote Peer is BSS\n")
257{
258 uint16_t nsei = atoi(argv[0]);
259 struct gprs_nsvc *nsvc;
260
261 nsvc = nsvc_by_nsei(vty_nsi, nsei);
262 if (!nsvc) {
263 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
264 return CMD_WARNING;
265 }
266
267 if (!strcmp(argv[1], "sgsn"))
268 nsvc->remote_end_is_sgsn = 1;
269 else
270 nsvc->remote_end_is_sgsn = 0;
271
272 return CMD_SUCCESS;
273}
274
275DEFUN(cfg_no_nse, cfg_no_nse_cmd,
276 "no nse <0-65535>",
Harald Welte24133c32010-05-15 23:06:26 +0200277 "Delete Persistent NS Entity\n"
Harald Welte144e0292010-05-13 11:45:07 +0200278 "Delete " NSE_CMD_STR)
279{
280 uint16_t nsei = atoi(argv[0]);
281 struct gprs_nsvc *nsvc;
282
283 nsvc = nsvc_by_nsei(vty_nsi, nsei);
284 if (!nsvc) {
285 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
286 return CMD_WARNING;
287 }
288
Harald Welte24133c32010-05-15 23:06:26 +0200289 if (!nsvc->persistent) {
290 vty_out(vty, "NSEI %u is not a persistent NSE%s",
291 nsei, VTY_NEWLINE);
292 return CMD_WARNING;
293 }
294
295 nsvc->persistent = 0;
Harald Welte144e0292010-05-13 11:45:07 +0200296
297 return CMD_SUCCESS;
298}
299
300DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
301 "timer " NS_TIMERS " <0-65535>",
302 "Network Service Timer\n"
303 NS_TIMERS_HELP "Timer Value\n")
304{
305 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
306 int val = atoi(argv[1]);
307
308 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
309 return CMD_WARNING;
310
311 vty_nsi->timeout[idx] = val;
312
313 return CMD_SUCCESS;
314}
315
Harald Welte43f3b692010-05-14 19:36:59 +0200316DEFUN(nsvc_nsei, nsvc_nsei_cmd,
317 "nsvc nsei <0-65535> (block|unblock|reset)",
318 "Perform an operation on a NSVC\n"
319 "NS-VC Identifier (NS-VCI)\n"
320 "Initiate BLOCK procedure\n"
321 "Initiate UNBLOCK procedure\n"
322 "Initiate RESET procedure\n")
323{
324 uint16_t nsvci = atoi(argv[0]);
325 const char *operation = argv[1];
326 struct gprs_nsvc *nsvc;
327
328 nsvc = nsvc_by_nsei(vty_nsi, nsvci);
329 if (!nsvc) {
330 vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE);
331 return CMD_WARNING;
332 }
333
334 if (!strcmp(operation, "block"))
335 gprs_ns_tx_block(nsvc, NS_CAUSE_OM_INTERVENTION);
336 else if (!strcmp(operation, "unblock"))
337 gprs_ns_tx_unblock(nsvc);
338 else if (!strcmp(operation, "reset"))
339 gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
340 else
341 return CMD_WARNING;
342
343 return CMD_SUCCESS;
344}
345
Harald Welte91f7f4b2010-05-15 23:52:02 +0200346DEFUN(logging_fltr_nsvc,
347 logging_fltr_nsvc_cmd,
348 "logging filter nsvc (nsei|nsvci) <0-65535>",
Harald Welte6703bf72010-05-16 00:00:04 +0200349 LOGGING_STR FILTER_STR
Harald Welte91f7f4b2010-05-15 23:52:02 +0200350 "Filter based on NS Virtual Connection\n"
351 "Identify NS-VC by NSEI\n"
352 "Identify NS-VC by NSVCI\n"
353 "Numeric identifier\n")
354{
355 struct telnet_connection *conn;
356 struct gprs_nsvc *nsvc;
357 uint16_t id = atoi(argv[1]);
358
359 conn = (struct telnet_connection *) vty->priv;
360 if (!conn->dbg) {
361 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
362 return CMD_WARNING;
363 }
364
365 if (!strcmp(argv[0], "nsei"))
366 nsvc = nsvc_by_nsei(vty_nsi, id);
367 else
368 nsvc = nsvc_by_nsvci(vty_nsi, id);
369
370 if (!nsvc) {
371 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
372 return CMD_WARNING;
373 }
374
375 log_set_nsvc_filter(conn->dbg, nsvc);
376 return CMD_SUCCESS;
377}
Harald Welte43f3b692010-05-14 19:36:59 +0200378
Harald Welte144e0292010-05-13 11:45:07 +0200379int gprs_ns_vty_init(struct gprs_ns_inst *nsi)
380{
381 vty_nsi = nsi;
382
383 install_element_ve(&show_ns_cmd);
Harald Welteaf1d4cb2010-05-13 12:32:30 +0200384 install_element_ve(&show_ns_stats_cmd);
Harald Welte92883342010-05-15 23:04:03 +0200385 install_element_ve(&show_nse_cmd);
Harald Welte91f7f4b2010-05-15 23:52:02 +0200386 install_element_ve(&logging_fltr_nsvc_cmd);
Harald Welte144e0292010-05-13 11:45:07 +0200387
388 install_element(CONFIG_NODE, &cfg_ns_cmd);
389 install_node(&ns_node, config_write_ns);
390 install_default(NS_NODE);
Harald Welte804fc812010-05-14 18:59:17 +0200391 install_element(NS_NODE, &ournode_exit_cmd);
Harald Weltea52ff452010-05-14 19:11:04 +0200392 install_element(NS_NODE, &ournode_end_cmd);
Harald Welte144e0292010-05-13 11:45:07 +0200393 install_element(NS_NODE, &cfg_nse_nsvci_cmd);
394 install_element(NS_NODE, &cfg_nse_remoteip_cmd);
395 install_element(NS_NODE, &cfg_nse_remoteport_cmd);
396 install_element(NS_NODE, &cfg_nse_remoterole_cmd);
397 install_element(NS_NODE, &cfg_no_nse_cmd);
398 install_element(NS_NODE, &cfg_ns_timer_cmd);
399
Harald Welte43f3b692010-05-14 19:36:59 +0200400 install_element(ENABLE_NODE, &nsvc_nsei_cmd);
401
Harald Welte144e0292010-05-13 11:45:07 +0200402 return 0;
403}