summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2023-01-17 11:01:37 +0100
committerPau Espin Pedrol <pespin@sysmocom.de>2023-01-19 20:02:07 +0100
commit3da09d1f7ee6129f8ae45e69a96dc58d602c40d9 (patch)
treeb311e9104a6f822ee40af033383afc5130af5910
parent6327f40be6673a93090317d47bf6ca3f17a90f24 (diff)
layer23: Initial integration of tun device
Use the new tundev API from libosmocore to create tun devices for each configured (and enbled) APN. No address nor routes are yet set on the tun devices because we still lack GMM/SNDCP/LLC/RLCMAC layers to negotiate them. A follow up patch will add some code to interact with the SNDCP layer. Depends: libosmocore.git Change-Id I3463271666df1e85746fb7b06ec45a17024b8c53 Change-Id: I86cac406843157aa2e51727cf8ccac9804d7961d
-rw-r--r--src/host/layer23/include/osmocom/bb/common/apn.h8
-rw-r--r--src/host/layer23/include/osmocom/bb/common/l23_app.h3
-rw-r--r--src/host/layer23/include/osmocom/bb/common/logging.h1
-rw-r--r--src/host/layer23/src/common/apn.c49
-rw-r--r--src/host/layer23/src/common/logging.c6
-rw-r--r--src/host/layer23/src/mobile/app_mobile.c5
-rw-r--r--src/host/layer23/src/modem/app_modem.c53
7 files changed, 124 insertions, 1 deletions
diff --git a/src/host/layer23/include/osmocom/bb/common/apn.h b/src/host/layer23/include/osmocom/bb/common/apn.h
index 4a92a624..94784ef7 100644
--- a/src/host/layer23/include/osmocom/bb/common/apn.h
+++ b/src/host/layer23/include/osmocom/bb/common/apn.h
@@ -19,6 +19,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/select.h>
+#include <osmocom/core/tun.h>
struct osmocom_ms;
@@ -48,9 +49,16 @@ struct osmobb_apn {
/* transmit G-PDU sequence numbers (true) or not (false) */
bool tx_gpdu_seq;
} cfg;
+ struct osmo_tundev *tun;
};
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);
+
+#define LOGPAPN(level, apn, fmt, args...) \
+ LOGP(DTUN, level, "APN(%s): " fmt, (apn)->cfg.name, ## args)
+
+#define LOGTUN(level, tun, fmt, args...) \
+ LOGP(DTUN, level, "TUN(%s): " fmt, osmo_tundev_get_name(tun), ## args)
diff --git a/src/host/layer23/include/osmocom/bb/common/l23_app.h b/src/host/layer23/include/osmocom/bb/common/l23_app.h
index 46c3f44b..d442e7e2 100644
--- a/src/host/layer23/include/osmocom/bb/common/l23_app.h
+++ b/src/host/layer23/include/osmocom/bb/common/l23_app.h
@@ -1,6 +1,8 @@
#ifndef _L23_APP_H
#define _L23_APP_H
+#include <osmocom/core/tun.h>
+
struct option;
struct vty_app_info;
@@ -37,6 +39,7 @@ struct l23_app_info {
int (*cfg_getopt_opt)(struct option **options);
int (*cfg_handle_opt)(int c,const char *optarg);
int (*vty_init)(void);
+ osmo_tundev_data_ind_cb_t tun_data_ind_cb;
};
extern struct l23_app_info *l23_app_info();
diff --git a/src/host/layer23/include/osmocom/bb/common/logging.h b/src/host/layer23/include/osmocom/bb/common/logging.h
index e9685284..5259f35e 100644
--- a/src/host/layer23/include/osmocom/bb/common/logging.h
+++ b/src/host/layer23/include/osmocom/bb/common/logging.h
@@ -26,6 +26,7 @@ enum {
DPRIM,
DLUA,
DGAPK,
+ DTUN,
};
extern const struct log_info log_info;
diff --git a/src/host/layer23/src/common/apn.c b/src/host/layer23/src/common/apn.c
index f60053d9..169e30e9 100644
--- a/src/host/layer23/src/common/apn.c
+++ b/src/host/layer23/src/common/apn.c
@@ -18,13 +18,15 @@
#include <stdint.h>
#include <errno.h>
#include <string.h>
-#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
#include <talloc.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/apn.h>
#include <osmocom/bb/common/ms.h>
+#include <osmocom/bb/common/l23_app.h>
struct osmobb_apn *apn_alloc(struct osmocom_ms *ms, const char *name)
{
@@ -38,6 +40,13 @@ struct osmobb_apn *apn_alloc(struct osmocom_ms *ms, const char *name)
apn->cfg.shutdown = true;
apn->cfg.tx_gpdu_seq = true;
+ apn->tun = osmo_tundev_alloc(apn, name);
+ if (!apn->tun) {
+ talloc_free(apn);
+ return NULL;
+ }
+ osmo_tundev_set_priv_data(apn->tun, apn);
+
apn->ms = ms;
llist_add_tail(&apn->list, &ms->gprs.apn_list);
return apn;
@@ -46,15 +55,53 @@ struct osmobb_apn *apn_alloc(struct osmocom_ms *ms, const char *name)
void apn_free(struct osmobb_apn *apn)
{
llist_del(&apn->list);
+ osmo_tundev_free(apn->tun);
talloc_free(apn);
}
int apn_start(struct osmobb_apn *apn)
{
+ struct l23_app_info *app_info = l23_app_info();
+ int rc;
+
+ if (apn->started)
+ return 0;
+
+ LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->cfg.dev_name);
+ /* Set TUN library callback. Must have been configured by the app: */
+ OSMO_ASSERT(app_info && app_info->tun_data_ind_cb);
+ osmo_tundev_set_data_ind_cb(apn->tun, app_info->tun_data_ind_cb);
+ osmo_tundev_set_dev_name(apn->tun, apn->cfg.dev_name);
+ osmo_tundev_set_netns_name(apn->tun, apn->cfg.dev_netns_name);
+
+ rc = osmo_tundev_open(apn->tun);
+ if (rc < 0) {
+ LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
+ return -1;
+ }
+
+ LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", osmo_tundev_get_dev_name(apn->tun));
+
+ /* TODO: set IP addresses on the tun device once we receive them from GGSN. See
+ osmo-ggsn.git's apn_start() */
+
+ LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n");
+ apn->started = true;
return 0;
}
int apn_stop(struct osmobb_apn *apn)
{
+ LOGPAPN(LOGL_NOTICE, apn, "Stopping\n");
+
+ /* shutdown whatever old state might be left */
+ if (apn->tun) {
+ /* release tun device */
+ LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n",
+ osmo_tundev_get_dev_name(apn->tun));
+ osmo_tundev_close(apn->tun);
+ }
+
+ apn->started = false;
return 0;
}
diff --git a/src/host/layer23/src/common/logging.c b/src/host/layer23/src/common/logging.c
index 56f03224..34c171f6 100644
--- a/src/host/layer23/src/common/logging.c
+++ b/src/host/layer23/src/common/logging.c
@@ -147,6 +147,12 @@ static const struct log_info_cat default_categories[] = {
.color = "\033[0;36m",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
+ [DTUN] = {
+ .name = "DTUN",
+ .description = "Tunnel interface",
+ .color = "\033[0;37m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
};
const struct log_info log_info = {
diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c
index 5bb19209..285672d7 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -508,6 +508,11 @@ int l23_app_init(const char *config_file)
return 0;
}
+struct l23_app_info *l23_app_info(void)
+{
+ return NULL; /* TODO: implement mobile as a full l23_app. */
+}
+
void mobile_set_started(struct osmocom_ms *ms, bool state)
{
ms->started = state;
diff --git a/src/host/layer23/src/modem/app_modem.c b/src/host/layer23/src/modem/app_modem.c
index d7c9a29d..6b8466d7 100644
--- a/src/host/layer23/src/modem/app_modem.c
+++ b/src/host/layer23/src/modem/app_modem.c
@@ -23,9 +23,14 @@
#include <errno.h>
#include <stdio.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
#include <osmocom/core/msgb.h>
#include <osmocom/core/signal.h>
#include <osmocom/core/application.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/tun.h>
#include <osmocom/vty/vty.h>
#include <osmocom/gsm/rsl.h>
@@ -42,6 +47,7 @@
#include <osmocom/bb/common/l23_app.h>
#include <osmocom/bb/common/l1l2_interface.h>
#include <osmocom/bb/common/sysinfo.h>
+#include <osmocom/bb/common/apn.h>
#include <osmocom/bb/modem/vty.h>
#include <l1ctl_proto.h>
@@ -60,6 +66,52 @@ static struct {
} chan_req;
} app_data;
+/* Local network-originated IP packet, needs to be sent via SNDCP/LLC (GPRS) towards GSM network */
+static int modem_tun_data_ind_cb(struct osmo_tundev *tun, struct msgb *msg)
+{
+ struct osmobb_apn *apn = (struct osmobb_apn *)osmo_tundev_get_priv_data(tun);
+ struct osmo_sockaddr dst;
+ struct iphdr *iph = (struct iphdr *)msgb_data(msg);
+ struct ip6_hdr *ip6h = (struct ip6_hdr *)msgb_data(msg);
+ size_t pkt_len = msgb_length(msg);
+ uint8_t pref_offset;
+ char addrstr[INET6_ADDRSTRLEN];
+ int rc = 0;
+
+ switch (iph->version) {
+ case 4:
+ if (pkt_len < sizeof(*iph) || pkt_len < 4*iph->ihl)
+ return -1;
+ dst.u.sin.sin_family = AF_INET;
+ dst.u.sin.sin_addr.s_addr = iph->daddr;
+ break;
+ case 6:
+ /* Due to the fact that 3GPP requires an allocation of a
+ * /64 prefix to each MS, we must instruct
+ * ippool_getip() below to match only the leading /64
+ * prefix, i.e. the first 8 bytes of the address. If the ll addr
+ * is used, then the match should be done on the trailing 64
+ * bits. */
+ dst.u.sin6.sin6_family = AF_INET6;
+ pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
+ memcpy(&dst.u.sin6.sin6_addr, ((uint8_t *)&ip6h->ip6_dst) + pref_offset, 8);
+ break;
+ default:
+ LOGTUN(LOGL_NOTICE, tun, "non-IPv%u packet received\n", iph->version);
+ rc = -1;
+ goto free_ret;
+ }
+
+ LOGPAPN(LOGL_DEBUG, apn, "system wants to transmit IPv%c pkt to %s (%zu bytes)\n",
+ iph->version == 4 ? '4' : '6', osmo_sockaddr_ntop(&dst.u.sa, addrstr), pkt_len);
+
+ /* TODO: prepare & transmit SNDCP UNITDATA.req */
+
+free_ret:
+ msgb_free(msg);
+ return rc;
+}
+
/* Generate a 8-bit CHANNEL REQUEST message as per 3GPP TS 44.018, 9.1.8 */
static uint8_t gen_chan_req(bool single_block)
{
@@ -517,6 +569,7 @@ static struct l23_app_info info = {
.cfg_supported = &l23_cfg_supported,
.vty_info = &_modem_vty_info,
.vty_init = modem_vty_init,
+ .tun_data_ind_cb = modem_tun_data_ind_cb,
};
struct l23_app_info *l23_app_info(void)