summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Protsenko <semen.protsenko@linaro.org>2018-07-26 22:14:19 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-07-26 22:14:19 -0700
commit3df1710818f44d2a23bfd11ba02d0c1b169e7b70 (patch)
tree656403391258cb029f353eedb7e1aea28d189961
parentc712b12e94d682c306b04aabf4ffac184dd2d75f (diff)
parentad51db40004c50d92207f4b553cc41469c4a7f5e (diff)
downloadppp-3df1710818f44d2a23bfd11ba02d0c1b169e7b70.tar.gz
pppd: Add pppol2tp-android plugin am: 0c9566a278 am: b6a7858352
am: ad51db4000 Change-Id: Ic34f170d7794b33d9409cb13b99e62c2024a0f15
-rw-r--r--pppd/README.pppol2tp33
-rw-r--r--pppd/plugins/pppol2tp-android/pppol2tp-android.c129
2 files changed, 162 insertions, 0 deletions
diff --git a/pppd/README.pppol2tp b/pppd/README.pppol2tp
new file mode 100644
index 0000000..e82548a
--- /dev/null
+++ b/pppd/README.pppol2tp
@@ -0,0 +1,33 @@
+PPPoL2TP-Android plugin
+=======================
+
+This PPPoL2TP-Android plugin was written for AOSP project from scratch. It has
+nothing to do with pppol2tp plugin from upstream ppp project [1].
+
+This plugin adds support for upstream kernel L2TP implementation in pppd
+daemon. Only LAC part of L2TP is implemented, as we don't use Android devices
+in LNS mode.
+
+In general case, the execution flow for VPN startup on Android devices is:
+ 1. Run IPSec client (racoon)
+ 2. Run L2TP client (mtpd)
+ 3. mtpd obtains "remote tunnel ID" and "remote session ID" from L2TP server
+ 4. mtpd creates L2TP sockets (see [2] for details):
+ - tunnel management PPPoX socket
+ - session PPPoX data socket
+ 5. mtpd runs pppd, passing arguments for pppol2tp-android plugin
+ 6. pppd dlopen() pppol2tp-android plugin (because it receives corresponding\
+ arguments from mtpd)
+
+Main task of this plugin is to obtain session_fd socket from mtpd and pass it
+back to pppd when .connect() callback is executed. In this respect it's similar
+to old pppox.c implementation. The differences are next:
+ 1. pppol2tp-android also obtains the second socket (for tunnel management)
+ which allows us to handle it properly
+ 2. pppol2tp-android handles the setting of MTU/MRU size (which can be passed
+ to the plugin with pppd parameters) via kernel L2TP implementation
+ 3. pppol2tp-android plugin is actually loaded dynamically with dlopen(),
+ as opposed to pppox.c which is hard-coded into pppd code
+
+[1] https://github.com/paulusmack/ppp
+[2] https://www.kernel.org/doc/Documentation/networking/l2tp.txt
diff --git a/pppd/plugins/pppol2tp-android/pppol2tp-android.c b/pppd/plugins/pppol2tp-android/pppol2tp-android.c
new file mode 100644
index 0000000..6a984de
--- /dev/null
+++ b/pppd/plugins/pppol2tp-android/pppol2tp-android.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/if_ppp.h>
+
+char pppd_version[] = VERSION;
+
+static struct channel pppol2tp_channel;
+
+/* Options variables */
+static int session_fd = -1;
+static int tunnel_fd = -1;
+static int session_id = 0;
+static int tunnel_id = 0;
+
+static int pppol2tp_set_session_fd(char **argv);
+
+static option_t pppol2tp_options[] = {
+ { "session_fd", o_special, pppol2tp_set_session_fd,
+ "Session PPPoX data socket", OPT_DEVNAM },
+ { "tunnel_fd", o_int, &tunnel_fd,
+ "Tunnel management PPPoX socket", OPT_PRIO },
+ { "session_id", o_int, &session_id, "Session ID", OPT_PRIO },
+ { "tunnel_id", o_int, &tunnel_id, "Tunnel ID", OPT_PRIO },
+ { NULL }
+};
+
+static int pppol2tp_set_session_fd(char **argv)
+{
+ if (!int_option(*argv, &session_fd))
+ return 0;
+
+ info("Using PPPoL2TP (socket = %d)", session_fd);
+ the_channel = &pppol2tp_channel;
+ return 1;
+}
+
+/**
+ * Set the MRU on the PPP network interface.
+ *
+ * @param mru New MRU value
+ *
+ * @note netif_set_mru() is missing in sys-linux.c, so implement it manually
+ * @note See net/l2tp/l2tp_ppp.c:pppol2tp_session_ioctl() in kernel for details
+ */
+static void pppol2tp_set_mru(int mru)
+{
+ int res;
+
+ if (ifunit < 0)
+ return;
+
+ res = ioctl(session_fd, PPPIOCSMRU, (caddr_t)&mru);
+ if (res < 0)
+ error("ioctl(PPPIOCSMRU): %m (line %d)", __LINE__);
+}
+
+/* Set the transmit-side PPP parameters of the channel */
+static void pppol2tp_send_config(int mtu, u_int32_t accm, int pcomp, int accomp)
+{
+ int new_mtu = lcp_allowoptions[0].mru; /* "mtu" pppd option */
+
+ if (new_mtu <= PPP_MAXMTU && new_mtu >= PPP_MINMTU)
+ netif_set_mtu(ifunit, new_mtu);
+}
+
+/* Set the receive-side PPP parameters of the channel */
+static void pppol2tp_recv_config(int mru, u_int32_t accm, int pcomp, int accomp)
+{
+ int new_mru = lcp_wantoptions[0].mru; /* "mru" pppd option */
+
+ if (new_mru <= PPP_MAXMRU && new_mru >= PPP_MINMRU)
+ pppol2tp_set_mru(new_mru);
+}
+
+static int pppol2tp_connect(void)
+{
+ return session_fd;
+}
+
+static void pppol2tp_disconnect(void)
+{
+ if (session_fd != -1) {
+ close(session_fd);
+ session_fd = -1;
+ }
+
+ if (tunnel_fd != -1) {
+ close(tunnel_fd);
+ tunnel_fd = -1;
+ }
+}
+
+void plugin_init(void)
+{
+ add_options(pppol2tp_options);
+}
+
+static struct channel pppol2tp_channel = {
+ .options = pppol2tp_options,
+ .process_extra_options = NULL,
+ .check_options = NULL,
+ .connect = pppol2tp_connect,
+ .disconnect = pppol2tp_disconnect,
+ .establish_ppp = generic_establish_ppp,
+ .disestablish_ppp = generic_disestablish_ppp,
+ .send_config = pppol2tp_send_config,
+ .recv_config = pppol2tp_recv_config,
+ .cleanup = NULL,
+ .close = NULL,
+};