blob: 7d439445a96d0fdcbc3d5c515a93455dea8a7936 [file] [log] [blame]
Harald Weltef2b4cd72010-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 Welte8be8c8f2010-05-15 23:52:02 +020040#include <openbsc/telnet_interface.h>
Harald Welte62ab20c2010-05-14 18:59:17 +020041#include <openbsc/vty.h>
Harald Weltef2b4cd72010-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);
Harald Welte5540c4c2010-05-19 14:38:50 +020082 switch (nsvc->ll) {
83 case GPRS_NS_LL_UDP:
84 vty_out(vty, " nse %u encapsulation udp%s", nsvc->nsei,
85 VTY_NEWLINE);
Harald Weltef2b4cd72010-05-13 11:45:07 +020086 vty_out(vty, " nse %u remote-ip %s%s",
87 nsvc->nsei,
88 inet_ntoa(nsvc->ip.bts_addr.sin_addr),
89 VTY_NEWLINE);
90 vty_out(vty, " nse %u remote-port %u%s",
91 nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port),
92 VTY_NEWLINE);
Harald Welte5540c4c2010-05-19 14:38:50 +020093 break;
94 case GPRS_NS_LL_FR_GRE:
95 vty_out(vty, " nse %u encapsulation framerelay-gre%s",
96 nsvc->nsei, VTY_NEWLINE);
97 vty_out(vty, " nse %u remote-ip %s%s",
98 nsvc->nsei,
99 inet_ntoa(nsvc->frgre.bts_addr.sin_addr),
100 VTY_NEWLINE);
101 vty_out(vty, " nse %u fr-dlci %u%s",
102 nsvc->nsei, ntohs(nsvc->frgre.bts_addr.sin_port),
103 VTY_NEWLINE);
104 default:
105 break;
Harald Weltef2b4cd72010-05-13 11:45:07 +0200106 }
107 }
108
109 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
110 vty_out(vty, " timer %s %u%s",
111 get_value_string(gprs_ns_timer_strs, i),
112 vty_nsi->timeout[i], VTY_NEWLINE);
113
114 return CMD_SUCCESS;
115}
116
117DEFUN(cfg_ns, cfg_ns_cmd,
118 "ns",
119 "Configure the GPRS Network Service")
120{
121 vty->node = NS_NODE;
122 return CMD_SUCCESS;
123}
124
Harald Welte55c91e42010-05-15 23:04:03 +0200125static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats)
126{
127 vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s",
128 nsvc->nsei, nsvc->nsvci,
129 nsvc->remote_end_is_sgsn ? "SGSN" : "BSS",
130 nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD",
131 nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED");
Harald Welte5540c4c2010-05-19 14:38:50 +0200132 if (nsvc->ll == GPRS_NS_LL_UDP || nsvc->ll == GPRS_NS_LL_FR_GRE)
133 vty_out(vty, ", %s %15s:%u",
134 nsvc->ll == GPRS_NS_LL_UDP ? "UDP" : "FR-GRE",
Harald Welte55c91e42010-05-15 23:04:03 +0200135 inet_ntoa(nsvc->ip.bts_addr.sin_addr),
136 ntohs(nsvc->ip.bts_addr.sin_port));
137 vty_out(vty, "%s", VTY_NEWLINE);
138 if (stats)
139 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
140}
141
Harald Welte73b23592010-05-13 12:32:30 +0200142static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats)
Harald Weltef2b4cd72010-05-13 11:45:07 +0200143{
Harald Weltef2b4cd72010-05-13 11:45:07 +0200144 struct gprs_nsvc *nsvc;
145
146 llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
Harald Welte9aa97fc2010-05-13 13:58:08 +0200147 if (nsvc == nsi->unknown_nsvc)
148 continue;
Harald Welte55c91e42010-05-15 23:04:03 +0200149 dump_nse(vty, nsvc, stats);
Harald Weltef2b4cd72010-05-13 11:45:07 +0200150 }
Harald Welte73b23592010-05-13 12:32:30 +0200151}
Harald Weltef2b4cd72010-05-13 11:45:07 +0200152
Harald Welte73b23592010-05-13 12:32:30 +0200153DEFUN(show_ns, show_ns_cmd, "show ns",
154 SHOW_STR "Display information about the NS protocol")
155{
156 struct gprs_ns_inst *nsi = vty_nsi;
157 dump_ns(vty, nsi, 0);
Harald Weltef2b4cd72010-05-13 11:45:07 +0200158 return CMD_SUCCESS;
159}
160
Harald Welte73b23592010-05-13 12:32:30 +0200161DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats",
162 SHOW_STR
163 "Display information about the NS protocol\n"
164 "Include statistics\n")
165{
166 struct gprs_ns_inst *nsi = vty_nsi;
167 dump_ns(vty, nsi, 1);
168 return CMD_SUCCESS;
169}
Harald Weltef2b4cd72010-05-13 11:45:07 +0200170
Harald Welte55c91e42010-05-15 23:04:03 +0200171DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
172 SHOW_STR "Display information about the NS protocol\n"
173 "Select one NSE by its NSE Identifier\n"
174 "Select one NSE by its NS-VC Identifier\n"
175 "The Identifier of selected type\n"
176 "Include Statistics\n")
177{
178 struct gprs_ns_inst *nsi = vty_nsi;
179 struct gprs_nsvc *nsvc;
180 uint16_t id = atoi(argv[1]);
181 int show_stats = 0;
182
183 if (!strcmp(argv[0], "nsei"))
184 nsvc = nsvc_by_nsei(nsi, id);
185 else
186 nsvc = nsvc_by_nsvci(nsi, id);
187
188 if (!nsvc) {
189 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
190 return CMD_WARNING;
191 }
192
193 if (argc >= 3)
194 show_stats = 1;
195
196 dump_nse(vty, nsvc, show_stats);
197 return CMD_SUCCESS;
198}
199
Harald Welte52613a12010-05-15 23:06:26 +0200200#define NSE_CMD_STR "Persistent NS Entity\n" "NS Entity ID (NSEI)\n"
Harald Weltef2b4cd72010-05-13 11:45:07 +0200201
202DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,
203 "nse <0-65535> nsvci <0-65534>",
204 NSE_CMD_STR
205 "NS Virtual Connection\n"
206 "NS Virtual Connection ID (NSVCI)\n"
207 )
208{
209 uint16_t nsei = atoi(argv[0]);
210 uint16_t nsvci = atoi(argv[1]);
211 struct gprs_nsvc *nsvc;
212
213 nsvc = nsvc_by_nsei(vty_nsi, nsei);
214 if (!nsvc) {
215 nsvc = nsvc_create(vty_nsi, nsvci);
216 nsvc->nsei = nsei;
217 }
218 nsvc->nsvci = nsvci;
219 /* All NSVCs that are explicitly configured by VTY are
220 * marked as persistent so we can write them to the config
221 * file at some later point */
222 nsvc->persistent = 1;
223
224 return CMD_SUCCESS;
225}
226
227DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd,
228 "nse <0-65535> remote-ip A.B.C.D",
229 NSE_CMD_STR
230 "Remote IP Address\n"
231 "Remote IP Address\n")
232{
233 uint16_t nsei = atoi(argv[0]);
234 struct gprs_nsvc *nsvc;
235
236 nsvc = nsvc_by_nsei(vty_nsi, nsei);
237 if (!nsvc) {
238 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
239 return CMD_WARNING;
240 }
241 inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr);
242
243 return CMD_SUCCESS;
244
245}
246
247DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd,
248 "nse <0-65535> remote-port <0-65535>",
249 NSE_CMD_STR
250 "Remote UDP Port\n"
251 "Remote UDP Port Number\n")
252{
253 uint16_t nsei = atoi(argv[0]);
254 uint16_t port = atoi(argv[1]);
255 struct gprs_nsvc *nsvc;
256
257 nsvc = nsvc_by_nsei(vty_nsi, nsei);
258 if (!nsvc) {
259 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
260 return CMD_WARNING;
261 }
262
Harald Welte5540c4c2010-05-19 14:38:50 +0200263 if (nsvc->ll != GPRS_NS_LL_UDP) {
264 vty_out(vty, "Cannot set UDP Port on non-UDP NSE%s",
265 VTY_NEWLINE);
266 return CMD_WARNING;
267 }
268
Harald Weltef2b4cd72010-05-13 11:45:07 +0200269 nsvc->ip.bts_addr.sin_port = htons(port);
270
271 return CMD_SUCCESS;
272}
273
Harald Welte5540c4c2010-05-19 14:38:50 +0200274DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd,
275 "nse <0-65535> fr-dlci <0-1023>",
276 NSE_CMD_STR
277 "Frame Relay DLCI\n"
278 "Frame Relay DLCI Number\n")
279{
280 uint16_t nsei = atoi(argv[0]);
281 uint16_t dlci = atoi(argv[1]);
282 struct gprs_nsvc *nsvc;
283
284 nsvc = nsvc_by_nsei(vty_nsi, nsei);
285 if (!nsvc) {
286 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
287 return CMD_WARNING;
288 }
289
290 if (nsvc->ll != GPRS_NS_LL_FR_GRE) {
291 vty_out(vty, "Cannot set FR DLCI on non-FR NSE%s",
292 VTY_NEWLINE);
293 return CMD_WARNING;
294 }
295
296 nsvc->frgre.bts_addr.sin_port = htons(dlci);
297
298 return CMD_SUCCESS;
299}
300
301DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd,
302 "nse <0-65535> encapsulation (udp|framerelay-gre)",
303 NSE_CMD_STR
304 "Encapsulation for NS\n"
305 "UDP/IP Encapsulation\n" "Frame-Relay/GRE/IP Encapsulation\n")
306{
307 uint16_t nsei = atoi(argv[0]);
308 struct gprs_nsvc *nsvc;
309
310 nsvc = nsvc_by_nsei(vty_nsi, nsei);
311 if (!nsvc) {
312 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
313 return CMD_WARNING;
314 }
315
316 if (!strcmp(argv[1], "udp"))
317 nsvc->ll = GPRS_NS_LL_UDP;
318 else
319 nsvc->ll = GPRS_NS_LL_FR_GRE;
320
321 return CMD_SUCCESS;
322}
323
324
Harald Weltef2b4cd72010-05-13 11:45:07 +0200325DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,
326 "nse <0-65535> remote-role (sgsn|bss)",
327 NSE_CMD_STR
328 "Remote NSE Role\n"
329 "Remote Peer is SGSN\n"
330 "Remote Peer is BSS\n")
331{
332 uint16_t nsei = atoi(argv[0]);
333 struct gprs_nsvc *nsvc;
334
335 nsvc = nsvc_by_nsei(vty_nsi, nsei);
336 if (!nsvc) {
337 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
338 return CMD_WARNING;
339 }
340
341 if (!strcmp(argv[1], "sgsn"))
342 nsvc->remote_end_is_sgsn = 1;
343 else
344 nsvc->remote_end_is_sgsn = 0;
345
346 return CMD_SUCCESS;
347}
348
349DEFUN(cfg_no_nse, cfg_no_nse_cmd,
350 "no nse <0-65535>",
Harald Welte52613a12010-05-15 23:06:26 +0200351 "Delete Persistent NS Entity\n"
Harald Weltef2b4cd72010-05-13 11:45:07 +0200352 "Delete " NSE_CMD_STR)
353{
354 uint16_t nsei = atoi(argv[0]);
355 struct gprs_nsvc *nsvc;
356
357 nsvc = nsvc_by_nsei(vty_nsi, nsei);
358 if (!nsvc) {
359 vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE);
360 return CMD_WARNING;
361 }
362
Harald Welte52613a12010-05-15 23:06:26 +0200363 if (!nsvc->persistent) {
364 vty_out(vty, "NSEI %u is not a persistent NSE%s",
365 nsei, VTY_NEWLINE);
366 return CMD_WARNING;
367 }
368
369 nsvc->persistent = 0;
Harald Weltef2b4cd72010-05-13 11:45:07 +0200370
371 return CMD_SUCCESS;
372}
373
374DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
375 "timer " NS_TIMERS " <0-65535>",
376 "Network Service Timer\n"
377 NS_TIMERS_HELP "Timer Value\n")
378{
379 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
380 int val = atoi(argv[1]);
381
382 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
383 return CMD_WARNING;
384
385 vty_nsi->timeout[idx] = val;
386
387 return CMD_SUCCESS;
388}
389
Harald Welte9ef91082010-05-14 19:36:59 +0200390DEFUN(nsvc_nsei, nsvc_nsei_cmd,
391 "nsvc nsei <0-65535> (block|unblock|reset)",
392 "Perform an operation on a NSVC\n"
393 "NS-VC Identifier (NS-VCI)\n"
394 "Initiate BLOCK procedure\n"
395 "Initiate UNBLOCK procedure\n"
396 "Initiate RESET procedure\n")
397{
398 uint16_t nsvci = atoi(argv[0]);
399 const char *operation = argv[1];
400 struct gprs_nsvc *nsvc;
401
402 nsvc = nsvc_by_nsei(vty_nsi, nsvci);
403 if (!nsvc) {
404 vty_out(vty, "No such NSVCI (%u)%s", nsvci, VTY_NEWLINE);
405 return CMD_WARNING;
406 }
407
408 if (!strcmp(operation, "block"))
409 gprs_ns_tx_block(nsvc, NS_CAUSE_OM_INTERVENTION);
410 else if (!strcmp(operation, "unblock"))
411 gprs_ns_tx_unblock(nsvc);
412 else if (!strcmp(operation, "reset"))
413 gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
414 else
415 return CMD_WARNING;
416
417 return CMD_SUCCESS;
418}
419
Harald Welte8be8c8f2010-05-15 23:52:02 +0200420DEFUN(logging_fltr_nsvc,
421 logging_fltr_nsvc_cmd,
422 "logging filter nsvc (nsei|nsvci) <0-65535>",
Harald Welte95647152010-05-16 00:00:04 +0200423 LOGGING_STR FILTER_STR
Harald Welte8be8c8f2010-05-15 23:52:02 +0200424 "Filter based on NS Virtual Connection\n"
425 "Identify NS-VC by NSEI\n"
426 "Identify NS-VC by NSVCI\n"
427 "Numeric identifier\n")
428{
429 struct telnet_connection *conn;
430 struct gprs_nsvc *nsvc;
431 uint16_t id = atoi(argv[1]);
432
433 conn = (struct telnet_connection *) vty->priv;
434 if (!conn->dbg) {
435 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
436 return CMD_WARNING;
437 }
438
439 if (!strcmp(argv[0], "nsei"))
440 nsvc = nsvc_by_nsei(vty_nsi, id);
441 else
442 nsvc = nsvc_by_nsvci(vty_nsi, id);
443
444 if (!nsvc) {
445 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
446 return CMD_WARNING;
447 }
448
449 log_set_nsvc_filter(conn->dbg, nsvc);
450 return CMD_SUCCESS;
451}
Harald Welte9ef91082010-05-14 19:36:59 +0200452
Harald Weltef2b4cd72010-05-13 11:45:07 +0200453int gprs_ns_vty_init(struct gprs_ns_inst *nsi)
454{
455 vty_nsi = nsi;
456
457 install_element_ve(&show_ns_cmd);
Harald Welte73b23592010-05-13 12:32:30 +0200458 install_element_ve(&show_ns_stats_cmd);
Harald Welte55c91e42010-05-15 23:04:03 +0200459 install_element_ve(&show_nse_cmd);
Harald Welte8be8c8f2010-05-15 23:52:02 +0200460 install_element_ve(&logging_fltr_nsvc_cmd);
Harald Weltef2b4cd72010-05-13 11:45:07 +0200461
462 install_element(CONFIG_NODE, &cfg_ns_cmd);
463 install_node(&ns_node, config_write_ns);
464 install_default(NS_NODE);
Harald Welte62ab20c2010-05-14 18:59:17 +0200465 install_element(NS_NODE, &ournode_exit_cmd);
Harald Welte54f74242010-05-14 19:11:04 +0200466 install_element(NS_NODE, &ournode_end_cmd);
Harald Weltef2b4cd72010-05-13 11:45:07 +0200467 install_element(NS_NODE, &cfg_nse_nsvci_cmd);
468 install_element(NS_NODE, &cfg_nse_remoteip_cmd);
469 install_element(NS_NODE, &cfg_nse_remoteport_cmd);
Harald Welte5540c4c2010-05-19 14:38:50 +0200470 install_element(NS_NODE, &cfg_nse_fr_dlci_cmd);
471 install_element(NS_NODE, &cfg_nse_encaps_cmd);
Harald Weltef2b4cd72010-05-13 11:45:07 +0200472 install_element(NS_NODE, &cfg_nse_remoterole_cmd);
473 install_element(NS_NODE, &cfg_no_nse_cmd);
474 install_element(NS_NODE, &cfg_ns_timer_cmd);
475
Harald Welte9ef91082010-05-14 19:36:59 +0200476 install_element(ENABLE_NODE, &nsvc_nsei_cmd);
477
Harald Weltef2b4cd72010-05-13 11:45:07 +0200478 return 0;
479}