pppd: Add pppopptp-android plugin

mtpd tool was reworked to use mainline kernel implementation of PPTP.
So now mtpd relies on pppopptp-android plugin. This patch implements
this plugin from scratch, as we can't use accel-pptp version [1],
because it is licensed under GPL and can't be adopted in Android.

[1] http://accel-pptp.sourceforge.net/

Change-Id: I7b9aa4ccfdd94a221e2d4a6272a1b2fd280341f6
Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
diff --git a/pppd/Android.bp b/pppd/Android.bp
index d995a0d..4e01738 100644
--- a/pppd/Android.bp
+++ b/pppd/Android.bp
@@ -77,7 +77,10 @@
     ],
 
     ldflags: ["-rdynamic"],
-    required: ["pppol2tp-android"],
+    required: [
+        "pppol2tp-android",
+        "pppopptp-android",
+    ],
 }
 
 cc_library_shared {
@@ -86,3 +89,10 @@
     srcs: ["plugins/pppol2tp-android/pppol2tp-android.c"],
     allow_undefined_symbols: true,
 }
+
+cc_library_shared {
+    name: "pppopptp-android",
+    defaults: ["ppp_defaults"],
+    srcs: ["plugins/pppopptp-android/pppopptp-android.c"],
+    allow_undefined_symbols: true,
+}
diff --git a/pppd/README.pppopptp b/pppd/README.pppopptp
new file mode 100644
index 0000000..2d24578
--- /dev/null
+++ b/pppd/README.pppopptp
@@ -0,0 +1,25 @@
+PPPoPPTP-Android plugin
+=======================
+
+This plugin was written for AOSP project from scratch. It has nothing to do with
+accel-pptp plugin [1].
+
+This plugin adds support for upstream kernel PPTP implementation in pppd daemon.
+Only PNS (client) part of PPTP is implemented, as we don't use Android devices
+in PAC mode.
+
+In general case, the execution flow for VPN startup on Android devices is:
+ 1. Run PPTP client (mtpd)
+ 2. mtpd obtains remote Call ID on OCRP (Outgoing-Call-Reply) packet
+ 3. mtpd creates PPTP socket
+ 4. mtpd runs pppd, passing PPTP socket as to pppopptp-android (as parameter)
+ 5. pppd dlopen() pppopptp-android plugin (because it received corresponding
+    arguments from mtpd)
+
+Main task of this plugin is to obtain PPTP socket FD from mtpd and pass it
+back to pppd when .connect() callback is executed.
+
+All control packets are handled in mtpd. PPP packets (like LCP) are handled in
+pppd. Data packets are handled by kernel PPTP driver.
+
+[1] http://accel-pptp.sourceforge.net/
diff --git a/pppd/plugins/pppopptp-android/pppopptp-android.c b/pppd/plugins/pppopptp-android/pppopptp-android.c
new file mode 100644
index 0000000..2d4e3bf
--- /dev/null
+++ b/pppd/plugins/pppopptp-android/pppopptp-android.c
@@ -0,0 +1,65 @@
+/*
+ * 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 <unistd.h>
+
+char pppd_version[] = VERSION;
+
+static struct channel pppopptp_channel;
+
+/* Option variables */
+static int pptp_socket = -1;
+
+static option_t pppopptp_options[] =
+{
+	{ "pptp_socket", o_int, &pptp_socket, "PPTP socket FD", OPT_PRIO },
+	{ NULL }
+};
+
+static int pptp_connect(void)
+{
+	info("Using PPPoPPTP (socket = %d)", pptp_socket);
+	return pptp_socket;
+}
+
+static void pptp_disconnect(void)
+{
+	if (pptp_socket != -1) {
+		close(pptp_socket);
+		pptp_socket = -1;
+	}
+}
+
+void plugin_init(void)
+{
+	add_options(pppopptp_options);
+	the_channel = &pppopptp_channel;
+}
+
+static struct channel pppopptp_channel = {
+	.options		= pppopptp_options,
+	.process_extra_options	= NULL,
+	.check_options		= NULL,
+	.connect		= pptp_connect,
+	.disconnect		= pptp_disconnect,
+	.establish_ppp		= generic_establish_ppp,
+	.disestablish_ppp	= generic_disestablish_ppp,
+	.send_config		= NULL,
+	.recv_config		= NULL,
+	.close			= NULL,
+	.cleanup		= NULL,
+};