pespin submitted this change.
layer23: Introduce APN VTY node
This commit adds an initial set of VTY commands to manage APN
configuration and set up, which is used by the modem app.
The sample modem.cfg file is updated to showcase how to configure APNs.
The app doesn't do anything with them yet. A follow up patch will add
code to create tun devices for each configured APN.
Change-Id: I7b4eaa0de428b418bb1d89bd544694e89beb3e6e
---
M doc/examples/modem/modem.cfg
M src/host/layer23/include/osmocom/bb/common/Makefile.am
A src/host/layer23/include/osmocom/bb/common/apn.h
M src/host/layer23/include/osmocom/bb/common/ms.h
M src/host/layer23/include/osmocom/bb/common/settings.h
M src/host/layer23/include/osmocom/bb/modem/vty.h
M src/host/layer23/src/common/Makefile.am
A src/host/layer23/src/common/apn.c
M src/host/layer23/src/common/ms.c
M src/host/layer23/src/common/settings.c
M src/host/layer23/src/modem/app_modem.c
M src/host/layer23/src/modem/vty.c
12 files changed, 381 insertions(+), 3 deletions(-)
diff --git a/doc/examples/modem/modem.cfg b/doc/examples/modem/modem.cfg
index d2cb81f..a441b0e 100644
--- a/doc/examples/modem/modem.cfg
+++ b/doc/examples/modem/modem.cfg
@@ -6,4 +6,9 @@
no login
!
ms 1
+ apn internet
+ tun-device modem4
+! tun-netns netns_modem4
+ type-support v4
+ no shutdown
no shutdown
diff --git a/src/host/layer23/include/osmocom/bb/common/Makefile.am b/src/host/layer23/include/osmocom/bb/common/Makefile.am
index 270f079..28caf78 100644
--- a/src/host/layer23/include/osmocom/bb/common/Makefile.am
+++ b/src/host/layer23/include/osmocom/bb/common/Makefile.am
@@ -1,4 +1,5 @@
noinst_HEADERS = \
+ apn.h \
l1ctl.h \
l1l2_interface.h \
l23_app.h \
diff --git a/src/host/layer23/include/osmocom/bb/common/apn.h b/src/host/layer23/include/osmocom/bb/common/apn.h
new file mode 100644
index 0000000..4a92a62
--- /dev/null
+++ b/src/host/layer23/include/osmocom/bb/common/apn.h
@@ -0,0 +1,56 @@
+/* APN Context
+ * (C) 2023 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ *
+ * 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.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/select.h>
+
+struct osmocom_ms;
+
+#define APN_TYPE_IPv4 0x01 /* v4-only */
+#define APN_TYPE_IPv6 0x02 /* v6-only */
+#define APN_TYPE_IPv4v6 0x04 /* v4v6 dual-stack */
+
+struct osmobb_apn {
+ /* list of APNs inside MS */
+ struct llist_head list;
+ /* back-pointer to MS */
+ struct osmocom_ms *ms;
+
+ bool started;
+
+ struct {
+ /* Primary name */
+ char *name;
+ /* name of the network device */
+ char *dev_name;
+ /* netns name of the network device, NULL = default netns */
+ char *dev_netns_name;
+ /* types supported address types on this APN */
+ uint32_t apn_type_mask;
+ /* administratively shutdown (true) or not (false) */
+ bool shutdown;
+ /* transmit G-PDU sequence numbers (true) or not (false) */
+ bool tx_gpdu_seq;
+ } cfg;
+};
+
+struct osmobb_apn *apn_alloc(struct osmocom_ms *ms, const char *name);
+void apn_free(struct osmobb_apn *apn);
+int apn_start(struct osmobb_apn *apn);
+int apn_stop(struct osmobb_apn *apn);
diff --git a/src/host/layer23/include/osmocom/bb/common/ms.h b/src/host/layer23/include/osmocom/bb/common/ms.h
index a706a4c..30bb514 100644
--- a/src/host/layer23/include/osmocom/bb/common/ms.h
+++ b/src/host/layer23/include/osmocom/bb/common/ms.h
@@ -90,6 +90,9 @@
struct osmomncc_entity mncc_entity;
struct llist_head trans_list;
+ /* GPRS */
+ struct gprs_settings gprs;
+
/* Audio I/O */
struct gapk_io_state *gapk_io;
diff --git a/src/host/layer23/include/osmocom/bb/common/settings.h b/src/host/layer23/include/osmocom/bb/common/settings.h
index 8ebf049..523ad8e 100644
--- a/src/host/layer23/include/osmocom/bb/common/settings.h
+++ b/src/host/layer23/include/osmocom/bb/common/settings.h
@@ -5,6 +5,7 @@
#include <osmocom/core/linuxlist.h>
struct osmocom_ms;
+struct osmobb_apn;
#define MOB_C7_DEFLT_ANY_TIMEOUT 30
@@ -180,6 +181,14 @@
char *gsm_check_imei(const char *imei, const char *sv);
int gsm_random_imei(struct gsm_settings *set);
+struct gprs_settings {
+ struct llist_head apn_list;
+};
+
+int gprs_settings_init(struct osmocom_ms *ms);
+int gprs_settings_fi(struct osmocom_ms *ms);
+struct osmobb_apn *ms_find_apn_by_name(struct osmocom_ms *ms, const char *apn_name);
+
extern char *layer2_socket_path;
#endif /* _settings_h */
diff --git a/src/host/layer23/include/osmocom/bb/modem/vty.h b/src/host/layer23/include/osmocom/bb/modem/vty.h
index 14ec624..5b69af6 100644
--- a/src/host/layer23/include/osmocom/bb/modem/vty.h
+++ b/src/host/layer23/include/osmocom/bb/modem/vty.h
@@ -1,3 +1,10 @@
#pragma once
+#include <osmocom/bb/common/vty.h>
+
+enum modem_vty_node {
+ APN_NODE = _LAST_L23VTY_NODE + 1,
+};
+
int modem_vty_init(void);
+int modem_vty_go_parent(struct vty *vty);
diff --git a/src/host/layer23/src/common/Makefile.am b/src/host/layer23/src/common/Makefile.am
index 9abc802..94eeec8 100644
--- a/src/host/layer23/src/common/Makefile.am
+++ b/src/host/layer23/src/common/Makefile.am
@@ -13,6 +13,7 @@
noinst_LIBRARIES = liblayer23.a
liblayer23_a_SOURCES = \
+ apn.c \
gps.c \
l1ctl.c \
l1l2_interface.c \
diff --git a/src/host/layer23/src/common/apn.c b/src/host/layer23/src/common/apn.c
new file mode 100644
index 0000000..f60053d
--- /dev/null
+++ b/src/host/layer23/src/common/apn.c
@@ -0,0 +1,60 @@
+/*
+ * (C) 2023 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ *
+ * 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.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include <talloc.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/apn.h>
+#include <osmocom/bb/common/ms.h>
+
+struct osmobb_apn *apn_alloc(struct osmocom_ms *ms, const char *name)
+{
+ struct osmobb_apn *apn;
+ apn = talloc_zero(ms, struct osmobb_apn);
+ if (!apn)
+ return NULL;
+
+ talloc_set_name(apn, "apn_%s", name);
+ apn->cfg.name = talloc_strdup(apn, name);
+ apn->cfg.shutdown = true;
+ apn->cfg.tx_gpdu_seq = true;
+
+ apn->ms = ms;
+ llist_add_tail(&apn->list, &ms->gprs.apn_list);
+ return apn;
+}
+
+void apn_free(struct osmobb_apn *apn)
+{
+ llist_del(&apn->list);
+ talloc_free(apn);
+}
+
+int apn_start(struct osmobb_apn *apn)
+{
+ return 0;
+}
+
+int apn_stop(struct osmobb_apn *apn)
+{
+ return 0;
+}
diff --git a/src/host/layer23/src/common/ms.c b/src/host/layer23/src/common/ms.c
index 558505a..ee27096 100644
--- a/src/host/layer23/src/common/ms.c
+++ b/src/host/layer23/src/common/ms.c
@@ -24,6 +24,12 @@
/* Default value be configured by cmdline arg: */
uint16_t cfg_test_arfcn = 871;
+static int osmocom_ms_talloc_destructor(struct osmocom_ms *ms)
+{
+ gprs_settings_fi(ms);
+ return 0;
+}
+
struct osmocom_ms *osmocom_ms_alloc(void *ctx, const char *name)
{
struct osmocom_ms *ms;
@@ -32,6 +38,7 @@
if (!ms)
return NULL;
talloc_set_name(ms, "ms_%s", name);
+ talloc_set_destructor(ms, osmocom_ms_talloc_destructor);
ms->name = talloc_strdup(ms, name);
ms->test_arfcn = cfg_test_arfcn;
@@ -50,6 +57,7 @@
gsm_support_init(ms);
gsm_settings_init(ms);
+ gprs_settings_init(ms);
return ms;
}
diff --git a/src/host/layer23/src/common/settings.c b/src/host/layer23/src/common/settings.c
index fd7177d..d391f7d 100644
--- a/src/host/layer23/src/common/settings.c
+++ b/src/host/layer23/src/common/settings.c
@@ -20,13 +20,12 @@
#include <string.h>
#include <osmocom/core/talloc.h>
-#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/common/settings.h>
#include <osmocom/bb/common/utils.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/apn.h>
#include <osmocom/bb/common/ms.h>
-#include <osmocom/bb/common/networks.h>
#include <osmocom/bb/common/l1l2_interface.h>
/* Used to set default path globally through cmdline */
@@ -220,3 +219,35 @@
{ AUDIO_IOF_TI, "ti" },
{ 0x00, NULL}
};
+
+
+int gprs_settings_init(struct osmocom_ms *ms)
+{
+ struct gprs_settings *set = &ms->gprs;
+ INIT_LLIST_HEAD(&set->apn_list);
+
+ return 0;
+}
+
+int gprs_settings_fi(struct osmocom_ms *ms)
+{
+ struct gprs_settings *set = &ms->gprs;
+ struct osmobb_apn *apn;
+ while ((apn = llist_first_entry_or_null(&set->apn_list, struct osmobb_apn, list))) {
+ /* free calls llist_del(): */
+ apn_free(apn);
+ }
+ return 0;
+}
+
+struct osmobb_apn *ms_find_apn_by_name(struct osmocom_ms *ms, const char *apn_name)
+{
+ struct gprs_settings *set = &ms->gprs;
+ struct osmobb_apn *apn;
+
+ llist_for_each_entry(apn, &set->apn_list, list) {
+ if (strcmp(apn->cfg.name, apn_name) == 0)
+ return apn;
+ }
+ return NULL;
+}
diff --git a/src/host/layer23/src/modem/app_modem.c b/src/host/layer23/src/modem/app_modem.c
index 7dcda17..d7c9a29 100644
--- a/src/host/layer23/src/modem/app_modem.c
+++ b/src/host/layer23/src/modem/app_modem.c
@@ -509,6 +509,7 @@
static struct vty_app_info _modem_vty_info = {
.name = "modem",
.version = PACKAGE_VERSION,
+ .go_parent_cb = modem_vty_go_parent,
};
static struct l23_app_info info = {
diff --git a/src/host/layer23/src/modem/vty.c b/src/host/layer23/src/modem/vty.c
index 4304876..bd8afd8 100644
--- a/src/host/layer23/src/modem/vty.c
+++ b/src/host/layer23/src/modem/vty.c
@@ -25,14 +25,200 @@
#include <osmocom/vty/command.h>
#include <osmocom/bb/common/vty.h>
+#include <osmocom/bb/common/apn.h>
#include <osmocom/bb/common/ms.h>
+#include <osmocom/bb/modem/vty.h>
+static struct cmd_node apn_node = {
+ APN_NODE,
+ "%s(apn)# ",
+ 1
+};
+
+int modem_vty_go_parent(struct vty *vty)
+{
+ struct osmobb_apn *apn;
+
+ switch (vty->node) {
+ case APN_NODE:
+ apn = vty->index;
+ vty->index = apn->ms;
+ vty->node = MS_NODE;
+ break;
+ }
+ return vty->node;
+}
+
+/* per APN config */
+DEFUN(cfg_ms_apn, cfg_ms_apn_cmd, "apn APN_NAME",
+ "Configure an APN\n"
+ "Name of APN\n")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct osmobb_apn *apn;
+
+ apn = ms_find_apn_by_name(ms, argv[0]);
+ if (!apn)
+ apn = apn_alloc(ms, argv[0]);
+ if (!apn) {
+ vty_out(vty, "Unable to create APN '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty->index = apn;
+ vty->node = APN_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_no_apn, cfg_ms_no_apn_cmd, "no apn APN_NAME",
+ NO_STR "Configure an APN\n"
+ "Name of APN\n")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct osmobb_apn *apn;
+
+ apn = ms_find_apn_by_name(ms, argv[0]);
+ if (!apn) {
+ vty_out(vty, "Unable to find APN '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ apn_free(apn);
+
+ 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 osmobb_apn *apn = (struct osmobb_apn *) vty->index;
+ osmo_talloc_replace_string(apn, &apn->cfg.dev_name, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_apn_tun_netns_name, cfg_apn_tun_netns_name_cmd,
+ "tun-netns NAME",
+ "Configure tun device network namespace name\n"
+ "TUN device network namespace name")
+{
+ struct osmobb_apn *apn = (struct osmobb_apn *) vty->index;
+ osmo_talloc_replace_string(apn, &apn->cfg.dev_netns_name, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_apn_no_tun_netns_name, cfg_apn_no_tun_netns_name_cmd,
+ "no tun-netns",
+ "Configure tun device to use default network namespace name\n")
+{
+ struct osmobb_apn *apn = (struct osmobb_apn *) vty->index;
+ TALLOC_FREE(apn->cfg.dev_netns_name);
+ return CMD_SUCCESS;
+}
+
+static const struct value_string pdp_type_names[] = {
+ { APN_TYPE_IPv4, "v4" },
+ { APN_TYPE_IPv6, "v6" },
+ { APN_TYPE_IPv4v6, "v4v6" },
+ { 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 osmobb_apn *apn = (struct osmobb_apn *) 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_shutdown, cfg_apn_shutdown_cmd,
+ "shutdown",
+ "Put the APN in administrative shut-down\n")
+{
+ struct osmobb_apn *apn = (struct osmobb_apn *) vty->index;
+
+ if (!apn->cfg.shutdown) {
+ if (apn_stop(apn)) {
+ 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 osmobb_apn *apn = (struct osmobb_apn *) vty->index;
+
+ if (apn->cfg.shutdown) {
+ if (!apn->cfg.dev_name) {
+ vty_out(vty, "%% Failed to start APN, tun-device is not configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ 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 config_write_apn(struct vty *vty, const struct osmobb_apn *apn)
+{
+ unsigned int i;
+
+ vty_out(vty, " apn %s%s", apn->cfg.name, VTY_NEWLINE);
+
+ if (apn->cfg.dev_name)
+ vty_out(vty, " tun-device %s%s", apn->cfg.dev_name, VTY_NEWLINE);
+ if (apn->cfg.dev_netns_name)
+ vty_out(vty, " tun-netns %s%s", apn->cfg.dev_netns_name, VTY_NEWLINE);
+
+ for (i = 0; i < 32; i++) {
+ if (!(apn->cfg.apn_type_mask & (UINT32_C(1) << i)))
+ continue;
+ vty_out(vty, " type-support %s%s", get_value_string(pdp_type_names, (UINT32_C(1) << i)),
+ VTY_NEWLINE);
+ }
+
+ /* must be last */
+ vty_out(vty, " %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE);
+}
+
+static void config_write_ms(struct vty *vty, const struct osmocom_ms *ms)
+{
+ struct osmobb_apn *apn;
+
+ vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
+
+ l23_vty_config_write_ms_node_contents(vty, ms, " ");
+
+ llist_for_each_entry(apn, &ms->gprs.apn_list, list)
+ config_write_apn(vty, apn);
+
+ l23_vty_config_write_ms_node_contents_final(vty, ms, " ");
+}
static int config_write(struct vty *vty)
{
struct osmocom_ms *ms;
llist_for_each_entry(ms, &ms_list, entity)
- l23_vty_config_write_ms_node(vty, ms, "");
+ config_write_ms(vty, ms);
return CMD_SUCCESS;
}
@@ -45,5 +231,15 @@
install_element_ve(&l23_show_ms_cmd);
install_element(CONFIG_NODE, &l23_cfg_ms_cmd);
+ install_element(MS_NODE, &cfg_ms_apn_cmd);
+ install_element(MS_NODE, &cfg_ms_no_apn_cmd);
+ install_node(&apn_node, NULL);
+ install_element(APN_NODE, &cfg_apn_tun_dev_name_cmd);
+ install_element(APN_NODE, &cfg_apn_tun_netns_name_cmd);
+ install_element(APN_NODE, &cfg_apn_no_tun_netns_name_cmd);
+ install_element(APN_NODE, &cfg_apn_type_support_cmd);
+ install_element(APN_NODE, &cfg_apn_shutdown_cmd);
+ install_element(APN_NODE, &cfg_apn_no_shutdown_cmd);
+
return 0;
}
To view, visit change 30992. To unsubscribe, or for help writing mail filters, visit settings.