9
0
Fork 0

Introduce a VTY, factually turning OpenGGSN into an Osmocom program

Change-Id: I9613ca3436e77ea132c47f0096df7c5050d7e826
This commit is contained in:
Harald Welte 2017-08-12 15:07:02 +02:00
parent 4d72643ede
commit c9f4f37dd4
13 changed files with 1673 additions and 2177 deletions

View File

@ -31,33 +31,13 @@ ggsn \- Gateway GPRS Support Node.
.B ggsn
[
.BI \-\-fg
.BI \-\-help
] [
.BI \-\-debug
.BI \-\-daemonize
] [
.BI \-\-conf " file"
.BI \-\-config-file " file"
] [
.BI \-\-pidfile " file"
] [
.BI \-\-statedir " file"
] [
.BI \-\-listen " host"
] [
.BI \-\-net " net"
] [
.BI \-\-ipup " script"
] [
.BI \-\-ipdown " script"
] [
.BI \-\-dynip " net"
] [
.BI \-\-statip " net"
] [
.BI \-\-pcodns1 " host"
] [
.BI \-\-pcodns2 " host"
] [
.BI \-\-timelimit " seconds"
.BI \-\-version
]
.SH DESCRIPTION
.B ggsn
@ -115,86 +95,17 @@ Print help and exit.
Print version and exit.
.TP
.BI --fg
Run in foreground (default = off)
.BI --daemonize
Run in background as a daemon (default = off)
.TP
.BI --debug
Run in debug mode (default = off)
.TP
.BI --conf " file"
.BI --config-file " file"
Read configuration
.I file
(default = /etc/ggsn.conf) where each line corresponds to one command
line option, but with the leading '--' removed. Command line options
override the options given in the configuration file.
.TP
.BI --pidfile " file"
Filename of process id
.I file
(default = /var/run/ggsn.pid)
.TP
.BI --statedir " path"
.I path
to directory of nonvolatile data (default = /var/lib/ggsn/)
.TP
.BI --listen " host"
Local interface IP address to use for the Gn/Gp interface. This option
must be specified. For security issues it is not possible to use
INADDR_ANY.
.TP
.BI --net " net"
Network address of the Gi interface (default = 192.168.0.0/24). The
network address is set during initialisation when
.B ggsn
establishes a tun device for the Gi interface.
.TP
.BI --ipup " script"
Script executed after the Gi tun network interface has been brought
up. Executed with the following parameters: <devicename> <ip address>
.TP
.BI --ipdown " script"
Script executed after the Gi tun network interface has been taken
down. Executed with the following parameters: <devicename> <ip
address>
.TP
.BI --dynip " net"
Dynamic IP address pool. Specifies a pool of dynamic IP addresses. If
this option is omitted the network address specified by the
.BI --net
option is used for dynamic IP address allocation.
.TP
.BI --pcodns1 " host"
PCO DNS Server 1 (default = 0.0.0.0). PCO stands for Protocol
Configuration options, and is part of the GPRS protocols. It is used
to inform the mobile station about the DNS address to use for host
name resolution.
.TP
.BI --pcodns2 " host"
PCO DNS Server 2 (default = 0.0.0.0). PCO stands for Protocol
Configuration options, and is part of the GPRS protocols. It is used
to inform the mobile station about the DNS address to use for host
name resolution.
.TP
.BI --timelimit " seconds"
Exit
.B ggsn
after \fIseconds\fP. Used for debugging.
(default = ./openggsn.cfg)
.SH FILES
.I /etc/ggsn.conf
.I ./openggsn.cfg
.RS
The configuration file for
.B ggsn.
@ -210,7 +121,7 @@ Directory holding nonvolatile data.
.SH BUGS
Report all bugs to the OpenGGSN bug tracking list at
.I http://sourceforge.net/projects/ggsn/
.I https://osmocom.org/projects/openggsn
.B ggsn
has very limited management support. Currently both SNMP as well as
@ -250,6 +161,7 @@ can be found at
.SH COPYRIGHT
Copyright (C) 2002, 2003 by Mondru AB.
Copyright (C) 2017 Harald Welte
The contents of this file may be used under the terms of the GNU
General Public License Version 2, provided that the above copyright
@ -258,3 +170,4 @@ substantial portions of the software.
.SH AUTHORS
Jens Jakobsen <jj@openggsn.org>
Harald Welte <laforge@gnumonks.org>

View File

@ -1,92 +0,0 @@
##############################################################################
#
# Sample ggsn configuration file
#
##############################################################################
# TAG: fg
# Include this flag if process is to run in the foreground
#
#fg
# TAG: debug
# Include this flag to include debug information.
#debug
# TAG: conf
# Configuration file to use. This file is the configuration file,
# so changing this parameter in the configuration file does not make
# sense. Use it on the command line instead.
# TAG: pidfile
# File to store information about the process id of the program.
# The program must have write access to this file/directory.
#pidfile /var/run/ggsn.pid
# TAG: statedir
# Directory to use for nonvolatile storage.
# The program must have write access to this directory.
#statedir /var/lib/ggsn/
# TAG: listen
# Specifies the local IP address to listen to
#listen 10.0.0.240
# TAG: net
# IP network address of external packet data network
# Used to set up network interface.
#net 192.168.0.0/24
# TAG: ipup
# Script executed after network interface has been brought up.
# Executed with the following parameters: <devicename> <ip address>
#ipup /etc/ggsn/ip-up
# TAG: ipdown
# Script executed after network interface has been taken down.
# Executed with the following parameters: <devicename> <ip address>
#ipdown /etc/ggsn/ip-down
# TAG: dynip
# Dynamic IP address pool.
# Used for allocation of dynamic IP address when address is not given
# by HLR.
# If this option is not given then the net option is used as a substitute.
#dynip 192.168.0.0/24
# TAG: statip
# Use of this tag is currently UNSUPPORTED
# Static IP address pool.
# Used for allocation of static IP address by means of HLR.
#statip 192.168.1.0/24
# TAG: pcodns1
# Protocol configuration option domain name system server 1.
#pcodns1 0.0.0.0
# TAG: pcodns2
# Protocol configuration option domain name system server 2.
#pcodns2 0.0.0.0
# TAG: timelimit
# Exit after timelimit seconds.
# Setting timelimit to zero will cause the program not to exit.
#timelimit 0
# TAG: apn
# Use of this tag is EXPERIMENTAL
# Access point name to connect to when run in client mode.
#apn internet
# TAG: qos
# Use of this tag is EXPERIMENTAL
# Requested Quality of Service used when run in client mode.
# 3 bytes corresponding to ????
#qos 0x0b921f
# TAG: qos
# Enable GTP datapath through Linux kernel driver gtp.ko (since 4.7).
#gtp-linux

