blob: 1738e709bedad90212c3b4b748d740ae4fb9d3c3 [file] [log] [blame]
Harald Weltedda21ed2017-08-12 15:07:02 +02001/*
2 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20#include <string.h>
21#include <stdint.h>
22#include <inttypes.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25
26#include <osmocom/core/talloc.h>
27#include <osmocom/core/utils.h>
28#include <osmocom/core/rate_ctr.h>
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +070029#include <osmocom/gsm/apn.h>
Vadim Yanitskiyfb625042019-05-19 02:00:31 +070030#include <osmocom/gsm/gsm48_ie.h>
Harald Weltedda21ed2017-08-12 15:07:02 +020031#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
32
33#include <osmocom/vty/command.h>
34#include <osmocom/vty/vty.h>
35#include <osmocom/vty/misc.h>
36
37#include "../gtp/gtp.h"
38#include "../gtp/pdp.h"
39
Pau Espin Pedrolf612ffe2019-08-20 13:24:55 +020040#include "../lib/util.h"
41
Harald Weltedda21ed2017-08-12 15:07:02 +020042#include "ggsn.h"
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +020043#include "sgsn.h"
Harald Weltedda21ed2017-08-12 15:07:02 +020044
45#define PREFIX_STR "Prefix (Network/Netmask)\n"
46#define IFCONFIG_STR "GGSN-based interface configuration\n"
47#define GGSN_STR "Gateway GPRS Support NODE (GGSN)\n"
48
49LLIST_HEAD(g_ggsn_list);
50
51enum ggsn_vty_node {
52 GGSN_NODE = _LAST_OSMOVTY_NODE + 1,
53 APN_NODE,
54};
55
56struct ggsn_ctx *ggsn_find(const char *name)
57{
58 struct ggsn_ctx *ggsn;
59
60 llist_for_each_entry(ggsn, &g_ggsn_list, list) {
61 if (!strcmp(ggsn->cfg.name, name))
62 return ggsn;
63 }
64 return NULL;
65}
66
67struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name)
68{
69 struct ggsn_ctx *ggsn;
70
71 ggsn = ggsn_find(name);
72 if (ggsn)
73 return ggsn;
74
75 ggsn = talloc_zero(ctx, struct ggsn_ctx);
76 if (!ggsn)
77 return NULL;
78
79 ggsn->cfg.name = talloc_strdup(ggsn, name);
80 ggsn->cfg.state_dir = talloc_strdup(ggsn, "/tmp");
81 ggsn->cfg.shutdown = true;
82 INIT_LLIST_HEAD(&ggsn->apn_list);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +020083 INIT_LLIST_HEAD(&ggsn->sgsn_list);
Harald Weltedda21ed2017-08-12 15:07:02 +020084
85 llist_add_tail(&ggsn->list, &g_ggsn_list);
86 return ggsn;
87}
88
89struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name)
90{
91 struct apn_ctx *apn;
92
93 llist_for_each_entry(apn, &ggsn->apn_list, list) {
94 if (!strcmp(apn->cfg.name, name))
95 return apn;
96 }
97 return NULL;
98}
99
100struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name)
101{
102 struct apn_ctx *apn = ggsn_find_apn(ggsn, name);
103 if (apn)
104 return apn;
105
106 apn = talloc_zero(ggsn, struct apn_ctx);
107 if (!apn)
108 return NULL;
109 apn->ggsn = ggsn;
110 apn->cfg.name = talloc_strdup(apn, name);
111 apn->cfg.shutdown = true;
Harald Welte93fed3b2017-09-24 11:43:17 +0800112 apn->cfg.tx_gpdu_seq = true;
Harald Weltedda21ed2017-08-12 15:07:02 +0200113 INIT_LLIST_HEAD(&apn->cfg.name_list);
114
115 llist_add_tail(&apn->list, &ggsn->apn_list);
116 return apn;
117}
118
119/* GGSN Node */
120
121static struct cmd_node ggsn_node = {
122 GGSN_NODE,
123 "%s(config-ggsn)# ",
124 1,
125};
126
127DEFUN(cfg_ggsn, cfg_ggsn_cmd,
128 "ggsn NAME",
129 "Configure the Gateway GPRS Support Node\n" "GGSN Name (has only local significance)\n")
130{
131 struct ggsn_ctx *ggsn;
132
133 ggsn = ggsn_find_or_create(tall_ggsn_ctx, argv[0]);
134 if (!ggsn)
135 return CMD_WARNING;
136
137 vty->node = GGSN_NODE;
138 vty->index = ggsn;
139 vty->index_sub = &ggsn->cfg.description;
140
141 return CMD_SUCCESS;
142}
143
144DEFUN(cfg_no_ggsn, cfg_no_ggsn_cmd,
145 "no ggsn NAME",
146 NO_STR "Remove the named Gateway GPRS Support Node\n"
147 "GGSN Name (has only local significance)\n")
148{
149 struct ggsn_ctx *ggsn;
150
151 ggsn = ggsn_find(argv[0]);
152 if (!ggsn) {
153 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
154 return CMD_WARNING;
155 }
156
157 if (!ggsn->cfg.shutdown) {
158 vty_out(vty, "%% GGSN %s is still active, please shutdown first%s",
159 ggsn->cfg.name, VTY_NEWLINE);
160 return CMD_WARNING;
161 }
162
163 if (!llist_empty(&ggsn->apn_list)) {
164 vty_out(vty, "%% GGSN %s still has APNs configured, please remove first%s",
165 ggsn->cfg.name, VTY_NEWLINE);
166 return CMD_WARNING;
167 }
168
169 llist_del(&ggsn->list);
170 talloc_free(ggsn);
171
172 return CMD_SUCCESS;
173}
174
Harald Welte98146772017-09-05 17:41:20 +0200175DEFUN(cfg_ggsn_bind_ip, cfg_ggsn_bind_ip_cmd,
176 "gtp bind-ip A.B.C.D",
Harald Weltedda21ed2017-08-12 15:07:02 +0200177 "GTP Parameters\n"
178 "Set the IP address for the local GTP bind\n"
179 "IPv4 Address\n")
180{
181 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
182 size_t t;
183
184 ippool_aton(&ggsn->cfg.listen_addr, &t, argv[0], 0);
185
186 return CMD_SUCCESS;
187}
188
Harald Welte98146772017-09-05 17:41:20 +0200189DEFUN(cfg_ggsn_gtpc_ip, cfg_ggsn_gtpc_ip_cmd,
190 "gtp control-ip A.B.C.D",
191 "GTP Parameters\n"
192 "Set the IP address states as local IP in GTP-C messages\n"
193 "IPv4 Address\n")
194{
195 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
196 size_t t;
197
198 ippool_aton(&ggsn->cfg.gtpc_addr, &t, argv[0], 0);
199
200 return CMD_SUCCESS;
201}
202
203DEFUN(cfg_ggsn_gtpu_ip, cfg_ggsn_gtpu_ip_cmd,
204 "gtp user-ip A.B.C.D",
205 "GTP Parameters\n"
206 "Set the IP address states as local IP in GTP-U messages\n"
207 "IPv4 Address\n")
208{
209 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
210 size_t t;
211
212 ippool_aton(&ggsn->cfg.gtpu_addr, &t, argv[0], 0);
213
214 return CMD_SUCCESS;
215}
216
Harald Weltedda21ed2017-08-12 15:07:02 +0200217DEFUN(cfg_ggsn_state_dir, cfg_ggsn_state_dir_cmd,
218 "gtp state-dir PATH",
219 "GTP Parameters\n"
220 "Set the directory for the GTP State file\n"
221 "Local Directory\n")
222{
223 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
224
225 osmo_talloc_replace_string(ggsn, &ggsn->cfg.state_dir, argv[0]);
226
227 return CMD_SUCCESS;
228}
229
230DEFUN(cfg_ggsn_apn, cfg_ggsn_apn_cmd,
231 "apn NAME", "APN Configuration\n" "APN Name\n")
232{
233 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
234 struct apn_ctx *apn;
235
236 apn = ggsn_find_or_create_apn(ggsn, argv[0]);
237 if (!apn)
238 return CMD_WARNING;
239
240 vty->node = APN_NODE;
241 vty->index = apn;
242 vty->index_sub = &ggsn->cfg.description;
243
244 return CMD_SUCCESS;
245}
246
247DEFUN(cfg_ggsn_no_apn, cfg_ggsn_no_apn_cmd,
248 "no apn NAME",
249 NO_STR "Remove APN Configuration\n" "APN Name\n")
250{
251 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
252 struct apn_ctx *apn;
253
254 apn = ggsn_find_apn(ggsn, argv[0]);
255 if (!apn) {
256 vty_out(vty, "%% No such APN '%s'%s", argv[0], VTY_NEWLINE);
257 return CMD_WARNING;
258 }
259
260 if (!apn->cfg.shutdown) {
261 vty_out(vty, "%% APN %s still active, please shutdown first%s",
262 apn->cfg.name, VTY_NEWLINE);
263 return CMD_WARNING;
264 }
265
266 llist_del(&apn->list);
267 talloc_free(apn);
268
269 return CMD_SUCCESS;
270}
271
272DEFUN(cfg_ggsn_default_apn, cfg_ggsn_default_apn_cmd,
273 "default-apn NAME",
274 "Set a default-APN to be used if no other APN matches\n"
275 "APN Name\n")
276{
277 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
278 struct apn_ctx *apn;
279
280 apn = ggsn_find_apn(ggsn, argv[0]);
281 if (!apn) {
282 vty_out(vty, "%% No APN of name '%s' found%s", argv[0], VTY_NEWLINE);
283 return CMD_WARNING;
284 }
285
286 ggsn->cfg.default_apn = apn;
287 return CMD_SUCCESS;
288}
289
290DEFUN(cfg_ggsn_no_default_apn, cfg_ggsn_no_default_apn_cmd,
291 "no default-apn",
292 NO_STR "Remove default-APN to be used if no other APN matches\n")
293{
294 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
295 ggsn->cfg.default_apn = NULL;
296 return CMD_SUCCESS;
297}
298
299DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd,
300 "shutdown ggsn",
301 "Put the GGSN in administrative shut-down\n" GGSN_STR)
302{
303 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
304
305 if (!ggsn->cfg.shutdown) {
306 if (ggsn_stop(ggsn)) {
307 vty_out(vty, "%% Failed to shutdown GGSN%s", VTY_NEWLINE);
308 return CMD_WARNING;
309 }
310 ggsn->cfg.shutdown = true;
311 }
312
313 return CMD_SUCCESS;
314}
315
316DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd,
317 "no shutdown ggsn",
318 NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
319{
320 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
321
322 if (ggsn->cfg.shutdown) {
323 if (ggsn_start(ggsn) < 0) {
324 vty_out(vty, "%% Failed to start GGSN, check log for details%s", VTY_NEWLINE);
325 return CMD_WARNING;
326 }
327 ggsn->cfg.shutdown = false;
328 }
329
330 return CMD_SUCCESS;
331}
332
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200333static void show_one_sgsn(struct vty *vty, const struct sgsn_peer *sgsn, const char* prefix)
334{
335 char buf[INET_ADDRSTRLEN];
336
337 inet_ntop(AF_INET, &sgsn->addr, buf, sizeof(buf));
338 vty_out(vty, "%s(S)GSN %s%s", prefix, buf, VTY_NEWLINE);
339 vty_out(vty, "%s Restart Counter: %d%s", prefix, sgsn->remote_restart_ctr, VTY_NEWLINE);
340 vty_out(vty, "%s PDP contexts: %d%s", prefix, llist_count(&sgsn->pdp_list), VTY_NEWLINE);
341 vty_out(vty, "%s Echo Requests in-flight: %u%s", prefix, sgsn->tx_msgs_queued, VTY_NEWLINE);
342}
343
344DEFUN(cfg_ggsn_show_sgsn, cfg_ggsn_show_sgsn_cmd,
345 "show sgsn",
346 NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
347{
348 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
349 struct sgsn_peer *sgsn;
350
351 llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry) {
352 show_one_sgsn(vty, sgsn, "");
353 }
354
355 return CMD_SUCCESS;
356}
357
358/* Seee 3GPP TS 29.060 section 7.2.1 */
359DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
360 "echo-interval <1-36000>",
361 GGSN_STR "GGSN Number\n"
362 "Send an echo request to this static GGSN every interval\n"
363 "Interval between echo requests in seconds\n")
364{
365 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
366 int prev_interval = ggsn->cfg.echo_interval;
367 struct sgsn_peer *sgsn;
368
369 ggsn->cfg.echo_interval = atoi(argv[0]);
370
371 if (ggsn->cfg.echo_interval < 60)
372 vty_out(vty, "%% 3GPP TS 29.060 section states interval should " \
373 "not be lower than 60 seconds, use this value for " \
374 "testing purposes only!%s", VTY_NEWLINE);
375
376 if (prev_interval == ggsn->cfg.echo_interval)
377 return CMD_SUCCESS;
378
379 /* Re-enable echo timer for all sgsn */
380 llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry)
381 sgsn_echo_timer_start(sgsn);
382
383 return CMD_SUCCESS;
384}
385
386DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
387 "no echo-interval",
388 GGSN_STR "GGSN Number\n"
389 NO_STR "Send an echo request to this static GGSN every interval.\n")
390{
391 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
392 int prev_interval = ggsn->cfg.echo_interval;
393 struct sgsn_peer *sgsn;
394
395 if (prev_interval == ggsn->cfg.echo_interval)
396 return CMD_SUCCESS;
397
398 ggsn->cfg.echo_interval = 0;
399
400 /* Disable echo timer for all sgsn */
401 llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry)
402 sgsn_echo_timer_stop(sgsn);
403
404 return CMD_SUCCESS;
405}
406
Harald Weltedda21ed2017-08-12 15:07:02 +0200407/* APN Node */
408
409static struct cmd_node apn_node = {
410 APN_NODE,
411 "%s(config-ggsn-apn)# ",
412 1,
413};
414
415static const struct value_string pdp_type_names[] = {
416 { APN_TYPE_IPv4, "v4" },
417 { APN_TYPE_IPv6, "v6" },
418 { APN_TYPE_IPv4v6, "v4v6" },
419 { 0, NULL }
420};
421
422static const struct value_string apn_gtpu_mode_names[] = {
423 { APN_GTPU_MODE_TUN, "tun" },
424 { APN_GTPU_MODE_KERNEL_GTP, "kernel-gtp" },
425 { 0, NULL }
426};
427
428
429#define V4V6V46_STRING "IPv4(-only) PDP Type\n" \
430 "IPv6(-only) PDP Type\n" \
431 "IPv4v6 (dual-stack) PDP Type\n"
432
433DEFUN(cfg_apn_type_support, cfg_apn_type_support_cmd,
434 "type-support (v4|v6|v4v6)",
435 "Enable support for PDP Type\n"
436 V4V6V46_STRING)
437{
438 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
439 uint32_t type = get_string_value(pdp_type_names, argv[0]);
440
441 apn->cfg.apn_type_mask |= type;
442 return CMD_SUCCESS;
443}
444
445DEFUN(cfg_apn_no_type_support, cfg_apn_no_type_support_cmd,
446 "no type-support (v4|v6|v4v6)",
447 NO_STR "Disable support for PDP Type\n"
448 V4V6V46_STRING)
449{
450 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
451 uint32_t type = get_string_value(pdp_type_names, argv[0]);
452
453 apn->cfg.apn_type_mask &= ~type;
454 return CMD_SUCCESS;
455}
456
457DEFUN(cfg_apn_gtpu_mode, cfg_apn_gtpu_mode_cmd,
458 "gtpu-mode (tun|kernel-gtp)",
459 "Set the Mode for this APN (tun or Linux Kernel GTP)\n"
460 "GTP-U in userspace using TUN device\n"
461 "GTP-U in kernel using Linux Kernel GTP\n")
462{
463 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
464
465 apn->cfg.gtpu_mode = get_string_value(apn_gtpu_mode_names, argv[0]);
466 return CMD_SUCCESS;
467}
468
469DEFUN(cfg_apn_tun_dev_name, cfg_apn_tun_dev_name_cmd,
470 "tun-device NAME",
471 "Configure tun device name\n"
472 "TUN device name")
473{
474 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
475 osmo_talloc_replace_string(apn, &apn->tun.cfg.dev_name, argv[0]);
476 return CMD_SUCCESS;
477}
478
479DEFUN(cfg_apn_ipup_script, cfg_apn_ipup_script_cmd,
480 "ipup-script PATH",
481 "Configure name/path of ip-up script\n"
482 "File/Path name of ip-up script\n")
483{
484 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
485 osmo_talloc_replace_string(apn, &apn->tun.cfg.ipup_script, argv[0]);
486 return CMD_SUCCESS;
487}
488
489DEFUN(cfg_apn_no_ipup_script, cfg_apn_no_ipup_script_cmd,
490 "no ipup-script",
491 NO_STR "Disable ip-up script\n")
492{
493 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
494 talloc_free(apn->tun.cfg.ipup_script);
495 apn->tun.cfg.ipup_script = NULL;
496 return CMD_SUCCESS;
497}
498
499DEFUN(cfg_apn_ipdown_script, cfg_apn_ipdown_script_cmd,
500 "ipdown-script PATH",
501 "Configure name/path of ip-down script\n"
502 "File/Path name of ip-down script\n")
503{
504 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
505 osmo_talloc_replace_string(apn, &apn->tun.cfg.ipdown_script, argv[0]);
506 return CMD_SUCCESS;
507}
508
509/* convert prefix from "A.B.C.D/M" notation to in46_prefix */
510static void str2prefix(struct in46_prefix *pfx, const char *in)
511{
512 size_t t;
513
514 ippool_aton(&pfx->addr, &t, in, 0);
515 pfx->prefixlen = t;
516}
517
518DEFUN(cfg_apn_no_ipdown_script, cfg_apn_no_ipdown_script_cmd,
519 "no ipdown-script",
520 NO_STR "Disable ip-down script\n")
521{
522 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
523 talloc_free(apn->tun.cfg.ipdown_script);
524 apn->tun.cfg.ipdown_script = NULL;
525 return CMD_SUCCESS;
526}
527
528DEFUN(cfg_apn_ip_prefix, cfg_apn_ip_prefix_cmd,
529 "ip prefix (static|dynamic) A.B.C.D/M",
530 IP_STR PREFIX_STR "IPv4 Adress/Prefix-Length\n")
531{
532 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
533 struct in46_prefix *pfx;
534
535 /* first update our parsed prefix */
Harald Welte53792732021-03-27 19:03:30 +0100536 if (!strcmp(argv[0], "static")) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200537 pfx = &apn->v4.cfg.static_prefix;
Harald Welte53792732021-03-27 19:03:30 +0100538 vty_out(vty, "%% static IP addresses currently not yet supported%s", VTY_NEWLINE);
539 return CMD_WARNING;
540 } else
Harald Weltedda21ed2017-08-12 15:07:02 +0200541 pfx = &apn->v4.cfg.dynamic_prefix;
542 str2prefix(pfx, argv[1]);
543
544 return CMD_SUCCESS;
545}
546
547DEFUN(cfg_apn_ip_ifconfig, cfg_apn_ip_ifconfig_cmd,
548 "ip ifconfig A.B.C.D/M",
549 IP_STR IFCONFIG_STR "IPv4 Adress/Prefix-Length\n")
550{
551 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
552 str2prefix(&apn->v4.cfg.ifconfig_prefix, argv[0]);
553 return CMD_SUCCESS;
554}
555
556DEFUN(cfg_apn_no_ip_ifconfig, cfg_apn_no_ip_ifconfig_cmd,
557 "no ip ifconfig",
558 NO_STR IP_STR IFCONFIG_STR)
559{
560 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
561 memset(&apn->v4.cfg.ifconfig_prefix, 0, sizeof(apn->v4.cfg.ifconfig_prefix));
562 return CMD_SUCCESS;
563}
564
565DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd,
566 "ipv6 prefix (static|dynamic) X:X::X:X/M",
567 IP6_STR PREFIX_STR "IPv6 Address/Prefix-Length\n")
568{
569 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
570 struct in46_prefix *pfx;
571
Harald Welte53792732021-03-27 19:03:30 +0100572 if (!strcmp(argv[0], "static")) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200573 pfx = &apn->v6.cfg.static_prefix;
Harald Welte53792732021-03-27 19:03:30 +0100574 vty_out(vty, "%% static IP addresses currently not yet supported%s", VTY_NEWLINE);
575 return CMD_WARNING;
576 } else
Harald Weltedda21ed2017-08-12 15:07:02 +0200577 pfx = &apn->v6.cfg.dynamic_prefix;
578 str2prefix(pfx, argv[1]);
579 return CMD_SUCCESS;
580}
581
582DEFUN(cfg_apn_ipv6_ifconfig, cfg_apn_ipv6_ifconfig_cmd,
583 "ipv6 ifconfig X:X::X:X/M",
584 IP6_STR IFCONFIG_STR "IPv6 Adress/Prefix-Length\n")
585{
586 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
587 str2prefix(&apn->v6.cfg.ifconfig_prefix, argv[0]);
588 return CMD_SUCCESS;
589}
590
591DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd,
592 "no ipv6 ifconfig",
593 NO_STR IP6_STR IFCONFIG_STR)
594{
595 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
596 memset(&apn->v6.cfg.ifconfig_prefix, 0, sizeof(apn->v6.cfg.ifconfig_prefix));
597 return CMD_SUCCESS;
598}
599
Pau Espin Pedrol37c45e32017-12-14 14:09:13 +0100600DEFUN(cfg_apn_ipv6_linklocal, cfg_apn_ipv6_linklocal_cmd,
601 "ipv6 link-local X:X::X:X/M",
602 IP6_STR IFCONFIG_STR "IPv6 Link-local Adress/Prefix-Length\n")
603{
604 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
605 str2prefix(&apn->v6.cfg.ll_prefix, argv[0]);
606 return CMD_SUCCESS;
607}
608
609DEFUN(cfg_apn_no_ipv6_linklocal, cfg_apn_no_ipv6_linklocal_cmd,
610 "no ipv6 link-local",
611 NO_STR IP6_STR IFCONFIG_STR)
612{
613 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
614 memset(&apn->v6.cfg.ll_prefix, 0, sizeof(apn->v6.cfg.ll_prefix));
615 return CMD_SUCCESS;
616}
617
Harald Weltedda21ed2017-08-12 15:07:02 +0200618#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
619
620DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
621 "ip dns <0-1> A.B.C.D",
622 IP_STR DNS_STRINGS)
623{
624 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
625 int idx = atoi(argv[0]);
626 size_t dummy;
627
628 ippool_aton(&apn->v4.cfg.dns[idx], &dummy, argv[1], 0);
629
630 return CMD_SUCCESS;
631}
632
633DEFUN(cfg_apn_ipv6_dns, cfg_apn_ipv6_dns_cmd,
634 "ipv6 dns <0-1> X:X::X:X",
635 IP6_STR DNS_STRINGS)
636{
637 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
638 int idx = atoi(argv[0]);
639 size_t dummy;
640
641 ippool_aton(&apn->v6.cfg.dns[idx], &dummy, argv[1], 0);
642
643 return CMD_SUCCESS;
644}
645
646DEFUN(cfg_apn_no_dns, cfg_apn_no_dns_cmd,
647 "no (ip|ipv6) dns <0-1>",
648 NO_STR IP_STR IP6_STR "Disable DNS Server\n" "primary/secondary DNS\n")
649{
650 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
651 struct in46_addr *a;
652 int idx = atoi(argv[1]);
653
654 if (!strcmp(argv[0], "ip"))
655 a = &apn->v4.cfg.dns[idx];
656 else
657 a = &apn->v6.cfg.dns[idx];
658
659 memset(a, 0, sizeof(*a));
660
661 return CMD_SUCCESS;
662}
663
Harald Welte93fed3b2017-09-24 11:43:17 +0800664DEFUN(cfg_apn_gpdu_seq, cfg_apn_gpdu_seq_cmd,
665 "g-pdu tx-sequence-numbers",
666 "G-PDU Configuration\n" "Enable transmission of G-PDU sequence numbers\n")
667{
668 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
669 apn->cfg.tx_gpdu_seq = true;
670 return CMD_SUCCESS;
671}
672
673DEFUN(cfg_apn_no_gpdu_seq, cfg_apn_no_gpdu_seq_cmd,
674 "no g-pdu tx-sequence-numbers",
675 NO_STR "G-PDU Configuration\n" "Disable transmission of G-PDU sequence numbers\n")
676{
677 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
678 apn->cfg.tx_gpdu_seq = false;
679 return CMD_SUCCESS;
680}
681
Harald Weltedda21ed2017-08-12 15:07:02 +0200682DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
683 "shutdown",
684 "Put the APN in administrative shut-down\n")
685{
686 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
687
688 if (!apn->cfg.shutdown) {
Pau Espin Pedrol72ab4bc2019-05-29 19:08:26 +0200689 if (apn_stop(apn)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200690 vty_out(vty, "%% Failed to Stop APN%s", VTY_NEWLINE);
691 return CMD_WARNING;
692 }
693 apn->cfg.shutdown = true;
694 }
695
696 return CMD_SUCCESS;
697}
698
699DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd,
700 "no shutdown",
701 NO_STR "Remove the APN from administrative shut-down\n")
702{
703 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
704
705 if (apn->cfg.shutdown) {
Oliver Smith02a82c32021-02-05 14:15:20 +0100706 if (!apn->tun.cfg.dev_name) {
707 vty_out(vty, "%% Failed to start APN, tun-device is not configured%s", VTY_NEWLINE);
708 return CMD_WARNING;
709 }
Harald Weltedda21ed2017-08-12 15:07:02 +0200710 if (apn_start(apn) < 0) {
711 vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
712 return CMD_WARNING;
713 }
714 apn->cfg.shutdown = false;
715 }
716
717 return CMD_SUCCESS;
718}
719
720
721static void vty_dump_prefix(struct vty *vty, const char *pre, const struct in46_prefix *pfx)
722{
723 vty_out(vty, "%s %s%s", pre, in46p_ntoa(pfx), VTY_NEWLINE);
724}
725
726static void config_write_apn(struct vty *vty, struct apn_ctx *apn)
727{
728 unsigned int i;
729
730 vty_out(vty, " apn %s%s", apn->cfg.name, VTY_NEWLINE);
731 if (apn->cfg.description)
732 vty_out(vty, " description %s%s", apn->cfg.description, VTY_NEWLINE);
733 vty_out(vty, " gtpu-mode %s%s", get_value_string(apn_gtpu_mode_names, apn->cfg.gtpu_mode),
734 VTY_NEWLINE);
735 if (apn->tun.cfg.dev_name)
736 vty_out(vty, " tun-device %s%s", apn->tun.cfg.dev_name, VTY_NEWLINE);
737 if (apn->tun.cfg.ipup_script)
738 vty_out(vty, " ipup-script %s%s", apn->tun.cfg.ipup_script, VTY_NEWLINE);
739 if (apn->tun.cfg.ipdown_script)
740 vty_out(vty, " ipdown-script %s%s", apn->tun.cfg.ipdown_script, VTY_NEWLINE);
741
742 for (i = 0; i < 32; i++) {
Pau Espin Pedrol55600012019-05-30 17:29:09 +0200743 if (!(apn->cfg.apn_type_mask & (UINT32_C(1) << i)))
Harald Weltedda21ed2017-08-12 15:07:02 +0200744 continue;
Pau Espin Pedrol55600012019-05-30 17:29:09 +0200745 vty_out(vty, " type-support %s%s", get_value_string(pdp_type_names, (UINT32_C(1) << i)),
Harald Weltedda21ed2017-08-12 15:07:02 +0200746 VTY_NEWLINE);
747 }
748
Harald Welte93fed3b2017-09-24 11:43:17 +0800749 if (!apn->cfg.tx_gpdu_seq)
750 vty_out(vty, " no g-pdu tx-sequence-numbers%s", VTY_NEWLINE);
751
Harald Weltedda21ed2017-08-12 15:07:02 +0200752 /* IPv4 prefixes + DNS */
753 if (apn->v4.cfg.static_prefix.addr.len)
754 vty_dump_prefix(vty, " ip prefix static", &apn->v4.cfg.static_prefix);
755 if (apn->v4.cfg.dynamic_prefix.addr.len)
756 vty_dump_prefix(vty, " ip prefix dynamic", &apn->v4.cfg.dynamic_prefix);
757 for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
758 if (!apn->v4.cfg.dns[i].len)
759 continue;
760 vty_out(vty, " ip dns %u %s%s", i, in46a_ntoa(&apn->v4.cfg.dns[i]), VTY_NEWLINE);
761 }
762 if (apn->v4.cfg.ifconfig_prefix.addr.len)
Harald Welteff438172017-09-24 22:48:46 +0800763 vty_dump_prefix(vty, " ip ifconfig", &apn->v4.cfg.ifconfig_prefix);
Harald Weltedda21ed2017-08-12 15:07:02 +0200764
765 /* IPv6 prefixes + DNS */
766 if (apn->v6.cfg.static_prefix.addr.len)
767 vty_dump_prefix(vty, " ipv6 prefix static", &apn->v6.cfg.static_prefix);
768 if (apn->v6.cfg.dynamic_prefix.addr.len)
769 vty_dump_prefix(vty, " ipv6 prefix dynamic", &apn->v6.cfg.dynamic_prefix);
770 for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
771 if (!apn->v6.cfg.dns[i].len)
772 continue;
Harald Welte3ca419a2017-09-24 22:47:51 +0800773 vty_out(vty, " ipv6 dns %u %s%s", i, in46a_ntoa(&apn->v6.cfg.dns[i]), VTY_NEWLINE);
Harald Weltedda21ed2017-08-12 15:07:02 +0200774 }
775 if (apn->v6.cfg.ifconfig_prefix.addr.len)
Harald Welteff438172017-09-24 22:48:46 +0800776 vty_dump_prefix(vty, " ipv6 ifconfig", &apn->v6.cfg.ifconfig_prefix);
Pau Espin Pedrole5a082d2017-12-15 15:55:04 +0100777 if (apn->v6.cfg.ll_prefix.addr.len)
778 vty_dump_prefix(vty, " ipv6 link-local", &apn->v6.cfg.ll_prefix);
Harald Weltedda21ed2017-08-12 15:07:02 +0200779
780 /* must be last */
781 vty_out(vty, " %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
782}
783
784static int config_write_ggsn(struct vty *vty)
785{
786 struct ggsn_ctx *ggsn;
787
788 llist_for_each_entry(ggsn, &g_ggsn_list, list) {
789 struct apn_ctx *apn;
790 vty_out(vty, "ggsn %s%s", ggsn->cfg.name, VTY_NEWLINE);
791 if (ggsn->cfg.description)
792 vty_out(vty, " description %s%s", ggsn->cfg.description, VTY_NEWLINE);
793 vty_out(vty, " gtp state-dir %s%s", ggsn->cfg.state_dir, VTY_NEWLINE);
Harald Welte98146772017-09-05 17:41:20 +0200794 vty_out(vty, " gtp bind-ip %s%s", in46a_ntoa(&ggsn->cfg.listen_addr), VTY_NEWLINE);
795 if (ggsn->cfg.gtpc_addr.v4.s_addr)
796 vty_out(vty, " gtp control-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpc_addr), VTY_NEWLINE);
797 if (ggsn->cfg.gtpu_addr.v4.s_addr)
798 vty_out(vty, " gtp user-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpu_addr), VTY_NEWLINE);
Harald Weltedda21ed2017-08-12 15:07:02 +0200799 llist_for_each_entry(apn, &ggsn->apn_list, list)
800 config_write_apn(vty, apn);
801 if (ggsn->cfg.default_apn)
802 vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +0200803 if (ggsn->cfg.echo_interval)
804 vty_out(vty, " echo-interval %u%s", ggsn->cfg.echo_interval, VTY_NEWLINE);
Harald Weltedda21ed2017-08-12 15:07:02 +0200805 /* must be last */
806 vty_out(vty, " %sshutdown ggsn%s", ggsn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
807 }
808
809 return 0;
810}
811
812static const char *print_gsnaddr(const struct ul16_t *in)
813{
814 struct in46_addr in46;
815
816 in46.len = in->l;
817 OSMO_ASSERT(in->l <= sizeof(in46.v6));
818 memcpy(&in46.v6, in->v, in->l);
819
820 return in46a_ntoa(&in46);
821}
822
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200823/* Useful for v4v6 APNs, where we first iterate over v4 pool and then over v6
824 pool. param v4only can be used to avoid printing duplicates for pdp context
825 containing both IPv4 and IPv6 addresses. */
826static void show_one_pdp_v4only(struct vty *vty, struct pdp_t *pdp, bool v4only)
Harald Weltedda21ed2017-08-12 15:07:02 +0200827{
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200828 struct ippoolm_t *peer4, *peer6;
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700829 char name_buf[256];
830 char *apn_name;
Vadim Yanitskiyfb625042019-05-19 02:00:31 +0700831 int rc;
832
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200833 peer4 = pdp_get_peer_ipv(pdp, false);
834 peer6 = pdp_get_peer_ipv(pdp, true);
835
836 if (v4only && peer6)
837 return;
838
Vadim Yanitskiyfb625042019-05-19 02:00:31 +0700839 /* Attempt to decode MSISDN */
840 rc = gsm48_decode_bcd_number2(name_buf, sizeof(name_buf),
841 pdp->msisdn.v, pdp->msisdn.l, 0);
Harald Weltedda21ed2017-08-12 15:07:02 +0200842
843 vty_out(vty, "IMSI: %s, NSAPI: %u, MSISDN: %s%s", imsi_gtp2str(&pdp->imsi), pdp->nsapi,
Vadim Yanitskiyfb625042019-05-19 02:00:31 +0700844 rc ? "(NONE)" : name_buf, VTY_NEWLINE);
Harald Weltedda21ed2017-08-12 15:07:02 +0200845
Pau Espin Pedrola0196312019-08-20 19:11:29 +0200846 vty_out(vty, " Version: %d", pdp->version);
847 if (pdp->version == 1) {
848 if (!pdp->secondary) {
849 vty_out(vty, ", Primary, Num Secondaries: %d%s%s",
850 pdp_count_secondary(pdp) - 1, /* primary included in count */
851 pdp->nodata ? ", No User Plane": "",
852 VTY_NEWLINE);
853 } else {
854 vty_out(vty, ", Secondary%s", VTY_NEWLINE);
855 }
856 } else {
857 vty_out(vty, "%s", VTY_NEWLINE);
858 }
859
Harald Weltedda21ed2017-08-12 15:07:02 +0200860 vty_out(vty, " Control: %s:%08x ", print_gsnaddr(&pdp->gsnlc), pdp->teic_own);
861 vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnrc), pdp->teic_gn, VTY_NEWLINE);
862
863 vty_out(vty, " Data: %s:%08x ", print_gsnaddr(&pdp->gsnlu), pdp->teid_own);
864 vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnru), pdp->teid_gn, VTY_NEWLINE);
865
Vadim Yanitskiyd7030d22019-05-13 22:10:24 +0700866 apn_name = osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
867 vty_out(vty, " APN requested: %s%s", apn_name ? name_buf : "(NONE)", VTY_NEWLINE);
868 apn_name = osmo_apn_to_str(name_buf, pdp->apn_use.v, pdp->apn_use.l);
869 vty_out(vty, " APN in use: %s%s", apn_name ? name_buf : "(NONE)", VTY_NEWLINE);
870
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200871 if (peer4)
Pau Espin Pedrol03cce862019-08-20 12:23:14 +0200872 vty_out(vty, " End-User Address (IPv4): %s%s",
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200873 in46a_ntop(&peer4->addr, name_buf, sizeof(name_buf)), VTY_NEWLINE);
874 if (peer6)
Pau Espin Pedrol03cce862019-08-20 12:23:14 +0200875 vty_out(vty, " End-User Address (IPv6): %s%s",
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200876 in46a_ntop(&peer6->addr, name_buf, sizeof(name_buf)), VTY_NEWLINE);
Harald Welte93fed3b2017-09-24 11:43:17 +0800877 vty_out(vty, " Transmit GTP Sequence Number for G-PDU: %s%s",
878 pdp->tx_gpdu_seq ? "Yes" : "No", VTY_NEWLINE);
Harald Weltedda21ed2017-08-12 15:07:02 +0200879}
880
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200881static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
882{
883 show_one_pdp_v4only(vty, pdp, false);
884}
885
Harald Weltedda21ed2017-08-12 15:07:02 +0200886DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
Pau Espin Pedrol7b52f002019-05-31 16:15:16 +0200887 "show pdp-context ggsn NAME imsi IMSI [<0-15>]",
Harald Weltedda21ed2017-08-12 15:07:02 +0200888 SHOW_STR "Display information on PDP Context\n"
Pau Espin Pedrol7b52f002019-05-31 16:15:16 +0200889 GGSN_STR "GGSN Name\n"
Harald Weltedda21ed2017-08-12 15:07:02 +0200890 "PDP contexts for given IMSI\n"
891 "PDP context for given NSAPI\n")
892{
Pau Espin Pedrol7b52f002019-05-31 16:15:16 +0200893 struct ggsn_ctx *ggsn;
894 uint64_t imsi;
Harald Weltedda21ed2017-08-12 15:07:02 +0200895 unsigned int nsapi;
896 struct pdp_t *pdp;
897 int num_found = 0;
898
Pau Espin Pedrol7b52f002019-05-31 16:15:16 +0200899 ggsn = ggsn_find(argv[0]);
900 if (!ggsn) {
901 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
902 return CMD_WARNING;
903 }
904
Keithcbc07bd2020-10-10 12:17:26 +0200905 if (strlen(argv[1]) < 6 || strlen(argv[1]) > 15) {
906 vty_out(vty, "%% Invalid IMSI '%s'%s", argv[1], VTY_NEWLINE);
907 return CMD_WARNING;
908 }
909
Keithfb2a7292020-10-12 15:32:07 +0200910 imsi = gtp_imsi_str2gtp(argv[1]);
Pau Espin Pedrol7b52f002019-05-31 16:15:16 +0200911
912 if (argc > 2) {
913 nsapi = atoi(argv[2]);
Keith080dcfa2020-10-10 15:15:31 +0200914 if (!gtp_pdp_getimsi(ggsn->gsn, &pdp, imsi, nsapi)) {
Harald Weltedda21ed2017-08-12 15:07:02 +0200915 show_one_pdp(vty, pdp);
916 num_found++;
917 }
918 } else {
919 for (nsapi = 0; nsapi < PDP_MAXNSAPI; nsapi++) {
Pau Espin Pedrol7b52f002019-05-31 16:15:16 +0200920 if (gtp_pdp_getimsi(ggsn->gsn, &pdp, imsi, nsapi))
Harald Weltedda21ed2017-08-12 15:07:02 +0200921 continue;
922 show_one_pdp(vty, pdp);
923 num_found++;
924 }
925 }
926 if (num_found == 0) {
927 vty_out(vty, "%% No such PDP context found%s", VTY_NEWLINE);
928 return CMD_WARNING;
929 } else
930 return CMD_SUCCESS;
931}
932
Vadim Yanitskiyca276e02019-05-13 13:06:51 +0700933DEFUN(show_pdpctx_ip, show_pdpctx_ip_cmd,
934 "show pdp-context ggsn NAME ipv4 A.B.C.D",
935 SHOW_STR "Display information on PDP Context\n"
936 GGSN_STR "GGSN Name\n" "IPv4 address type\n" "IP address\n")
937{
938 struct ggsn_ctx *ggsn;
939 struct apn_ctx *apn;
940 unsigned int i;
941
942 ggsn = ggsn_find(argv[0]);
943 if (!ggsn) {
944 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
945 return CMD_WARNING;
946 }
947
948 /* Iterate over all APNs of a given GGSN */
949 llist_for_each_entry(apn, &ggsn->apn_list, list) {
950 struct ippool_t *pool = apn->v4.pool;
951
952 /* In some rare cases, if GGSN fails to init TUN/TAP interfaces
953 * (e.g. due to insufficient permissions), it will continue to
954 * work in such broken state, and pool would be NULL. */
955 if (!pool)
956 continue;
957
958 /* Iterate over all IPv4 pool members */
959 for (i = 0; i < pool->listsize; i++) {
960 struct ippoolm_t *member = &pool->member[i];
961 if (member->inuse == 0)
962 continue;
963 if (strcmp(argv[1], in46a_ntoa(&member->addr)) == 0) {
964 show_one_pdp(vty, member->peer);
965 return CMD_SUCCESS;
966 }
967 }
968 }
969
970 vty_out(vty, "%% No PDP context found for IP '%s'%s", argv[1], VTY_NEWLINE);
971 return CMD_WARNING;
972}
973
Harald Weltedda21ed2017-08-12 15:07:02 +0200974/* show all (active) PDP contexts within a pool */
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200975static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool, bool pdp_v4only)
Harald Weltedda21ed2017-08-12 15:07:02 +0200976{
977 unsigned int i;
978
979 if (!pool)
980 return;
981
982 for (i = 0; i < pool->listsize; i++) {
983 struct ippoolm_t *member = &pool->member[i];
984 if (member->inuse == 0)
985 continue;
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200986 show_one_pdp_v4only(vty, member->peer, pdp_v4only);
Harald Weltedda21ed2017-08-12 15:07:02 +0200987 }
988}
989
990/* show all (active) PDP contexts within an APN */
991static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn)
992{
Pau Espin Pedrol310ea1d2019-08-20 14:15:25 +0200993 ippool_show_pdp_contexts(vty, apn->v4.pool, true);
994 ippool_show_pdp_contexts(vty, apn->v6.pool, false);
Harald Weltedda21ed2017-08-12 15:07:02 +0200995}
996
997DEFUN(show_pdpctx, show_pdpctx_cmd,
Vadim Yanitskiy977b3392019-05-13 15:32:21 +0700998 "show pdp-context ggsn NAME",
Harald Weltedda21ed2017-08-12 15:07:02 +0200999 SHOW_STR "Show PDP Context Information\n"
Vadim Yanitskiy977b3392019-05-13 15:32:21 +07001000 GGSN_STR "GGSN Name\n")
Harald Weltedda21ed2017-08-12 15:07:02 +02001001{
1002 struct ggsn_ctx *ggsn;
1003 struct apn_ctx *apn;
1004
1005 ggsn = ggsn_find(argv[0]);
1006 if (!ggsn) {
1007 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
1008 return CMD_WARNING;
1009 }
Vadim Yanitskiy977b3392019-05-13 15:32:21 +07001010
1011 llist_for_each_entry(apn, &ggsn->apn_list, list)
Harald Weltedda21ed2017-08-12 15:07:02 +02001012 apn_show_pdp_contexts(vty, apn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001013
1014 return CMD_SUCCESS;
1015}
1016
Vadim Yanitskiy977b3392019-05-13 15:32:21 +07001017DEFUN(show_pdpctx_apn, show_pdpctx_apn_cmd,
1018 "show pdp-context ggsn NAME apn APN",
1019 SHOW_STR "Show PDP Context Information\n"
1020 GGSN_STR "GGSN Name\n" "Filter by APN\n" "APN name\n")
1021{
1022 struct ggsn_ctx *ggsn;
1023 struct apn_ctx *apn;
1024
1025 ggsn = ggsn_find(argv[0]);
1026 if (!ggsn) {
1027 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
1028 return CMD_WARNING;
1029 }
1030
1031 apn = ggsn_find_apn(ggsn, argv[1]);
1032 if (!apn) {
1033 vty_out(vty, "%% No such APN '%s'%s", argv[1], VTY_NEWLINE);
1034 return CMD_WARNING;
1035 }
1036
1037 apn_show_pdp_contexts(vty, apn);
1038 return CMD_SUCCESS;
1039}
1040
1041/* Backwards compatibility: the VTY parser is (mis)interpreting
1042 * "[apn APN]" as two separate elements: "[apn" and "APN]",
1043 * but the first part somehow turns into command "ap". */
1044ALIAS_DEPRECATED(show_pdpctx_apn, show_deprecated_pdpctx_apn_cmd,
1045 "show pdp-context ggsn NAME ap APN",
1046 SHOW_STR "Show PDP Context Information\n"
1047 GGSN_STR "GGSN Name\n" "Filter by APN\n" "APN name\n");
1048
Harald Weltedda21ed2017-08-12 15:07:02 +02001049static void show_apn(struct vty *vty, struct apn_ctx *apn)
1050{
1051 vty_out(vty, " APN: %s%s", apn->cfg.name, VTY_NEWLINE);
1052 /* FIXME */
1053}
1054
1055static void show_one_ggsn(struct vty *vty, struct ggsn_ctx *ggsn)
1056{
1057 struct apn_ctx *apn;
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +02001058 struct sgsn_peer *sgsn;
Harald Weltedda21ed2017-08-12 15:07:02 +02001059 vty_out(vty, "GGSN %s: Bound to %s%s", ggsn->cfg.name, in46a_ntoa(&ggsn->cfg.listen_addr),
1060 VTY_NEWLINE);
1061 /* FIXME */
1062
1063 llist_for_each_entry(apn, &ggsn->apn_list, list)
1064 show_apn(vty, apn);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +02001065 llist_for_each_entry(sgsn, &ggsn->sgsn_list, entry)
1066 show_one_sgsn(vty, sgsn, " ");
Harald Weltedda21ed2017-08-12 15:07:02 +02001067}
1068
1069DEFUN(show_ggsn, show_ggsn_cmd,
1070 "show ggsn [NAME]",
1071 SHOW_STR "Display information on the GGSN\n")
1072{
1073 struct ggsn_ctx *ggsn;
1074
1075 if (argc == 0) {
1076 llist_for_each_entry(ggsn, &g_ggsn_list, list)
1077 show_one_ggsn(vty, ggsn);
1078 } else {
1079 ggsn = ggsn_find(argv[0]);
1080 if (!ggsn)
1081 return CMD_WARNING;
1082 show_one_ggsn(vty, ggsn);
1083 }
1084
1085 return CMD_SUCCESS;
1086}
1087
1088int ggsn_vty_init(void)
1089{
1090 install_element_ve(&show_pdpctx_cmd);
Vadim Yanitskiy977b3392019-05-13 15:32:21 +07001091 install_element_ve(&show_pdpctx_apn_cmd);
1092 install_element_ve(&show_deprecated_pdpctx_apn_cmd);
Harald Weltedda21ed2017-08-12 15:07:02 +02001093 install_element_ve(&show_pdpctx_imsi_cmd);
Vadim Yanitskiyca276e02019-05-13 13:06:51 +07001094 install_element_ve(&show_pdpctx_ip_cmd);
Harald Weltedda21ed2017-08-12 15:07:02 +02001095 install_element_ve(&show_ggsn_cmd);
1096
1097 install_element(CONFIG_NODE, &cfg_ggsn_cmd);
1098 install_element(CONFIG_NODE, &cfg_no_ggsn_cmd);
Pau Espin Pedrol840ce8a2017-11-16 17:01:44 +01001099
Harald Weltedda21ed2017-08-12 15:07:02 +02001100 install_node(&ggsn_node, config_write_ggsn);
Harald Weltedda21ed2017-08-12 15:07:02 +02001101 install_element(GGSN_NODE, &cfg_description_cmd);
1102 install_element(GGSN_NODE, &cfg_no_description_cmd);
1103 install_element(GGSN_NODE, &cfg_ggsn_shutdown_cmd);
1104 install_element(GGSN_NODE, &cfg_ggsn_no_shutdown_cmd);
Harald Welte98146772017-09-05 17:41:20 +02001105 install_element(GGSN_NODE, &cfg_ggsn_bind_ip_cmd);
1106 install_element(GGSN_NODE, &cfg_ggsn_gtpc_ip_cmd);
1107 install_element(GGSN_NODE, &cfg_ggsn_gtpu_ip_cmd);
Harald Weltedda21ed2017-08-12 15:07:02 +02001108 install_element(GGSN_NODE, &cfg_ggsn_state_dir_cmd);
1109 install_element(GGSN_NODE, &cfg_ggsn_apn_cmd);
1110 install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
1111 install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
1112 install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd);
Pau Espin Pedrolf5fbb412019-08-21 18:49:44 +02001113 install_element(GGSN_NODE, &cfg_ggsn_show_sgsn_cmd);
1114 install_element(GGSN_NODE, &cfg_ggsn_echo_interval_cmd);
1115 install_element(GGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
Harald Weltedda21ed2017-08-12 15:07:02 +02001116
1117 install_node(&apn_node, NULL);
Harald Weltedda21ed2017-08-12 15:07:02 +02001118 install_element(APN_NODE, &cfg_description_cmd);
1119 install_element(APN_NODE, &cfg_no_description_cmd);
1120 install_element(APN_NODE, &cfg_apn_shutdown_cmd);
1121 install_element(APN_NODE, &cfg_apn_no_shutdown_cmd);
1122 install_element(APN_NODE, &cfg_apn_gtpu_mode_cmd);
1123 install_element(APN_NODE, &cfg_apn_type_support_cmd);
1124 install_element(APN_NODE, &cfg_apn_no_type_support_cmd);
1125 install_element(APN_NODE, &cfg_apn_tun_dev_name_cmd);
1126 install_element(APN_NODE, &cfg_apn_ipup_script_cmd);
1127 install_element(APN_NODE, &cfg_apn_no_ipup_script_cmd);
1128 install_element(APN_NODE, &cfg_apn_ipdown_script_cmd);
1129 install_element(APN_NODE, &cfg_apn_no_ipdown_script_cmd);
1130 install_element(APN_NODE, &cfg_apn_ip_prefix_cmd);
1131 install_element(APN_NODE, &cfg_apn_ipv6_prefix_cmd);
1132 install_element(APN_NODE, &cfg_apn_ip_dns_cmd);
1133 install_element(APN_NODE, &cfg_apn_ipv6_dns_cmd);
1134 install_element(APN_NODE, &cfg_apn_no_dns_cmd);
1135 install_element(APN_NODE, &cfg_apn_ip_ifconfig_cmd);
1136 install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
1137 install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
1138 install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
Pau Espin Pedrol37c45e32017-12-14 14:09:13 +01001139 install_element(APN_NODE, &cfg_apn_ipv6_linklocal_cmd);
1140 install_element(APN_NODE, &cfg_apn_no_ipv6_linklocal_cmd);
Harald Welte93fed3b2017-09-24 11:43:17 +08001141 install_element(APN_NODE, &cfg_apn_gpdu_seq_cmd);
1142 install_element(APN_NODE, &cfg_apn_no_gpdu_seq_cmd);
Harald Weltedda21ed2017-08-12 15:07:02 +02001143
1144 return 0;
1145}
1146
1147static int ggsn_vty_is_config_node(struct vty *vty, int node)
1148{
1149 switch (node) {
1150 case GGSN_NODE:
1151 case APN_NODE:
1152 return 1;
1153 default:
1154 return 0;
1155 }
1156}
1157
1158static int ggsn_vty_go_parent(struct vty *vty)
1159{
1160 switch (vty->node) {
1161 case GGSN_NODE:
1162 vty->node = CONFIG_NODE;
1163 vty->index = NULL;
1164 vty->index_sub = NULL;
1165 break;
1166 case APN_NODE:
1167 vty->node = GGSN_NODE;
1168 {
1169 struct apn_ctx *apn = vty->index;
1170 vty->index = apn->ggsn;
1171 vty->index_sub = &apn->ggsn->cfg.description;
1172 }
1173 break;
Vadim Yanitskiy906c2092018-05-09 23:11:27 +07001174 default:
1175 vty->node = CONFIG_NODE;
1176 vty->index = NULL;
1177 vty->index_sub = NULL;
Harald Weltedda21ed2017-08-12 15:07:02 +02001178 }
1179
1180 return vty->node;
1181}
1182
1183static const char ggsn_copyright[] =
1184 "Copyright (C) 2011-2017 Harald Welte <laforge@gnumonks.org>\r\n"
1185 "Copyright (C) 2012-2017 Holger Hans Peter Freyther <holger@moiji-mobile.com>\r\n"
1186 "Copyright (C) 2012-2017 sysmocom - s.f.m.c. GmbH\r\n"
1187 "Copyright (C) 2002-2005 Mondru AB\r\n"
1188 "License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl-2.0.html>\r\n"
1189 "This is free software: you are free to change and redistribute it.\r\n"
1190 "There is NO WARRANTY, to the extent permitted by law.\r\n";
1191
1192struct vty_app_info g_vty_info = {
Harald Welte632e8432017-09-05 18:12:14 +02001193 .name = "OsmoGGSN",
Harald Weltedda21ed2017-08-12 15:07:02 +02001194 .version = PACKAGE_VERSION,
1195 .copyright = ggsn_copyright,
1196 .go_parent_cb = ggsn_vty_go_parent,
1197 .is_config_node = ggsn_vty_is_config_node,
1198};