pespin submitted this change.
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
---
M src/host/layer23/include/osmocom/bb/common/apn.h
M src/host/layer23/include/osmocom/bb/common/l23_app.h
M src/host/layer23/include/osmocom/bb/common/logging.h
M src/host/layer23/src/common/apn.c
M src/host/layer23/src/common/logging.c
M src/host/layer23/src/mobile/app_mobile.c
M src/host/layer23/src/modem/app_modem.c
7 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/src/host/layer23/include/osmocom/bb/common/apn.h b/src/host/layer23/include/osmocom/bb/common/apn.h
index 4a92a62..94784ef 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 @@
/* 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 46c3f44..d442e7e 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 @@
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 e968528..5259f35 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 @@
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 f60053d..169e30e 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 @@
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 @@
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 56f0322..34c171f 100644
--- a/src/host/layer23/src/common/logging.c
+++ b/src/host/layer23/src/common/logging.c
@@ -147,6 +147,12 @@
.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 5bb1920..285672d 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -508,6 +508,11 @@
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 d7c9a29..6b8466d 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 @@
} 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 @@
.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)
To view, visit change 30996. To unsubscribe, or for help writing mail filters, visit settings.