71
examples/osmo-ggsn.cfg Normal file
View File

@ -0,0 +1,71 @@
!
! OpenGGSN (0.94.1-adac) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging print category 0
logging timestamp 0
logging level ip info
logging level tun info
logging level ggsn info
logging level sgsn notice
logging level icmp6 notice
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
logging level lctrl notice
logging level lgtp info
logging level lstats notice
logging level lgsup notice
logging level loap notice
logging level lss7 notice
logging level lsccp notice
logging level lsua notice
logging level lm3ua notice
logging level lmgcp notice
!
stats interval 5
!
line vty
no login
!
ggsn ggsn0
gtp state-dir /tmp
gtp bind-ip 127.0.0.6
apn internet
gtpu-mode tun
tun-device tun4
type-support v4
ip prefix dynamic 176.16.222.0/24
ip dns 0 192.168.100.1
ip dns 1 8.8.8.8
ip ifconfig 176.16.222.0/24
no shutdown
apn inet6
gtpu-mode tun
tun-device tun6
type-support v6
ipv6 prefix dynamic 2001:780:44:2000:0:0:0:0/56
ipv6 dns 0 2001:4860:4860::8888
ipv6 ifconfig 2001:780:44:2000:0:0:0:0/56
no shutdown
apn inet46
gtpu-mode tun
tun-device tun46
type-support v4v6
ip prefix dynamic 176.16.46.0/24
ip dns 0 192.168.100.1
ip dns 1 8.8.8.8
ip ifconfig 176.16.46.0/24
ipv6 prefix dynamic 2001:780:44:2100:0:0:0:0/56
ipv6 dns 0 2001:4860:4860::8888
ipv6 ifconfig 2001:780:44:2100:0:0:0:0/56
no shutdown
default-apn internet
no shutdown ggsn

View File

@ -2,17 +2,17 @@ bin_PROGRAMS = ggsn
AM_LDFLAGS = @EXEC_LDFLAGS@
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
if ENABLE_GTP_KERNEL
AM_CFLAGS += -DGTP_KERNEL
ggsn_LDADD = @EXEC_LDADD@ -lgtp -lgtpnl -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS)
else
ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS)
ggsn_LDADD += -lgtpnl
endif
ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
ggsn_SOURCES = ggsn.c cmdline.c cmdline.h gtp-kernel.h icmpv6.c icmpv6.h checksum.c checksum.h
ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h gtp-kernel.h icmpv6.c icmpv6.h checksum.c checksum.h
if ENABLE_GTP_KERNEL
ggsn_SOURCES += gtp-kernel.c

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
# OpenGGSN - Gateway GPRS Support Node
# Copyright (C) 2002, 2003, 2004 Mondru AB.
#
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
#
# Use "gengetopt --conf-parser < cmdline.ggo"
# to generate cmdline.c and cmdline.h
option "fg" f "Run in foreground" flag off
option "debug" d "Run in debug mode" flag off
option "conf" c "Read configuration file" string default="/etc/ggsn.conf" no
option "pidfile" - "Filename of process id file" string default="/var/run/ggsn.pid" no
option "statedir" - "Directory of nonvolatile data" string default="/var/lib/ggsn/" no
option "listen" l "Local interface" string no
option "net" n "Network" string default="192.168.0.0/24" no
option "ipup" - "Script to run after link-up" string no
option "ipdown" - "Script to run after link-down" string no
option "dynip" - "Dynamic IP address pool" string no
option "statip" - "Static IP address pool" string no
option "pcodns1" - "PCO DNS Server 1" string default="0.0.0.0" no
option "pcodns2" - "PCO DNS Server 2" string default="0.0.0.0" no
option "timelimit" - "Exit after timelimit seconds" int default="0" no
option "apn" a "Access point name" string default="internet" no
option "qos" q "Requested quality of service" int default="0x0b921f" no
option "logfile" - "Logfile for errors" string no
option "loglevel" - "Global log ldevel" string default="error" no
option "gtp-linux" g "GTP linux kernel support" flag off

View File

