blob: 4a3e7537a25eea7805cfdbaac1c6f2901c754327 [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>
29#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
30
31#include <osmocom/vty/command.h>
32#include <osmocom/vty/vty.h>
33#include <osmocom/vty/misc.h>
34
35#include "../gtp/gtp.h"
36#include "../gtp/pdp.h"
37
38#include "ggsn.h"
39
40#define PREFIX_STR "Prefix (Network/Netmask)\n"
41#define IFCONFIG_STR "GGSN-based interface configuration\n"
42#define GGSN_STR "Gateway GPRS Support NODE (GGSN)\n"
43
44LLIST_HEAD(g_ggsn_list);
45
46enum ggsn_vty_node {
47 GGSN_NODE = _LAST_OSMOVTY_NODE + 1,
48 APN_NODE,
49};
50
51struct ggsn_ctx *ggsn_find(const char *name)
52{
53 struct ggsn_ctx *ggsn;
54
55 llist_for_each_entry(ggsn, &g_ggsn_list, list) {
56 if (!strcmp(ggsn->cfg.name, name))
57 return ggsn;
58 }
59 return NULL;
60}
61
62struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name)
63{
64 struct ggsn_ctx *ggsn;
65
66 ggsn = ggsn_find(name);
67 if (ggsn)
68 return ggsn;
69
70 ggsn = talloc_zero(ctx, struct ggsn_ctx);
71 if (!ggsn)
72 return NULL;
73
74 ggsn->cfg.name = talloc_strdup(ggsn, name);
75 ggsn->cfg.state_dir = talloc_strdup(ggsn, "/tmp");
76 ggsn->cfg.shutdown = true;
77 INIT_LLIST_HEAD(&ggsn->apn_list);
78
79 llist_add_tail(&ggsn->list, &g_ggsn_list);
80 return ggsn;
81}
82
83struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name)
84{
85 struct apn_ctx *apn;
86
87 llist_for_each_entry(apn, &ggsn->apn_list, list) {
88 if (!strcmp(apn->cfg.name, name))
89 return apn;
90 }
91 return NULL;
92}
93
94struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name)
95{
96 struct apn_ctx *apn = ggsn_find_apn(ggsn, name);
97 if (apn)
98 return apn;
99
100 apn = talloc_zero(ggsn, struct apn_ctx);
101 if (!apn)
102 return NULL;
103 apn->ggsn = ggsn;
104 apn->cfg.name = talloc_strdup(apn, name);
105 apn->cfg.shutdown = true;
106 INIT_LLIST_HEAD(&apn->cfg.name_list);
107
108 llist_add_tail(&apn->list, &ggsn->apn_list);
109 return apn;
110}
111
112/* GGSN Node */
113
114static struct cmd_node ggsn_node = {
115 GGSN_NODE,
116 "%s(config-ggsn)# ",
117 1,
118};
119
120DEFUN(cfg_ggsn, cfg_ggsn_cmd,
121 "ggsn NAME",
122 "Configure the Gateway GPRS Support Node\n" "GGSN Name (has only local significance)\n")
123{
124 struct ggsn_ctx *ggsn;
125
126 ggsn = ggsn_find_or_create(tall_ggsn_ctx, argv[0]);
127 if (!ggsn)
128 return CMD_WARNING;
129
130 vty->node = GGSN_NODE;
131 vty->index = ggsn;
132 vty->index_sub = &ggsn->cfg.description;
133
134 return CMD_SUCCESS;
135}
136
137DEFUN(cfg_no_ggsn, cfg_no_ggsn_cmd,
138 "no ggsn NAME",
139 NO_STR "Remove the named Gateway GPRS Support Node\n"
140 "GGSN Name (has only local significance)\n")
141{
142 struct ggsn_ctx *ggsn;
143
144 ggsn = ggsn_find(argv[0]);
145 if (!ggsn) {
146 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
147 return CMD_WARNING;
148 }
149
150 if (!ggsn->cfg.shutdown) {
151 vty_out(vty, "%% GGSN %s is still active, please shutdown first%s",
152 ggsn->cfg.name, VTY_NEWLINE);
153 return CMD_WARNING;
154 }
155
156 if (!llist_empty(&ggsn->apn_list)) {
157 vty_out(vty, "%% GGSN %s still has APNs configured, please remove first%s",
158 ggsn->cfg.name, VTY_NEWLINE);
159 return CMD_WARNING;
160 }
161
162 llist_del(&ggsn->list);
163 talloc_free(ggsn);
164
165 return CMD_SUCCESS;
166}
167
168DEFUN(cfg_ggsn_local_ip, cfg_ggsn_local_ip_cmd,
169 "gtp local-ip A.B.C.D",
170 "GTP Parameters\n"
171 "Set the IP address for the local GTP bind\n"
172 "IPv4 Address\n")
173{
174 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
175 size_t t;
176
177 ippool_aton(&ggsn->cfg.listen_addr, &t, argv[0], 0);
178
179 return CMD_SUCCESS;
180}
181
182DEFUN(cfg_ggsn_state_dir, cfg_ggsn_state_dir_cmd,
183 "gtp state-dir PATH",
184 "GTP Parameters\n"
185 "Set the directory for the GTP State file\n"
186 "Local Directory\n")
187{
188 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
189
190 osmo_talloc_replace_string(ggsn, &ggsn->cfg.state_dir, argv[0]);
191
192 return CMD_SUCCESS;
193}
194
195DEFUN(cfg_ggsn_apn, cfg_ggsn_apn_cmd,
196 "apn NAME", "APN Configuration\n" "APN Name\n")
197{
198 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
199 struct apn_ctx *apn;
200
201 apn = ggsn_find_or_create_apn(ggsn, argv[0]);
202 if (!apn)
203 return CMD_WARNING;
204
205 vty->node = APN_NODE;
206 vty->index = apn;
207 vty->index_sub = &ggsn->cfg.description;
208
209 return CMD_SUCCESS;
210}
211
212DEFUN(cfg_ggsn_no_apn, cfg_ggsn_no_apn_cmd,
213 "no apn NAME",
214 NO_STR "Remove APN Configuration\n" "APN Name\n")
215{
216 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
217 struct apn_ctx *apn;
218
219 apn = ggsn_find_apn(ggsn, argv[0]);
220 if (!apn) {
221 vty_out(vty, "%% No such APN '%s'%s", argv[0], VTY_NEWLINE);
222 return CMD_WARNING;
223 }
224
225 if (!apn->cfg.shutdown) {
226 vty_out(vty, "%% APN %s still active, please shutdown first%s",
227 apn->cfg.name, VTY_NEWLINE);
228 return CMD_WARNING;
229 }
230
231 llist_del(&apn->list);
232 talloc_free(apn);
233
234 return CMD_SUCCESS;
235}
236
237DEFUN(cfg_ggsn_default_apn, cfg_ggsn_default_apn_cmd,
238 "default-apn NAME",
239 "Set a default-APN to be used if no other APN matches\n"
240 "APN Name\n")
241{
242 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
243 struct apn_ctx *apn;
244
245 apn = ggsn_find_apn(ggsn, argv[0]);
246 if (!apn) {
247 vty_out(vty, "%% No APN of name '%s' found%s", argv[0], VTY_NEWLINE);
248 return CMD_WARNING;
249 }
250
251 ggsn->cfg.default_apn = apn;
252 return CMD_SUCCESS;
253}
254
255DEFUN(cfg_ggsn_no_default_apn, cfg_ggsn_no_default_apn_cmd,
256 "no default-apn",
257 NO_STR "Remove default-APN to be used if no other APN matches\n")
258{
259 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
260 ggsn->cfg.default_apn = NULL;
261 return CMD_SUCCESS;
262}
263
264DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd,
265 "shutdown ggsn",
266 "Put the GGSN in administrative shut-down\n" GGSN_STR)
267{
268 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
269
270 if (!ggsn->cfg.shutdown) {
271 if (ggsn_stop(ggsn)) {
272 vty_out(vty, "%% Failed to shutdown GGSN%s", VTY_NEWLINE);
273 return CMD_WARNING;
274 }
275 ggsn->cfg.shutdown = true;
276 }
277
278 return CMD_SUCCESS;
279}
280
281DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd,
282 "no shutdown ggsn",
283 NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
284{
285 struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
286
287 if (ggsn->cfg.shutdown) {
288 if (ggsn_start(ggsn) < 0) {
289 vty_out(vty, "%% Failed to start GGSN, check log for details%s", VTY_NEWLINE);
290 return CMD_WARNING;
291 }
292 ggsn->cfg.shutdown = false;
293 }
294
295 return CMD_SUCCESS;
296}
297
298/* APN Node */
299
300static struct cmd_node apn_node = {
301 APN_NODE,
302 "%s(config-ggsn-apn)# ",
303 1,
304};
305
306static const struct value_string pdp_type_names[] = {
307 { APN_TYPE_IPv4, "v4" },
308 { APN_TYPE_IPv6, "v6" },
309 { APN_TYPE_IPv4v6, "v4v6" },
310 { 0, NULL }
311};
312
313static const struct value_string apn_gtpu_mode_names[] = {
314 { APN_GTPU_MODE_TUN, "tun" },
315 { APN_GTPU_MODE_KERNEL_GTP, "kernel-gtp" },
316 { 0, NULL }
317};
318
319
320#define V4V6V46_STRING "IPv4(-only) PDP Type\n" \
321 "IPv6(-only) PDP Type\n" \
322 "IPv4v6 (dual-stack) PDP Type\n"
323
324DEFUN(cfg_apn_type_support, cfg_apn_type_support_cmd,
325 "type-support (v4|v6|v4v6)",
326 "Enable support for PDP Type\n"
327 V4V6V46_STRING)
328{
329 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
330 uint32_t type = get_string_value(pdp_type_names, argv[0]);
331
332 apn->cfg.apn_type_mask |= type;
333 return CMD_SUCCESS;
334}
335
336DEFUN(cfg_apn_no_type_support, cfg_apn_no_type_support_cmd,
337 "no type-support (v4|v6|v4v6)",
338 NO_STR "Disable support for PDP Type\n"
339 V4V6V46_STRING)
340{
341 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
342 uint32_t type = get_string_value(pdp_type_names, argv[0]);
343
344 apn->cfg.apn_type_mask &= ~type;
345 return CMD_SUCCESS;
346}
347
348DEFUN(cfg_apn_gtpu_mode, cfg_apn_gtpu_mode_cmd,
349 "gtpu-mode (tun|kernel-gtp)",
350 "Set the Mode for this APN (tun or Linux Kernel GTP)\n"
351 "GTP-U in userspace using TUN device\n"
352 "GTP-U in kernel using Linux Kernel GTP\n")
353{
354 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
355
356 apn->cfg.gtpu_mode = get_string_value(apn_gtpu_mode_names, argv[0]);
357 return CMD_SUCCESS;
358}
359
360DEFUN(cfg_apn_tun_dev_name, cfg_apn_tun_dev_name_cmd,
361 "tun-device NAME",
362 "Configure tun device name\n"
363 "TUN device name")
364{
365 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
366 osmo_talloc_replace_string(apn, &apn->tun.cfg.dev_name, argv[0]);
367 return CMD_SUCCESS;
368}
369
370DEFUN(cfg_apn_ipup_script, cfg_apn_ipup_script_cmd,
371 "ipup-script PATH",
372 "Configure name/path of ip-up script\n"
373 "File/Path name of ip-up script\n")
374{
375 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
376 osmo_talloc_replace_string(apn, &apn->tun.cfg.ipup_script, argv[0]);
377 return CMD_SUCCESS;
378}
379
380DEFUN(cfg_apn_no_ipup_script, cfg_apn_no_ipup_script_cmd,
381 "no ipup-script",
382 NO_STR "Disable ip-up script\n")
383{
384 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
385 talloc_free(apn->tun.cfg.ipup_script);
386 apn->tun.cfg.ipup_script = NULL;
387 return CMD_SUCCESS;
388}
389
390DEFUN(cfg_apn_ipdown_script, cfg_apn_ipdown_script_cmd,
391 "ipdown-script PATH",
392 "Configure name/path of ip-down script\n"
393 "File/Path name of ip-down script\n")
394{
395 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
396 osmo_talloc_replace_string(apn, &apn->tun.cfg.ipdown_script, argv[0]);
397 return CMD_SUCCESS;
398}
399
400/* convert prefix from "A.B.C.D/M" notation to in46_prefix */
401static void str2prefix(struct in46_prefix *pfx, const char *in)
402{
403 size_t t;
404
405 ippool_aton(&pfx->addr, &t, in, 0);
406 pfx->prefixlen = t;
407}
408
409DEFUN(cfg_apn_no_ipdown_script, cfg_apn_no_ipdown_script_cmd,
410 "no ipdown-script",
411 NO_STR "Disable ip-down script\n")
412{
413 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
414 talloc_free(apn->tun.cfg.ipdown_script);
415 apn->tun.cfg.ipdown_script = NULL;
416 return CMD_SUCCESS;
417}
418
419DEFUN(cfg_apn_ip_prefix, cfg_apn_ip_prefix_cmd,
420 "ip prefix (static|dynamic) A.B.C.D/M",
421 IP_STR PREFIX_STR "IPv4 Adress/Prefix-Length\n")
422{
423 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
424 struct in46_prefix *pfx;
425
426 /* first update our parsed prefix */
427 if (!strcmp(argv[0], "static"))
428 pfx = &apn->v4.cfg.static_prefix;
429 else
430 pfx = &apn->v4.cfg.dynamic_prefix;
431 str2prefix(pfx, argv[1]);
432
433 return CMD_SUCCESS;
434}
435
436DEFUN(cfg_apn_ip_ifconfig, cfg_apn_ip_ifconfig_cmd,
437 "ip ifconfig A.B.C.D/M",
438 IP_STR IFCONFIG_STR "IPv4 Adress/Prefix-Length\n")
439{
440 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
441 str2prefix(&apn->v4.cfg.ifconfig_prefix, argv[0]);
442 return CMD_SUCCESS;
443}
444
445DEFUN(cfg_apn_no_ip_ifconfig, cfg_apn_no_ip_ifconfig_cmd,
446 "no ip ifconfig",
447 NO_STR IP_STR IFCONFIG_STR)
448{
449 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
450 memset(&apn->v4.cfg.ifconfig_prefix, 0, sizeof(apn->v4.cfg.ifconfig_prefix));
451 return CMD_SUCCESS;
452}
453
454DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd,
455 "ipv6 prefix (static|dynamic) X:X::X:X/M",
456 IP6_STR PREFIX_STR "IPv6 Address/Prefix-Length\n")
457{
458 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
459 struct in46_prefix *pfx;
460
461 if (!strcmp(argv[0], "static"))
462 pfx = &apn->v6.cfg.static_prefix;
463 else
464 pfx = &apn->v6.cfg.dynamic_prefix;
465 str2prefix(pfx, argv[1]);
466 return CMD_SUCCESS;
467}
468
469DEFUN(cfg_apn_ipv6_ifconfig, cfg_apn_ipv6_ifconfig_cmd,
470 "ipv6 ifconfig X:X::X:X/M",
471 IP6_STR IFCONFIG_STR "IPv6 Adress/Prefix-Length\n")
472{
473 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
474 str2prefix(&apn->v6.cfg.ifconfig_prefix, argv[0]);
475 return CMD_SUCCESS;
476}
477
478DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd,
479 "no ipv6 ifconfig",
480 NO_STR IP6_STR IFCONFIG_STR)
481{
482 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
483 memset(&apn->v6.cfg.ifconfig_prefix, 0, sizeof(apn->v6.cfg.ifconfig_prefix));
484 return CMD_SUCCESS;
485}
486
487#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
488
489DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
490 "ip dns <0-1> A.B.C.D",
491 IP_STR DNS_STRINGS)
492{
493 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
494 int idx = atoi(argv[0]);
495 size_t dummy;
496
497 ippool_aton(&apn->v4.cfg.dns[idx], &dummy, argv[1], 0);
498
499 return CMD_SUCCESS;
500}
501
502DEFUN(cfg_apn_ipv6_dns, cfg_apn_ipv6_dns_cmd,
503 "ipv6 dns <0-1> X:X::X:X",
504 IP6_STR DNS_STRINGS)
505{
506 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
507 int idx = atoi(argv[0]);
508 size_t dummy;
509
510 ippool_aton(&apn->v6.cfg.dns[idx], &dummy, argv[1], 0);
511
512 return CMD_SUCCESS;
513}
514
515DEFUN(cfg_apn_no_dns, cfg_apn_no_dns_cmd,
516 "no (ip|ipv6) dns <0-1>",
517 NO_STR IP_STR IP6_STR "Disable DNS Server\n" "primary/secondary DNS\n")
518{
519 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
520 struct in46_addr *a;
521 int idx = atoi(argv[1]);
522
523 if (!strcmp(argv[0], "ip"))
524 a = &apn->v4.cfg.dns[idx];
525 else
526 a = &apn->v6.cfg.dns[idx];
527
528 memset(a, 0, sizeof(*a));
529
530 return CMD_SUCCESS;
531}
532
533DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
534 "shutdown",
535 "Put the APN in administrative shut-down\n")
536{
537 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
538
539 if (!apn->cfg.shutdown) {
540 if (apn_stop(apn, false)) {
541 vty_out(vty, "%% Failed to Stop APN%s", VTY_NEWLINE);
542 return CMD_WARNING;
543 }
544 apn->cfg.shutdown = true;
545 }
546
547 return CMD_SUCCESS;
548}
549
550DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd,
551 "no shutdown",
552 NO_STR "Remove the APN from administrative shut-down\n")
553{
554 struct apn_ctx *apn = (struct apn_ctx *) vty->index;
555
556 if (apn->cfg.shutdown) {
557 if (apn_start(apn) < 0) {
558 vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
559 return CMD_WARNING;
560 }
561 apn->cfg.shutdown = false;
562 }
563
564 return CMD_SUCCESS;
565}
566
567
568static void vty_dump_prefix(struct vty *vty, const char *pre, const struct in46_prefix *pfx)
569{
570 vty_out(vty, "%s %s%s", pre, in46p_ntoa(pfx), VTY_NEWLINE);
571}
572
573static void config_write_apn(struct vty *vty, struct apn_ctx *apn)
574{
575 unsigned int i;
576
577 vty_out(vty, " apn %s%s", apn->cfg.name, VTY_NEWLINE);
578 if (apn->cfg.description)
579 vty_out(vty, " description %s%s", apn->cfg.description, VTY_NEWLINE);
580 vty_out(vty, " gtpu-mode %s%s", get_value_string(apn_gtpu_mode_names, apn->cfg.gtpu_mode),
581 VTY_NEWLINE);
582 if (apn->tun.cfg.dev_name)
583 vty_out(vty, " tun-device %s%s", apn->tun.cfg.dev_name, VTY_NEWLINE);
584 if (apn->tun.cfg.ipup_script)
585 vty_out(vty, " ipup-script %s%s", apn->tun.cfg.ipup_script, VTY_NEWLINE);
586 if (apn->tun.cfg.ipdown_script)
587 vty_out(vty, " ipdown-script %s%s", apn->tun.cfg.ipdown_script, VTY_NEWLINE);
588
589 for (i = 0; i < 32; i++) {
590 if (!(apn->cfg.apn_type_mask & (1 << i)))
591 continue;
592 vty_out(vty, " type-support %s%s", get_value_string(pdp_type_names, (1 << i)),
593 VTY_NEWLINE);
594 }
595
596 /* IPv4 prefixes + DNS */
597 if (apn->v4.cfg.static_prefix.addr.len)
598 vty_dump_prefix(vty, " ip prefix static", &apn->v4.cfg.static_prefix);
599 if (apn->v4.cfg.dynamic_prefix.addr.len)
600 vty_dump_prefix(vty, " ip prefix dynamic", &apn->v4.cfg.dynamic_prefix);
601 for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
602 if (!apn->v4.cfg.dns[i].len)
603 continue;
604 vty_out(vty, " ip dns %u %s%s", i, in46a_ntoa(&apn->v4.cfg.dns[i]), VTY_NEWLINE);
605 }
606 if (apn->v4.cfg.ifconfig_prefix.addr.len)
607 vty_dump_prefix(vty, " ip ifconfig ", &apn->v4.cfg.ifconfig_prefix);
608
609 /* IPv6 prefixes + DNS */
610 if (apn->v6.cfg.static_prefix.addr.len)
611 vty_dump_prefix(vty, " ipv6 prefix static", &apn->v6.cfg.static_prefix);
612 if (apn->v6.cfg.dynamic_prefix.addr.len)
613 vty_dump_prefix(vty, " ipv6 prefix dynamic", &apn->v6.cfg.dynamic_prefix);
614 for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
615 if (!apn->v6.cfg.dns[i].len)
616 continue;
617 vty_out(vty, " ip dns %u %s%s", i, in46a_ntoa(&apn->v6.cfg.dns[i]), VTY_NEWLINE);
618 }
619 if (apn->v6.cfg.ifconfig_prefix.addr.len)
620 vty_dump_prefix(vty, " ipv6 ifconfig ", &apn->v6.cfg.ifconfig_prefix);
621
622 /* must be last */
623 vty_out(vty, " %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
624}
625
626static int config_write_ggsn(struct vty *vty)
627{
628 struct ggsn_ctx *ggsn;
629
630 llist_for_each_entry(ggsn, &g_ggsn_list, list) {
631 struct apn_ctx *apn;
632 vty_out(vty, "ggsn %s%s", ggsn->cfg.name, VTY_NEWLINE);
633 if (ggsn->cfg.description)
634 vty_out(vty, " description %s%s", ggsn->cfg.description, VTY_NEWLINE);
635 vty_out(vty, " gtp state-dir %s%s", ggsn->cfg.state_dir, VTY_NEWLINE);
636 vty_out(vty, " gtp local-ip %s%s", in46a_ntoa(&ggsn->cfg.listen_addr), VTY_NEWLINE);
637 llist_for_each_entry(apn, &ggsn->apn_list, list)
638 config_write_apn(vty, apn);
639 if (ggsn->cfg.default_apn)
640 vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE);
641 /* must be last */
642 vty_out(vty, " %sshutdown ggsn%s", ggsn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
643 }
644
645 return 0;
646}
647
648static const char *print_gsnaddr(const struct ul16_t *in)
649{
650 struct in46_addr in46;
651
652 in46.len = in->l;
653 OSMO_ASSERT(in->l <= sizeof(in46.v6));
654 memcpy(&in46.v6, in->v, in->l);
655
656 return in46a_ntoa(&in46);
657}
658
659static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
660{
661 struct in46_addr eua46;
662
663 vty_out(vty, "IMSI: %s, NSAPI: %u, MSISDN: %s%s", imsi_gtp2str(&pdp->imsi), pdp->nsapi,
664 osmo_hexdump_nospc(pdp->msisdn.v, pdp->msisdn.l), VTY_NEWLINE);
665
666 vty_out(vty, " Control: %s:%08x ", print_gsnaddr(&pdp->gsnlc), pdp->teic_own);
667 vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnrc), pdp->teic_gn, VTY_NEWLINE);
668
669 vty_out(vty, " Data: %s:%08x ", print_gsnaddr(&pdp->gsnlu), pdp->teid_own);
670 vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnru), pdp->teid_gn, VTY_NEWLINE);
671
672 in46a_from_eua(&pdp->eua, &eua46);
673 vty_out(vty, " End-User Address: %s%s", in46a_ntoa(&eua46), VTY_NEWLINE);
674}
675
676DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
677 "show pdp-context imsi IMSI [<0-15>]",
678 SHOW_STR "Display information on PDP Context\n"
679 "PDP contexts for given IMSI\n"
680 "PDP context for given NSAPI\n")
681{
682 uint64_t imsi = strtoull(argv[0], NULL, 10);
683 unsigned int nsapi;
684 struct pdp_t *pdp;
685 int num_found = 0;
686
687 if (argc > 1) {
688 nsapi = atoi(argv[1]);
689 if (pdp_getimsi(&pdp, imsi, nsapi)) {
690 show_one_pdp(vty, pdp);
691 num_found++;
692 }
693 } else {
694 for (nsapi = 0; nsapi < PDP_MAXNSAPI; nsapi++) {
695 if (pdp_getimsi(&pdp, imsi, nsapi))
696 continue;
697 show_one_pdp(vty, pdp);
698 num_found++;
699 }
700 }
701 if (num_found == 0) {
702 vty_out(vty, "%% No such PDP context found%s", VTY_NEWLINE);
703 return CMD_WARNING;
704 } else
705 return CMD_SUCCESS;
706}
707
708/* show all (active) PDP contexts within a pool */
709static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool)
710{
711 unsigned int i;
712
713 if (!pool)
714 return;
715
716 for (i = 0; i < pool->listsize; i++) {
717 struct ippoolm_t *member = &pool->member[i];
718 if (member->inuse == 0)
719 continue;
720 show_one_pdp(vty, member->peer);
721 }
722}
723
724/* show all (active) PDP contexts within an APN */
725static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn)
726{
727 ippool_show_pdp_contexts(vty, apn->v4.pool);
728 ippool_show_pdp_contexts(vty, apn->v6.pool);
729}
730
731DEFUN(show_pdpctx, show_pdpctx_cmd,
732 "show pdp-context ggsn NAME [apn APN]",
733 SHOW_STR "Show PDP Context Information\n"
734 GGSN_STR "GGSN Name\n") // FIXME
735{
736 struct ggsn_ctx *ggsn;
737 struct apn_ctx *apn;
738
739 ggsn = ggsn_find(argv[0]);
740 if (!ggsn) {
741 vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
742 return CMD_WARNING;
743 }
744 if (argc < 2) {
745 llist_for_each_entry(apn, &ggsn->apn_list, list)
746 apn_show_pdp_contexts(vty, apn);
747 } else {
748 apn = ggsn_find_apn(ggsn, argv[1]);
749 if (!apn) {
750 vty_out(vty, "%% No such APN '%s'%s", argv[1], VTY_NEWLINE);
751 return CMD_WARNING;
752 }
753 apn_show_pdp_contexts(vty, apn);
754 }
755
756 return CMD_SUCCESS;
757}
758
759static void show_apn(struct vty *vty, struct apn_ctx *apn)
760{
761 vty_out(vty, " APN: %s%s", apn->cfg.name, VTY_NEWLINE);
762 /* FIXME */
763}
764
765static void show_one_ggsn(struct vty *vty, struct ggsn_ctx *ggsn)
766{
767 struct apn_ctx *apn;
768 vty_out(vty, "GGSN %s: Bound to %s%s", ggsn->cfg.name, in46a_ntoa(&ggsn->cfg.listen_addr),
769 VTY_NEWLINE);
770 /* FIXME */
771
772 llist_for_each_entry(apn, &ggsn->apn_list, list)
773 show_apn(vty, apn);
774}
775
776DEFUN(show_ggsn, show_ggsn_cmd,
777 "show ggsn [NAME]",
778 SHOW_STR "Display information on the GGSN\n")
779{
780 struct ggsn_ctx *ggsn;
781
782 if (argc == 0) {
783 llist_for_each_entry(ggsn, &g_ggsn_list, list)
784 show_one_ggsn(vty, ggsn);
785 } else {
786 ggsn = ggsn_find(argv[0]);
787 if (!ggsn)
788 return CMD_WARNING;
789 show_one_ggsn(vty, ggsn);
790 }
791
792 return CMD_SUCCESS;
793}
794
795int ggsn_vty_init(void)
796{
797 install_element_ve(&show_pdpctx_cmd);
798 install_element_ve(&show_pdpctx_imsi_cmd);
799 install_element_ve(&show_ggsn_cmd);
800
801 install_element(CONFIG_NODE, &cfg_ggsn_cmd);
802 install_element(CONFIG_NODE, &cfg_no_ggsn_cmd);
803 install_node(&ggsn_node, config_write_ggsn);
804 vty_install_default(GGSN_NODE);
805 install_element(GGSN_NODE, &cfg_description_cmd);
806 install_element(GGSN_NODE, &cfg_no_description_cmd);
807 install_element(GGSN_NODE, &cfg_ggsn_shutdown_cmd);
808 install_element(GGSN_NODE, &cfg_ggsn_no_shutdown_cmd);
809 install_element(GGSN_NODE, &cfg_ggsn_local_ip_cmd);
810 install_element(GGSN_NODE, &cfg_ggsn_state_dir_cmd);
811 install_element(GGSN_NODE, &cfg_ggsn_apn_cmd);
812 install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
813 install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
814 install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd);
815
816 install_node(&apn_node, NULL);
817 vty_install_default(APN_NODE);
818 install_element(APN_NODE, &cfg_description_cmd);
819 install_element(APN_NODE, &cfg_no_description_cmd);
820 install_element(APN_NODE, &cfg_apn_shutdown_cmd);
821 install_element(APN_NODE, &cfg_apn_no_shutdown_cmd);
822 install_element(APN_NODE, &cfg_apn_gtpu_mode_cmd);
823 install_element(APN_NODE, &cfg_apn_type_support_cmd);
824 install_element(APN_NODE, &cfg_apn_no_type_support_cmd);
825 install_element(APN_NODE, &cfg_apn_tun_dev_name_cmd);
826 install_element(APN_NODE, &cfg_apn_ipup_script_cmd);
827 install_element(APN_NODE, &cfg_apn_no_ipup_script_cmd);
828 install_element(APN_NODE, &cfg_apn_ipdown_script_cmd);
829 install_element(APN_NODE, &cfg_apn_no_ipdown_script_cmd);
830 install_element(APN_NODE, &cfg_apn_ip_prefix_cmd);
831 install_element(APN_NODE, &cfg_apn_ipv6_prefix_cmd);
832 install_element(APN_NODE, &cfg_apn_ip_dns_cmd);
833 install_element(APN_NODE, &cfg_apn_ipv6_dns_cmd);
834 install_element(APN_NODE, &cfg_apn_no_dns_cmd);
835 install_element(APN_NODE, &cfg_apn_ip_ifconfig_cmd);
836 install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
837 install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
838 install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
839
840 return 0;
841}
842
843static int ggsn_vty_is_config_node(struct vty *vty, int node)
844{
845 switch (node) {
846 case GGSN_NODE:
847 case APN_NODE:
848 return 1;
849 default:
850 return 0;
851 }
852}
853
854static int ggsn_vty_go_parent(struct vty *vty)
855{
856 switch (vty->node) {
857 case GGSN_NODE:
858 vty->node = CONFIG_NODE;
859 vty->index = NULL;
860 vty->index_sub = NULL;
861 break;
862 case APN_NODE:
863 vty->node = GGSN_NODE;
864 {
865 struct apn_ctx *apn = vty->index;
866 vty->index = apn->ggsn;
867 vty->index_sub = &apn->ggsn->cfg.description;
868 }
869 break;
870 }
871
872 return vty->node;
873}
874
875static const char ggsn_copyright[] =
876 "Copyright (C) 2011-2017 Harald Welte <laforge@gnumonks.org>\r\n"
877 "Copyright (C) 2012-2017 Holger Hans Peter Freyther <holger@moiji-mobile.com>\r\n"
878 "Copyright (C) 2012-2017 sysmocom - s.f.m.c. GmbH\r\n"
879 "Copyright (C) 2002-2005 Mondru AB\r\n"
880 "License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl-2.0.html>\r\n"
881 "This is free software: you are free to change and redistribute it.\r\n"
882 "There is NO WARRANTY, to the extent permitted by law.\r\n";
883
884struct vty_app_info g_vty_info = {
Harald Welte632e8432017-09-05 18:12:14 +0200885 .name = "OsmoGGSN",
Harald Weltedda21ed2017-08-12 15:07:02 +0200886 .version = PACKAGE_VERSION,
887 .copyright = ggsn_copyright,
888 .go_parent_cb = ggsn_vty_go_parent,
889 .is_config_node = ggsn_vty_is_config_node,
890};