@ -1,275 +0,0 @@
/** @file cmdline.h
* @brief The header file for the command line option parser
* generated by GNU Gengetopt version 2.22.6
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
#ifndef CMDLINE_H
#define CMDLINE_H
/* If we use autoconf. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h> /* for FILE */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef CMDLINE_PARSER_PACKAGE
/** @brief the program name (used for printing errors) */
#define CMDLINE_PARSER_PACKAGE PACKAGE
#endif
#ifndef CMDLINE_PARSER_PACKAGE_NAME
/** @brief the complete program name (used for help and version) */
#ifdef PACKAGE_NAME
#define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME
#else
#define CMDLINE_PARSER_PACKAGE_NAME PACKAGE
#endif
#endif
#ifndef CMDLINE_PARSER_VERSION
/** @brief the program version */
#define CMDLINE_PARSER_VERSION VERSION
#endif
/** @brief Where the command line options are stored */
struct gengetopt_args_info
{
const char *help_help; /**< @brief Print help and exit help description. */
const char *version_help; /**< @brief Print version and exit help description. */
int fg_flag; /**< @brief Run in foreground (default=off). */
const char *fg_help; /**< @brief Run in foreground help description. */
int debug_flag; /**< @brief Run in debug mode (default=off). */
const char *debug_help; /**< @brief Run in debug mode help description. */
char * conf_arg; /**< @brief Read configuration file (default='/etc/ggsn.conf'). */
char * conf_orig; /**< @brief Read configuration file original value given at command line. */
const char *conf_help; /**< @brief Read configuration file help description. */
char * pidfile_arg; /**< @brief Filename of process id file (default='/var/run/ggsn.pid'). */
char * pidfile_orig; /**< @brief Filename of process id file original value given at command line. */
const char *pidfile_help; /**< @brief Filename of process id file help description. */
char * statedir_arg; /**< @brief Directory of nonvolatile data (default='/var/lib/ggsn/'). */
char * statedir_orig; /**< @brief Directory of nonvolatile data original value given at command line. */
const char *statedir_help; /**< @brief Directory of nonvolatile data help description. */
char * listen_arg; /**< @brief Local interface. */
char * listen_orig; /**< @brief Local interface original value given at command line. */
const char *listen_help; /**< @brief Local interface help description. */
char * net_arg; /**< @brief Network (default='192.168.0.0/24'). */
char * net_orig; /**< @brief Network original value given at command line. */
const char *net_help; /**< @brief Network help description. */
char * ipup_arg; /**< @brief Script to run after link-up. */
char * ipup_orig; /**< @brief Script to run after link-up original value given at command line. */
const char *ipup_help; /**< @brief Script to run after link-up help description. */
char * ipdown_arg; /**< @brief Script to run after link-down. */
char * ipdown_orig; /**< @brief Script to run after link-down original value given at command line. */
const char *ipdown_help; /**< @brief Script to run after link-down help description. */
char * dynip_arg; /**< @brief Dynamic IP address pool. */
char * dynip_orig; /**< @brief Dynamic IP address pool original value given at command line. */
const char *dynip_help; /**< @brief Dynamic IP address pool help description. */
char * statip_arg; /**< @brief Static IP address pool. */
char * statip_orig; /**< @brief Static IP address pool original value given at command line. */
const char *statip_help; /**< @brief Static IP address pool help description. */
char * pcodns1_arg; /**< @brief PCO DNS Server 1 (default='0.0.0.0'). */
char * pcodns1_orig; /**< @brief PCO DNS Server 1 original value given at command line. */
const char *pcodns1_help; /**< @brief PCO DNS Server 1 help description. */
char * pcodns2_arg; /**< @brief PCO DNS Server 2 (default='0.0.0.0'). */
char * pcodns2_orig; /**< @brief PCO DNS Server 2 original value given at command line. */
const char *pcodns2_help; /**< @brief PCO DNS Server 2 help description. */
int timelimit_arg; /**< @brief Exit after timelimit seconds (default='0'). */
char * timelimit_orig; /**< @brief Exit after timelimit seconds original value given at command line. */
const char *timelimit_help; /**< @brief Exit after timelimit seconds help description. */
char * apn_arg; /**< @brief Access point name (default='internet'). */
char * apn_orig; /**< @brief Access point name original value given at command line. */
const char *apn_help; /**< @brief Access point name help description. */
int qos_arg; /**< @brief Requested quality of service (default='0x0b921f'). */
char * qos_orig; /**< @brief Requested quality of service original value given at command line. */
const char *qos_help; /**< @brief Requested quality of service help description. */
char * logfile_arg; /**< @brief Logfile for errors. */
char * logfile_orig; /**< @brief Logfile for errors original value given at command line. */
const char *logfile_help; /**< @brief Logfile for errors help description. */
char * loglevel_arg; /**< @brief Global log ldevel (default='error'). */
char * loglevel_orig; /**< @brief Global log ldevel original value given at command line. */
const char *loglevel_help; /**< @brief Global log ldevel help description. */
int gtp_linux_flag; /**< @brief GTP linux kernel support (default=off). */
const char *gtp_linux_help; /**< @brief GTP linux kernel support help description. */
unsigned int help_given ; /**< @brief Whether help was given. */
unsigned int version_given ; /**< @brief Whether version was given. */
unsigned int fg_given ; /**< @brief Whether fg was given. */
unsigned int debug_given ; /**< @brief Whether debug was given. */
unsigned int conf_given ; /**< @brief Whether conf was given. */
unsigned int pidfile_given ; /**< @brief Whether pidfile was given. */
unsigned int statedir_given ; /**< @brief Whether statedir was given. */
unsigned int listen_given ; /**< @brief Whether listen was given. */
unsigned int net_given ; /**< @brief Whether net was given. */
unsigned int ipup_given ; /**< @brief Whether ipup was given. */
unsigned int ipdown_given ; /**< @brief Whether ipdown was given. */
unsigned int dynip_given ; /**< @brief Whether dynip was given. */
unsigned int statip_given ; /**< @brief Whether statip was given. */
unsigned int pcodns1_given ; /**< @brief Whether pcodns1 was given. */
unsigned int pcodns2_given ; /**< @brief Whether pcodns2 was given. */
unsigned int timelimit_given ; /**< @brief Whether timelimit was given. */
unsigned int apn_given ; /**< @brief Whether apn was given. */
unsigned int qos_given ; /**< @brief Whether qos was given. */
unsigned int logfile_given ; /**< @brief Whether logfile was given. */
unsigned int loglevel_given ; /**< @brief Whether loglevel was given. */
unsigned int gtp_linux_given ; /**< @brief Whether gtp-linux was given. */
} ;
/** @brief The additional parameters to pass to parser functions */
struct cmdline_parser_params
{
int override; /**< @brief whether to override possibly already present options (default 0) */
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
} ;
/** @brief the purpose string of the program */
extern const char *gengetopt_args_info_purpose;
/** @brief the usage string of the program */
extern const char *gengetopt_args_info_usage;
/** @brief the description string of the program */
extern const char *gengetopt_args_info_description;
/** @brief all the lines making the help output */
extern const char *gengetopt_args_info_help[];
/**
* The command line parser
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser (int argc, char **argv,
struct gengetopt_args_info *args_info);
/**
* The command line parser (version with additional parameters - deprecated)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_ext() instead
*/
int cmdline_parser2 (int argc, char **argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The command line parser (version with additional parameters)
* @param argc the number of command line options
* @param argv the command line options
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_ext (int argc, char **argv,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Save the contents of the option struct into an already open FILE stream.
* @param outfile the stream where to dump options
* @param args_info the option struct to dump
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_dump(FILE *outfile,
struct gengetopt_args_info *args_info);
/**
* Save the contents of the option struct into a (text) file.
* This file can be read by the config file parser (if generated by gengetopt)
* @param filename the file where to save
* @param args_info the option struct to save
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/**
* Print the help
*/
void cmdline_parser_print_help(void);
/**
* Print the version
*/
void cmdline_parser_print_version(void);
/**
* Initializes all the fields a cmdline_parser_params structure
* to their default values
* @param params the structure to initialize
*/
void cmdline_parser_params_init(struct cmdline_parser_params *params);
/**
* Allocates dynamically a cmdline_parser_params structure and initializes
* all its fields to their default values
* @return the created and initialized cmdline_parser_params structure
*/
struct cmdline_parser_params *cmdline_parser_params_create(void);
/**
* Initializes the passed gengetopt_args_info structure's fields
* (also set default values for options that have a default)
* @param args_info the structure to initialize
*/
void cmdline_parser_init (struct gengetopt_args_info *args_info);
/**
* Deallocates the string fields of the gengetopt_args_info structure
* (but does not deallocate the structure itself)
* @param args_info the structure to deallocate
*/
void cmdline_parser_free (struct gengetopt_args_info *args_info);
/**
* The config file parser (deprecated version)
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param override whether to override possibly already present options
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
* @deprecated use cmdline_parser_config_file() instead
*/
int cmdline_parser_configfile (const char *filename,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
/**
* The config file parser
* @param filename the name of the config file
* @param args_info the structure where option information will be stored
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
int cmdline_parser_config_file (const char *filename,
struct gengetopt_args_info *args_info,
struct cmdline_parser_params *params);
/**
* Checks that all the required options were specified
* @param args_info the structure to check
* @param prog_name the name of the program that will be used to print
* possible errors
* @return
*/
int cmdline_parser_required (struct gengetopt_args_info *args_info,
const char *prog_name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CMDLINE_H */

File diff suppressed because it is too large Load Diff

133
ggsn/ggsn.h Normal file
View File

@ -0,0 +1,133 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "../lib/tun.h"
#include "../lib/ippool.h"
#include "../lib/syserr.h"
#include "../lib/in46_addr.h"
#include "../gtp/gtp.h"
#define APN_TYPE_IPv4 0x01 /* v4-only */
#define APN_TYPE_IPv6 0x02 /* v6-only */
#define APN_TYPE_IPv4v6 0x04 /* v4v6 dual-stack */
struct ggsn_ctx;
struct apn_ctx_ip {
struct {
struct in46_prefix ifconfig_prefix;
struct in46_prefix static_prefix;
struct in46_prefix dynamic_prefix;
/* v4 DNS server names */
struct in46_addr dns[2];
} cfg;
/* v4 address pool */
struct ippool_t *pool;
};
struct apn_name {
struct llist_head list;
char *name;
};
enum apn_gtpu_mode {
APN_GTPU_MODE_TUN = 0, /* default */
APN_GTPU_MODE_KERNEL_GTP,
};
struct apn_ctx {
/* list of APNs inside GGSN */
struct llist_head list;
/* back-pointer to GGSN */
struct ggsn_ctx *ggsn;
bool started;
struct {
/* Primary name */
char *name;
/* Description string */
char *description;
/* List of secondary APN names */
struct llist_head name_list;
/* types supported address types on this APN */
uint32_t apn_type_mask;
/* GTP-U via TUN device or in Linux kernel */
enum apn_gtpu_mode gtpu_mode;
/* administratively shut-down (true) or not (false) */
bool shutdown;
} cfg;
/* corresponding tun device */
struct {
struct {
/* name of the network device */
char *dev_name;
/* ip-up and ip-down script names/paths */
char *ipup_script;
char *ipdown_script;
} cfg;
struct tun_t *tun;
struct osmo_fd fd;
} tun;
struct apn_ctx_ip v4;
struct apn_ctx_ip v6;
};
struct ggsn_ctx {
/* global list of GGSNs */
struct llist_head list;
/* list of APNs in this GGSN */
struct llist_head apn_list;
bool started;
struct {
char *name;
/* Description string */
char *description;
/* an APN that shall be used as default for any non-matching APN */
struct apn_ctx *default_apn;
/* ADdress to which we listen for GTP */
struct in46_addr listen_addr;
/* directory for state file */
char *state_dir;
/* administratively shut-down (true) or not (false) */
bool shutdown;
} cfg;
/* The libgtp (G)GSN instance, i.e. what listens to GTP */
struct gsn_t *gsn;
/* osmo-fd for gsn */
struct osmo_fd gtp_fd0;
struct osmo_fd gtp_fd1c;
struct osmo_fd gtp_fd1u;
struct osmo_timer_list gtp_timer;
};
/* ggsn_vty.c */
extern struct llist_head g_ggsn_list;
extern struct vty_app_info g_vty_info;
extern int ggsn_vty_init(void);
struct ggsn_ctx *ggsn_find(const char *name);
struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name);
struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name);
struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name);
/* ggsn.c */
extern void *tall_ggsn_ctx;
extern int ggsn_start(struct ggsn_ctx *ggsn);
extern int ggsn_stop(struct ggsn_ctx *ggsn);
extern int apn_start(struct apn_ctx *apn);
extern int apn_stop(struct apn_ctx *apn, bool force);

890
ggsn/ggsn_vty.c Normal file
View File

@ -0,0 +1,890 @@
/*
* (C) 2017 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#include "../gtp/gtp.h"
#include "../gtp/pdp.h"
#include "ggsn.h"
#define PREFIX_STR "Prefix (Network/Netmask)\n"
#define IFCONFIG_STR "GGSN-based interface configuration\n"
#define GGSN_STR "Gateway GPRS Support NODE (GGSN)\n"
LLIST_HEAD(g_ggsn_list);
enum ggsn_vty_node {
GGSN_NODE = _LAST_OSMOVTY_NODE + 1,
APN_NODE,
};
struct ggsn_ctx *ggsn_find(const char *name)
{
struct ggsn_ctx *ggsn;
llist_for_each_entry(ggsn, &g_ggsn_list, list) {
if (!strcmp(ggsn->cfg.name, name))
return ggsn;
}
return NULL;
}
struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name)
{
struct ggsn_ctx *ggsn;
ggsn = ggsn_find(name);
if (ggsn)
return ggsn;
ggsn = talloc_zero(ctx, struct ggsn_ctx);
if (!ggsn)
return NULL;
ggsn->cfg.name = talloc_strdup(ggsn, name);
ggsn->cfg.state_dir = talloc_strdup(ggsn, "/tmp");
ggsn->cfg.shutdown = true;
INIT_LLIST_HEAD(&ggsn->apn_list);
llist_add_tail(&ggsn->list, &g_ggsn_list);
return ggsn;
}
struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name)
{
struct apn_ctx *apn;
llist_for_each_entry(apn, &ggsn->apn_list, list) {
if (!strcmp(apn->cfg.name, name))
return apn;
}
return NULL;
}
struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name)
{
struct apn_ctx *apn = ggsn_find_apn(ggsn, name);
if (apn)
return apn;
apn = talloc_zero(ggsn, struct apn_ctx);
if (!apn)
return NULL;
apn->ggsn = ggsn;
apn->cfg.name = talloc_strdup(apn, name);
apn->cfg.shutdown = true;
INIT_LLIST_HEAD(&apn->cfg.name_list);
llist_add_tail(&apn->list, &ggsn->apn_list);
return apn;
}
/* GGSN Node */
static struct cmd_node ggsn_node = {
GGSN_NODE,
"%s(config-ggsn)# ",
1,
};
DEFUN(cfg_ggsn, cfg_ggsn_cmd,
"ggsn NAME",
"Configure the Gateway GPRS Support Node\n" "GGSN Name (has only local significance)\n")
{
struct ggsn_ctx *ggsn;
ggsn = ggsn_find_or_create(tall_ggsn_ctx, argv[0]);
if (!ggsn)
return CMD_WARNING;
vty->node = GGSN_NODE;
vty->index = ggsn;
vty->index_sub = &ggsn->cfg.description;
return CMD_SUCCESS;
}
DEFUN(cfg_no_ggsn, cfg_no_ggsn_cmd,
"no ggsn NAME",
NO_STR "Remove the named Gateway GPRS Support Node\n"
"GGSN Name (has only local significance)\n")
{
struct ggsn_ctx *ggsn;
ggsn = ggsn_find(argv[0]);
if (!ggsn) {
vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
if (!ggsn->cfg.shutdown) {
vty_out(vty, "%% GGSN %s is still active, please shutdown first%s",
ggsn->cfg.name, VTY_NEWLINE);
return CMD_WARNING;
}
if (!llist_empty(&ggsn->apn_list)) {
vty_out(vty, "%% GGSN %s still has APNs configured, please remove first%s",
ggsn->cfg.name, VTY_NEWLINE);
return CMD_WARNING;
}
llist_del(&ggsn->list);
talloc_free(ggsn);
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_local_ip, cfg_ggsn_local_ip_cmd,
"gtp local-ip A.B.C.D",
"GTP Parameters\n"
"Set the IP address for the local GTP bind\n"
"IPv4 Address\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
size_t t;
ippool_aton(&ggsn->cfg.listen_addr, &t, argv[0], 0);
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_state_dir, cfg_ggsn_state_dir_cmd,
"gtp state-dir PATH",
"GTP Parameters\n"
"Set the directory for the GTP State file\n"
"Local Directory\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
osmo_talloc_replace_string(ggsn, &ggsn->cfg.state_dir, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_apn, cfg_ggsn_apn_cmd,
"apn NAME", "APN Configuration\n" "APN Name\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
struct apn_ctx *apn;
apn = ggsn_find_or_create_apn(ggsn, argv[0]);
if (!apn)
return CMD_WARNING;
vty->node = APN_NODE;
vty->index = apn;
vty->index_sub = &ggsn->cfg.description;
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_no_apn, cfg_ggsn_no_apn_cmd,
"no apn NAME",
NO_STR "Remove APN Configuration\n" "APN Name\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
struct apn_ctx *apn;
apn = ggsn_find_apn(ggsn, argv[0]);
if (!apn) {
vty_out(vty, "%% No such APN '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
if (!apn->cfg.shutdown) {
vty_out(vty, "%% APN %s still active, please shutdown first%s",
apn->cfg.name, VTY_NEWLINE);
return CMD_WARNING;
}
llist_del(&apn->list);
talloc_free(apn);
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_default_apn, cfg_ggsn_default_apn_cmd,
"default-apn NAME",
"Set a default-APN to be used if no other APN matches\n"
"APN Name\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
struct apn_ctx *apn;
apn = ggsn_find_apn(ggsn, argv[0]);
if (!apn) {
vty_out(vty, "%% No APN of name '%s' found%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
ggsn->cfg.default_apn = apn;
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_no_default_apn, cfg_ggsn_no_default_apn_cmd,
"no default-apn",
NO_STR "Remove default-APN to be used if no other APN matches\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
ggsn->cfg.default_apn = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd,
"shutdown ggsn",
"Put the GGSN in administrative shut-down\n" GGSN_STR)
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
if (!ggsn->cfg.shutdown) {
if (ggsn_stop(ggsn)) {
vty_out(vty, "%% Failed to shutdown GGSN%s", VTY_NEWLINE);
return CMD_WARNING;
}
ggsn->cfg.shutdown = true;
}
return CMD_SUCCESS;
}
DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd,
"no shutdown ggsn",
NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
if (ggsn->cfg.shutdown) {
if (ggsn_start(ggsn) < 0) {
vty_out(vty, "%% Failed to start GGSN, check log for details%s", VTY_NEWLINE);
return CMD_WARNING;
}
ggsn->cfg.shutdown = false;
}
return CMD_SUCCESS;
}
/* APN Node */
static struct cmd_node apn_node = {
APN_NODE,
"%s(config-ggsn-apn)# ",
1,
};
static const struct value_string pdp_type_names[] = {
{ APN_TYPE_IPv4, "v4" },
{ APN_TYPE_IPv6, "v6" },
{ APN_TYPE_IPv4v6, "v4v6" },
{ 0, NULL }
};
static const struct value_string apn_gtpu_mode_names[] = {
{ APN_GTPU_MODE_TUN, "tun" },
{ APN_GTPU_MODE_KERNEL_GTP, "kernel-gtp" },
{ 0, NULL }
};
#define V4V6V46_STRING "IPv4(-only) PDP Type\n" \
"IPv6(-only) PDP Type\n" \
"IPv4v6 (dual-stack) PDP Type\n"
DEFUN(cfg_apn_type_support, cfg_apn_type_support_cmd,
"type-support (v4|v6|v4v6)",
"Enable support for PDP Type\n"
V4V6V46_STRING)
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
uint32_t type = get_string_value(pdp_type_names, argv[0]);
apn->cfg.apn_type_mask |= type;
return CMD_SUCCESS;
}
DEFUN(cfg_apn_no_type_support, cfg_apn_no_type_support_cmd,
"no type-support (v4|v6|v4v6)",
NO_STR "Disable support for PDP Type\n"
V4V6V46_STRING)
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
uint32_t type = get_string_value(pdp_type_names, argv[0]);
apn->cfg.apn_type_mask &= ~type;
return CMD_SUCCESS;
}
DEFUN(cfg_apn_gtpu_mode, cfg_apn_gtpu_mode_cmd,
"gtpu-mode (tun|kernel-gtp)",
"Set the Mode for this APN (tun or Linux Kernel GTP)\n"
"GTP-U in userspace using TUN device\n"
"GTP-U in kernel using Linux Kernel GTP\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
apn->cfg.gtpu_mode = get_string_value(apn_gtpu_mode_names, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_tun_dev_name, cfg_apn_tun_dev_name_cmd,
"tun-device NAME",
"Configure tun device name\n"
"TUN device name")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
osmo_talloc_replace_string(apn, &apn->tun.cfg.dev_name, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ipup_script, cfg_apn_ipup_script_cmd,
"ipup-script PATH",
"Configure name/path of ip-up script\n"
"File/Path name of ip-up script\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
osmo_talloc_replace_string(apn, &apn->tun.cfg.ipup_script, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_no_ipup_script, cfg_apn_no_ipup_script_cmd,
"no ipup-script",
NO_STR "Disable ip-up script\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
talloc_free(apn->tun.cfg.ipup_script);
apn->tun.cfg.ipup_script = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ipdown_script, cfg_apn_ipdown_script_cmd,
"ipdown-script PATH",
"Configure name/path of ip-down script\n"
"File/Path name of ip-down script\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
osmo_talloc_replace_string(apn, &apn->tun.cfg.ipdown_script, argv[0]);
return CMD_SUCCESS;
}
/* convert prefix from "A.B.C.D/M" notation to in46_prefix */
static void str2prefix(struct in46_prefix *pfx, const char *in)
{
size_t t;
ippool_aton(&pfx->addr, &t, in, 0);
pfx->prefixlen = t;
}
DEFUN(cfg_apn_no_ipdown_script, cfg_apn_no_ipdown_script_cmd,
"no ipdown-script",
NO_STR "Disable ip-down script\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
talloc_free(apn->tun.cfg.ipdown_script);
apn->tun.cfg.ipdown_script = NULL;
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ip_prefix, cfg_apn_ip_prefix_cmd,
"ip prefix (static|dynamic) A.B.C.D/M",
IP_STR PREFIX_STR "IPv4 Adress/Prefix-Length\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
struct in46_prefix *pfx;
/* first update our parsed prefix */
if (!strcmp(argv[0], "static"))
pfx = &apn->v4.cfg.static_prefix;
else
pfx = &apn->v4.cfg.dynamic_prefix;
str2prefix(pfx, argv[1]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ip_ifconfig, cfg_apn_ip_ifconfig_cmd,
"ip ifconfig A.B.C.D/M",
IP_STR IFCONFIG_STR "IPv4 Adress/Prefix-Length\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
str2prefix(&apn->v4.cfg.ifconfig_prefix, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_no_ip_ifconfig, cfg_apn_no_ip_ifconfig_cmd,
"no ip ifconfig",
NO_STR IP_STR IFCONFIG_STR)
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
memset(&apn->v4.cfg.ifconfig_prefix, 0, sizeof(apn->v4.cfg.ifconfig_prefix));
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd,
"ipv6 prefix (static|dynamic) X:X::X:X/M",
IP6_STR PREFIX_STR "IPv6 Address/Prefix-Length\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
struct in46_prefix *pfx;
if (!strcmp(argv[0], "static"))
pfx = &apn->v6.cfg.static_prefix;
else
pfx = &apn->v6.cfg.dynamic_prefix;
str2prefix(pfx, argv[1]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ipv6_ifconfig, cfg_apn_ipv6_ifconfig_cmd,
"ipv6 ifconfig X:X::X:X/M",
IP6_STR IFCONFIG_STR "IPv6 Adress/Prefix-Length\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
str2prefix(&apn->v6.cfg.ifconfig_prefix, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd,
"no ipv6 ifconfig",
NO_STR IP6_STR IFCONFIG_STR)
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
memset(&apn->v6.cfg.ifconfig_prefix, 0, sizeof(apn->v6.cfg.ifconfig_prefix));
return CMD_SUCCESS;
}
#define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n"
DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd,
"ip dns <0-1> A.B.C.D",
IP_STR DNS_STRINGS)
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
int idx = atoi(argv[0]);
size_t dummy;
ippool_aton(&apn->v4.cfg.dns[idx], &dummy, argv[1], 0);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_ipv6_dns, cfg_apn_ipv6_dns_cmd,
"ipv6 dns <0-1> X:X::X:X",
IP6_STR DNS_STRINGS)
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
int idx = atoi(argv[0]);
size_t dummy;
ippool_aton(&apn->v6.cfg.dns[idx], &dummy, argv[1], 0);
return CMD_SUCCESS;
}
DEFUN(cfg_apn_no_dns, cfg_apn_no_dns_cmd,
"no (ip|ipv6) dns <0-1>",
NO_STR IP_STR IP6_STR "Disable DNS Server\n" "primary/secondary DNS\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
struct in46_addr *a;
int idx = atoi(argv[1]);
if (!strcmp(argv[0], "ip"))
a = &apn->v4.cfg.dns[idx];
else
a = &apn->v6.cfg.dns[idx];
memset(a, 0, sizeof(*a));
return CMD_SUCCESS;
}
DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
"shutdown",
"Put the APN in administrative shut-down\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
if (!apn->cfg.shutdown) {
if (apn_stop(apn, false)) {
vty_out(vty, "%% Failed to Stop APN%s", VTY_NEWLINE);
return CMD_WARNING;
}
apn->cfg.shutdown = true;
}
return CMD_SUCCESS;
}
DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd,
"no shutdown",
NO_STR "Remove the APN from administrative shut-down\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
if (apn->cfg.shutdown) {
if (apn_start(apn) < 0) {
vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
return CMD_WARNING;
}
apn->cfg.shutdown = false;
}
return CMD_SUCCESS;
}
static void vty_dump_prefix(struct vty *vty, const char *pre, const struct in46_prefix *pfx)
{
vty_out(vty, "%s %s%s", pre, in46p_ntoa(pfx), VTY_NEWLINE);
}
static void config_write_apn(struct vty *vty, struct apn_ctx *apn)
{
unsigned int i;
vty_out(vty, " apn %s%s", apn->cfg.name, VTY_NEWLINE);
if (apn->cfg.description)
vty_out(vty, " description %s%s", apn->cfg.description, VTY_NEWLINE);
vty_out(vty, " gtpu-mode %s%s", get_value_string(apn_gtpu_mode_names, apn->cfg.gtpu_mode),
VTY_NEWLINE);
if (apn->tun.cfg.dev_name)
vty_out(vty, " tun-device %s%s", apn->tun.cfg.dev_name, VTY_NEWLINE);
if (apn->tun.cfg.ipup_script)
vty_out(vty, " ipup-script %s%s", apn->tun.cfg.ipup_script, VTY_NEWLINE);
if (apn->tun.cfg.ipdown_script)
vty_out(vty, " ipdown-script %s%s", apn->tun.cfg.ipdown_script, VTY_NEWLINE);
for (i = 0; i < 32; i++) {
if (!(apn->cfg.apn_type_mask & (1 << i)))
continue;
vty_out(vty, " type-support %s%s", get_value_string(pdp_type_names, (1 << i)),
VTY_NEWLINE);
}
/* IPv4 prefixes + DNS */
if (apn->v4.cfg.static_prefix.addr.len)
vty_dump_prefix(vty, " ip prefix static", &apn->v4.cfg.static_prefix);
if (apn->v4.cfg.dynamic_prefix.addr.len)
vty_dump_prefix(vty, " ip prefix dynamic", &apn->v4.cfg.dynamic_prefix);
for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) {
if (!apn->v4.cfg.dns[i].len)
continue;
vty_out(vty, " ip dns %u %s%s", i, in46a_ntoa(&apn->v4.cfg.dns[i]), VTY_NEWLINE);
}
if (apn->v4.cfg.ifconfig_prefix.addr.len)
vty_dump_prefix(vty, " ip ifconfig ", &apn->v4.cfg.ifconfig_prefix);
/* IPv6 prefixes + DNS */
if (apn->v6.cfg.static_prefix.addr.len)
vty_dump_prefix(vty, " ipv6 prefix static", &apn->v6.cfg.static_prefix);
if (apn->v6.cfg.dynamic_prefix.addr.len)
vty_dump_prefix(vty, " ipv6 prefix dynamic", &apn->v6.cfg.dynamic_prefix);
for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) {
if (!apn->v6.cfg.dns[i].len)
continue;
vty_out(vty, " ip dns %u %s%s", i, in46a_ntoa(&apn->v6.cfg.dns[i]), VTY_NEWLINE);
}
if (apn->v6.cfg.ifconfig_prefix.addr.len)
vty_dump_prefix(vty, " ipv6 ifconfig ", &apn->v6.cfg.ifconfig_prefix);
/* must be last */
vty_out(vty, " %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
}
static int config_write_ggsn(struct vty *vty)
{
struct ggsn_ctx *ggsn;
llist_for_each_entry(ggsn, &g_ggsn_list, list) {
struct apn_ctx *apn;
vty_out(vty, "ggsn %s%s", ggsn->cfg.name, VTY_NEWLINE);
if (ggsn->cfg.description)
vty_out(vty, " description %s%s", ggsn->cfg.description, VTY_NEWLINE);
vty_out(vty, " gtp state-dir %s%s", ggsn->cfg.state_dir, VTY_NEWLINE);
vty_out(vty, " gtp local-ip %s%s", in46a_ntoa(&ggsn->cfg.listen_addr), VTY_NEWLINE);
llist_for_each_entry(apn, &ggsn->apn_list, list)
config_write_apn(vty, apn);
if (ggsn->cfg.default_apn)
vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE);
/* must be last */
vty_out(vty, " %sshutdown ggsn%s", ggsn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
}
return 0;
}
static const char *print_gsnaddr(const struct ul16_t *in)
{
struct in46_addr in46;
in46.len = in->l;
OSMO_ASSERT(in->l <= sizeof(in46.v6));
memcpy(&in46.v6, in->v, in->l);
return in46a_ntoa(&in46);
}
static void show_one_pdp(struct vty *vty, struct pdp_t *pdp)
{
struct in46_addr eua46;
vty_out(vty, "IMSI: %s, NSAPI: %u, MSISDN: %s%s", imsi_gtp2str(&pdp->imsi), pdp->nsapi,
osmo_hexdump_nospc(pdp->msisdn.v, pdp->msisdn.l), VTY_NEWLINE);
vty_out(vty, " Control: %s:%08x ", print_gsnaddr(&pdp->gsnlc), pdp->teic_own);
vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnrc), pdp->teic_gn, VTY_NEWLINE);
vty_out(vty, " Data: %s:%08x ", print_gsnaddr(&pdp->gsnlu), pdp->teid_own);
vty_out(vty, "<-> %s:%08x%s", print_gsnaddr(&pdp->gsnru), pdp->teid_gn, VTY_NEWLINE);
in46a_from_eua(&pdp->eua, &eua46);
vty_out(vty, " End-User Address: %s%s", in46a_ntoa(&eua46), VTY_NEWLINE);
}
DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
"show pdp-context imsi IMSI [<0-15>]",
SHOW_STR "Display information on PDP Context\n"
"PDP contexts for given IMSI\n"
"PDP context for given NSAPI\n")
{
uint64_t imsi = strtoull(argv[0], NULL, 10);
unsigned int nsapi;
struct pdp_t *pdp;
int num_found = 0;
if (argc > 1) {
nsapi = atoi(argv[1]);
if (pdp_getimsi(&pdp, imsi, nsapi)) {
show_one_pdp(vty, pdp);
num_found++;
}
} else {
for (nsapi = 0; nsapi < PDP_MAXNSAPI; nsapi++) {
if (pdp_getimsi(&pdp, imsi, nsapi))
continue;
show_one_pdp(vty, pdp);
num_found++;
}
}
if (num_found == 0) {
vty_out(vty, "%% No such PDP context found%s", VTY_NEWLINE);
return CMD_WARNING;
} else
return CMD_SUCCESS;
}
/* show all (active) PDP contexts within a pool */
static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool)
{
unsigned int i;
if (!pool)
return;
for (i = 0; i < pool->listsize; i++) {
struct ippoolm_t *member = &pool->member[i];
if (member->inuse == 0)
continue;
show_one_pdp(vty, member->peer);
}
}
/* show all (active) PDP contexts within an APN */
static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn)
{
ippool_show_pdp_contexts(vty, apn->v4.pool);
ippool_show_pdp_contexts(vty, apn->v6.pool);
}
DEFUN(show_pdpctx, show_pdpctx_cmd,
"show pdp-context ggsn NAME [apn APN]",
SHOW_STR "Show PDP Context Information\n"
GGSN_STR "GGSN Name\n") // FIXME
{
struct ggsn_ctx *ggsn;
struct apn_ctx *apn;
ggsn = ggsn_find(argv[0]);
if (!ggsn) {
vty_out(vty, "%% No such GGSN '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
if (argc < 2) {
llist_for_each_entry(apn, &ggsn->apn_list, list)
apn_show_pdp_contexts(vty, apn);
} else {
apn = ggsn_find_apn(ggsn, argv[1]);
if (!apn) {
vty_out(vty, "%% No such APN '%s'%s", argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
apn_show_pdp_contexts(vty, apn);
}
return CMD_SUCCESS;
}
static void show_apn(struct vty *vty, struct apn_ctx *apn)
{
vty_out(vty, " APN: %s%s", apn->cfg.name, VTY_NEWLINE);
/* FIXME */
}
static void show_one_ggsn(struct vty *vty, struct ggsn_ctx *ggsn)
{
struct apn_ctx *apn;
vty_out(vty, "GGSN %s: Bound to %s%s", ggsn->cfg.name, in46a_ntoa(&ggsn->cfg.listen_addr),
VTY_NEWLINE);
/* FIXME */
llist_for_each_entry(apn, &ggsn->apn_list, list)
show_apn(vty, apn);
}
DEFUN(show_ggsn, show_ggsn_cmd,
"show ggsn [NAME]",
SHOW_STR "Display information on the GGSN\n")
{
struct ggsn_ctx *ggsn;
if (argc == 0) {
llist_for_each_entry(ggsn, &g_ggsn_list, list)
show_one_ggsn(vty, ggsn);
} else {
ggsn = ggsn_find(argv[0]);
if (!ggsn)
return CMD_WARNING;
show_one_ggsn(vty, ggsn);
}
return CMD_SUCCESS;
}
int ggsn_vty_init(void)
{
install_element_ve(&show_pdpctx_cmd);
install_element_ve(&show_pdpctx_imsi_cmd);
install_element_ve(&show_ggsn_cmd);
install_element(CONFIG_NODE, &cfg_ggsn_cmd);
install_element(CONFIG_NODE, &cfg_no_ggsn_cmd);
install_node(&ggsn_node, config_write_ggsn);
vty_install_default(GGSN_NODE);
install_element(GGSN_NODE, &cfg_description_cmd);
install_element(GGSN_NODE, &cfg_no_description_cmd);
install_element(GGSN_NODE, &cfg_ggsn_shutdown_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_shutdown_cmd);
install_element(GGSN_NODE, &cfg_ggsn_local_ip_cmd);
install_element(GGSN_NODE, &cfg_ggsn_state_dir_cmd);
install_element(GGSN_NODE, &cfg_ggsn_apn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd);
install_node(&apn_node, NULL);
vty_install_default(APN_NODE);
install_element(APN_NODE, &cfg_description_cmd);
install_element(APN_NODE, &cfg_no_description_cmd);
install_element(APN_NODE, &cfg_apn_shutdown_cmd);
install_element(APN_NODE, &cfg_apn_no_shutdown_cmd);
install_element(APN_NODE, &cfg_apn_gtpu_mode_cmd);
install_element(APN_NODE, &cfg_apn_type_support_cmd);
install_element(APN_NODE, &cfg_apn_no_type_support_cmd);
install_element(APN_NODE, &cfg_apn_tun_dev_name_cmd);
install_element(APN_NODE, &cfg_apn_ipup_script_cmd);
install_element(APN_NODE, &cfg_apn_no_ipup_script_cmd);
install_element(APN_NODE, &cfg_apn_ipdown_script_cmd);
install_element(APN_NODE, &cfg_apn_no_ipdown_script_cmd);
install_element(APN_NODE, &cfg_apn_ip_prefix_cmd);
install_element(APN_NODE, &cfg_apn_ipv6_prefix_cmd);
install_element(APN_NODE, &cfg_apn_ip_dns_cmd);
install_element(APN_NODE, &cfg_apn_ipv6_dns_cmd);
install_element(APN_NODE, &cfg_apn_no_dns_cmd);
install_element(APN_NODE, &cfg_apn_ip_ifconfig_cmd);
install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd);
install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd);
install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd);
return 0;
}
static int ggsn_vty_is_config_node(struct vty *vty, int node)
{
switch (node) {
case GGSN_NODE:
case APN_NODE:
return 1;
default:
return 0;
}
}
static int ggsn_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case GGSN_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
vty->index_sub = NULL;
break;
case APN_NODE:
vty->node = GGSN_NODE;
{
struct apn_ctx *apn = vty->index;
vty->index = apn->ggsn;
vty->index_sub = &apn->ggsn->cfg.description;
}
break;
}
return vty->node;
}
static const char ggsn_copyright[] =
"Copyright (C) 2011-2017 Harald Welte <laforge@gnumonks.org>\r\n"
"Copyright (C) 2012-2017 Holger Hans Peter Freyther <holger@moiji-mobile.com>\r\n"
"Copyright (C) 2012-2017 sysmocom - s.f.m.c. GmbH\r\n"
"Copyright (C) 2002-2005 Mondru AB\r\n"
"License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl-2.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
struct vty_app_info g_vty_info = {
.name = "OpenGGSN",
.version = PACKAGE_VERSION,
.copyright = ggsn_copyright,
.go_parent_cb = ggsn_vty_go_parent,
.is_config_node = ggsn_vty_is_config_node,
};

View File

@ -583,7 +583,7 @@ int tun_delroute(struct tun_t *this,
return tun_route(this, dst, gateway, mask, 1);
}
int tun_new(struct tun_t **tun)
int tun_new(struct tun_t **tun, const char *dev_name)
{
#if defined(__linux__)
@ -615,6 +615,8 @@ int tun_new(struct tun_t **tun)
/* Set device flags. For some weird reason this is also the method
used to obtain the network interface name */
memset(&ifr, 0, sizeof(ifr));
if (dev_name)
strcpy(ifr.ifr_name, dev_name);
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");

View File

@ -65,7 +65,7 @@ struct tun_t {
void *priv;
};
extern int tun_new(struct tun_t **tun);
extern int tun_new(struct tun_t **tun, const char *dev_name);
extern int tun_free(struct tun_t *tun);
extern int tun_decaps(struct tun_t *this);
extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);

View File

@ -1461,7 +1461,7 @@ int main(int argc, char **argv)
if (options.createif) {
printf("Setting up interface\n");
/* Create a tunnel interface */
if (tun_new((struct tun_t **)&tun)) {
if (tun_new((struct tun_t **)&tun, NULL)) {
SYS_ERR(DSGSN, LOGL_ERROR, 0,
"Failed to create tun");
exit(1);