Merge pie-platform-release to aosp-master - DO NOT MERGE
Change-Id: Iebd3beb4a77cb91342c2b2c4a592c9036970a3d5
diff --git a/l2tp.c b/l2tp.c
index 7dd550a..1d6171e 100644
--- a/l2tp.c
+++ b/l2tp.c
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-/* A simple implementation of L2TP Access Concentrator (RFC 2661) which only
- * creates a single session. The following code only handles control packets.
- * Data packets are handled by PPPoLAC driver which can be found in Android
- * kernel tree. */
+/*
+ * Implementation of L2TP Access Concentrator (RFC 2661). The following code
+ * only handles control packets. Data packets are handled by kernel driver:
+ * - PX_PROTO_OL2TP (upstream impl.), if it's enabled in kernel
+ * - or PX_PROTO_OLAC (Android impl.), if upstream implementation is not
+ * available / not enabled. It will be removed in new Android kernels.
+ */
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -31,6 +35,7 @@
#include <arpa/inet.h>
#include <linux/netdevice.h>
#include <linux/if_pppox.h>
+#include <linux/types.h>
#include <openssl/md5.h>
#include "mtpd.h"
@@ -89,11 +94,11 @@
#define ATTRIBUTE_HEADER_SIZE 6
#define MAX_ATTRIBUTE_SIZE 1024
-static uint16_t local_tunnel;
-static uint16_t local_session;
+static __be16 local_tunnel;
+static __be16 local_session;
static uint16_t local_sequence;
-static uint16_t remote_tunnel;
-static uint16_t remote_session;
+static __be16 remote_tunnel;
+static __be16 remote_session;
static uint16_t remote_sequence;
static uint16_t state;
@@ -321,7 +326,8 @@
local_tunnel = random();
}
- log_print(DEBUG, "Sending SCCRQ (local_tunnel = %d)", local_tunnel);
+ log_print(DEBUG, "Sending SCCRQ (local_tunnel = %u)",
+ (unsigned)ntohs(local_tunnel));
state = SCCRQ;
set_message(0, SCCRQ);
add_attribute_u16(PROTOCOL_VERSION, htons(0x0100));
@@ -347,10 +353,40 @@
return TIMEOUT_INTERVAL;
}
-static int create_pppox()
+/**
+ * Check if upstream kernel implementation is enabled.
+ *
+ * @return true if upstream L2TP is enabled in kernel and false otherwise
+ */
+static bool check_ol2tp(void)
{
- int pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OLAC);
+ int fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+
+ if (fd < 0) {
+ return false;
+ } else {
+ close(fd);
+ return true;
+ }
+}
+
+/**
+ * Create OLAC session.
+ *
+ * @deprecated It will be removed soon in favor of upstream OL2TP.
+ *
+ * @return PPPoX socket file descriptor
+ */
+static int create_pppox_olac(void)
+{
+ int pppox;
+
+ log_print(WARNING, "Using deprecated OLAC protocol. "
+ "Its support will be removed soon. "
+ "Please enable OL2TP support in your kernel");
+
log_print(INFO, "Creating PPPoX socket");
+ pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OLAC);
if (pppox == -1) {
log_print(FATAL, "Socket() %s", strerror(errno));
@@ -371,6 +407,69 @@
return pppox;
}
+/**
+ * Create OL2TP tunnel and session.
+ *
+ * @param[out] tfd Will contain tunnel socket file descriptor
+ * @param[out] sfd Will contain session socket file descriptor
+ */
+static void create_pppox_ol2tp(int *tfd, int *sfd)
+{
+ int tunnel_fd;
+ int session_fd;
+ struct sockaddr_pppol2tp tunnel_sa;
+ struct sockaddr_pppol2tp session_sa;
+
+ log_print(INFO, "Creating PPPoX tunnel socket...");
+ tunnel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+ if (tunnel_fd < 0) {
+ log_print(FATAL, "Tunnel socket(): %s", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ memset(&tunnel_sa, 0, sizeof(tunnel_sa));
+ tunnel_sa.sa_family = AF_PPPOX;
+ tunnel_sa.sa_protocol = PX_PROTO_OL2TP;
+ tunnel_sa.pppol2tp.fd = the_socket; /* UDP socket */
+ tunnel_sa.pppol2tp.s_tunnel = ntohs(local_tunnel);
+ tunnel_sa.pppol2tp.s_session = 0; /* special case: mgmt socket */
+ tunnel_sa.pppol2tp.d_tunnel = ntohs(remote_tunnel);
+ tunnel_sa.pppol2tp.d_session = 0; /* special case: mgmt socket */
+
+ log_print(INFO, "Connecting to tunnel socket...");
+ if (connect(tunnel_fd, (struct sockaddr *)&tunnel_sa,
+ sizeof(tunnel_sa))) {
+ log_print(FATAL, "Tunnel connect(): %s", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ log_print(INFO, "Creating PPPoX session socket...");
+ session_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+ if (session_fd < 0) {
+ log_print(FATAL, "Session socket(): %s", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ memset(&session_sa, 0, sizeof(session_sa));
+ session_sa.sa_family = AF_PPPOX;
+ session_sa.sa_protocol = PX_PROTO_OL2TP;
+ session_sa.pppol2tp.fd = the_socket;
+ session_sa.pppol2tp.s_tunnel = ntohs(local_tunnel);
+ session_sa.pppol2tp.s_session = ntohs(local_session);
+ session_sa.pppol2tp.d_tunnel = ntohs(remote_tunnel);
+ session_sa.pppol2tp.d_session = ntohs(remote_session);
+
+ log_print(INFO, "Connecting to session socket...");
+ if (connect(session_fd, (struct sockaddr *)&session_sa,
+ sizeof(session_sa))) {
+ log_print(FATAL, "Session connect(): %s", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ *tfd = tunnel_fd;
+ *sfd = session_fd;
+}
+
static uint8_t *compute_response(uint8_t type, void *challenge, int size)
{
static uint8_t response[MD5_DIGEST_LENGTH];
@@ -383,18 +482,18 @@
return response;
}
-static int verify_challenge()
+static bool verify_challenge()
{
if (secret) {
uint8_t response[MD5_DIGEST_LENGTH];
if (get_attribute_raw(CHALLENGE_RESPONSE, response, MD5_DIGEST_LENGTH)
!= MD5_DIGEST_LENGTH) {
- return 0;
+ return false;
}
return !memcmp(compute_response(SCCRP, challenge, CHALLENGE_SIZE),
response, MD5_DIGEST_LENGTH);
}
- return 1;
+ return true;
}
static void answer_challenge()
@@ -412,8 +511,8 @@
static int l2tp_process()
{
uint16_t sequence = local_sequence;
- uint16_t tunnel = 0;
- uint16_t session = 0;
+ __be16 tunnel = 0;
+ __be16 session = 0;
if (!recv_packet(&session)) {
return acknowledged ? 0 : TIMEOUT_INTERVAL;
@@ -427,8 +526,8 @@
if (get_attribute_u16(ASSIGNED_TUNNEL, &tunnel) && tunnel &&
verify_challenge()) {
remote_tunnel = tunnel;
- log_print(DEBUG, "Received SCCRP (remote_tunnel = %d) -> "
- "Sending SCCCN", remote_tunnel);
+ log_print(DEBUG, "Received SCCRP (remote_tunnel = %u) -> "
+ "Sending SCCCN", (unsigned)ntohs(remote_tunnel));
state = SCCCN;
set_message(0, SCCCN);
answer_challenge();
@@ -445,8 +544,8 @@
if (state == ICRQ && session == local_session) {
if (get_attribute_u16(ASSIGNED_SESSION, &session) && session) {
remote_session = session;
- log_print(DEBUG, "Received ICRP (remote_session = %d) -> "
- "Sending ICCN", remote_session);
+ log_print(DEBUG, "Received ICRP (remote_session = %u) -> "
+ "Sending ICCN", (unsigned)ntohs(remote_session));
state = ICCN;
set_message(remote_session, ICCN);
add_attribute_u32(CONNECT_SPEED, htonl(100000000));
@@ -467,8 +566,8 @@
case CDN:
if (session && session == local_session) {
- log_print(DEBUG, "Received CDN (local_session = %d)",
- local_session);
+ log_print(DEBUG, "Received CDN (local_session = %u)",
+ (unsigned)ntohs(local_session));
log_print(INFO, "Remote server hung up");
return -REMOTE_REQUESTED;
}
@@ -484,7 +583,8 @@
local_session = random();
}
log_print(DEBUG, "Received %s -> Sending ICRQ (local_session = "
- "%d)", messages[incoming.message], local_session);
+ "%u)", messages[incoming.message],
+ (unsigned)ntohs(local_session));
log_print(INFO, "Tunnel established");
state = ICRQ;
set_message(0, ICRQ);
@@ -504,7 +604,17 @@
if (state == ICCN) {
log_print(INFO, "Session established");
state = ACK;
- start_pppd(create_pppox());
+
+ if (check_ol2tp()) {
+ int tunnel_fd, session_fd;
+
+ create_pppox_ol2tp(&tunnel_fd, &session_fd);
+ start_pppd_ol2tp(tunnel_fd, session_fd,
+ ntohs(remote_tunnel),
+ ntohs(remote_session));
+ } else {
+ start_pppd(create_pppox_olac());
+ }
}
return 0;
@@ -513,8 +623,9 @@
/* Since we run pppd as a client, it does not makes sense to
* accept ICRQ or OCRQ. Always send CDN with a proper error. */
if (get_attribute_u16(ASSIGNED_SESSION, &session) && session) {
- log_print(DEBUG, "Received %s (remote_session = %d) -> "
- "Sending CDN", messages[incoming.message], session);
+ log_print(DEBUG, "Received %s (remote_session = %u) -> "
+ "Sending CDN", messages[incoming.message],
+ (unsigned)ntohs(session));
set_message(session, CDN);
add_attribute_u32(RESULT_CODE, htonl(0x00020006));
add_attribute_u16(ASSIGNED_SESSION, 0);
diff --git a/mtpd.c b/mtpd.c
index ae0a1e6..ac724ac 100644
--- a/mtpd.c
+++ b/mtpd.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
+#include <limits.h>
#ifdef ANDROID_CHANGES
#include <android/log.h>
@@ -37,6 +38,12 @@
#include "mtpd.h"
#include "NetdClient.h"
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+/* Characters count in string with max value of unsigned type t */
+#define TYPE_STRLEN_U(t) ((((sizeof(t) * CHAR_BIT) * 1233) >> 12) + 1)
+/* Length of string with max file descriptor value */
+#define FD_MAX_LEN TYPE_STRLEN_U(int)
+
int the_socket = -1;
extern struct protocol l2tp;
@@ -322,9 +329,9 @@
if (!pppd_pid) {
char *args[pppd_argc + 5];
- char number[12];
+ char number[FD_MAX_LEN + 1];
- sprintf(number, "%d", pppox);
+ snprintf(number, FD_MAX_LEN + 1, "%d", pppox);
args[0] = "pppd";
args[1] = "nodetach";
args[2] = "pppox";
@@ -332,29 +339,135 @@
memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
args[4 + pppd_argc] = NULL;
-#ifdef ANDROID_CHANGES
- {
- char envargs[65536];
- char *tail = envargs;
- int i;
- /* Hex encode the arguments using [A-P] instead of [0-9A-F]. */
- for (i = 0; args[i]; ++i) {
- char *p = args[i];
- do {
- *tail++ = 'A' + ((*p >> 4) & 0x0F);
- *tail++ = 'A' + (*p & 0x0F);
- } while (*p++);
- }
- *tail = 0;
- setenv("envargs", envargs, 1);
- args[1] = NULL;
- }
-#endif
execvp("pppd", args);
log_print(FATAL, "Exec() %s", strerror(errno));
- exit(1); /* Pretending a fatal error in pppd. */
+ exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */
}
log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
close(pppox);
}
+
+/**
+ * Start pppd daemon with pppol2tp-android plugin.
+ *
+ * @param tunnel_fd Tunnel socket file descriptor
+ * @param session_fd Session socket file descriptor
+ * @param tunnel_id Tunnel ID; must be in host byte order
+ * @param session_id Session ID; must be in host byte order
+ */
+void start_pppd_ol2tp(int tunnel_fd, int session_fd, int tunnel_id,
+ int session_id)
+{
+ if (pppd_pid) {
+ log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
+ goto ret;
+ }
+
+ log_print(INFO, "Starting pppd (tunnel_fd = %d, session_fd = %d)",
+ tunnel_fd, session_fd);
+
+ pppd_pid = fork();
+ if (pppd_pid < 0) {
+ log_print(FATAL, "Fork() %s", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ if (!pppd_pid) {
+ char tunnel_fd_str[FD_MAX_LEN + 1];
+ char session_fd_str[FD_MAX_LEN + 1];
+ char tunnel_id_str[FD_MAX_LEN + 1];
+ char session_id_str[FD_MAX_LEN + 1];
+
+ snprintf(tunnel_fd_str, FD_MAX_LEN + 1, "%d", tunnel_fd);
+ snprintf(session_fd_str, FD_MAX_LEN + 1, "%d", session_fd);
+ snprintf(tunnel_id_str, FD_MAX_LEN + 1, "%d", tunnel_id);
+ snprintf(session_id_str, FD_MAX_LEN + 1, "%d", session_id);
+
+ const char *l2tp_args[] = {
+ "pppd",
+ "nodetach",
+ "plugin",
+ "pppol2tp-android.so",
+ "session_fd",
+ session_fd_str,
+ "tunnel_fd",
+ tunnel_fd_str,
+ "session_id",
+ session_id_str,
+ "tunnel_id",
+ tunnel_id_str,
+ };
+ const size_t args_len = ARRAY_SIZE(l2tp_args) + pppd_argc + 1;
+ char *args[args_len];
+
+ /* Populate args[] from l2tp_args[] and pppd_argv[] */
+ memcpy(args, l2tp_args, sizeof(l2tp_args));
+ memcpy(args + ARRAY_SIZE(l2tp_args), pppd_argv,
+ sizeof(char *) * pppd_argc);
+ args[args_len - 1] = NULL;
+
+ execvp("pppd", args);
+ log_print(FATAL, "Exec() %s", strerror(errno));
+ exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */
+ }
+
+ log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
+
+ret:
+ close(session_fd);
+ close(tunnel_fd);
+}
+
+/**
+ * Start pppd daemon with pppopptp-android plugin.
+ *
+ * @param pptp_fd PPTP socket file descriptor
+ */
+void start_pppd_pptp(int pptp_fd)
+{
+ if (pppd_pid) {
+ log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
+ goto ret;
+ }
+
+ log_print(INFO, "Starting pppd (pptp_fd = %d)", pptp_fd);
+
+ pppd_pid = fork();
+ if (pppd_pid < 0) {
+ log_print(FATAL, "Fork() %s", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ if (!pppd_pid) {
+ char pptp_fd_str[FD_MAX_LEN + 1];
+
+ snprintf(pptp_fd_str, FD_MAX_LEN + 1, "%d", pptp_fd);
+
+ const char *pptp_args[] = {
+ "pppd",
+ "nodetach",
+ "plugin",
+ "pppopptp-android.so",
+ "pptp_socket",
+ pptp_fd_str,
+ };
+ const size_t args_len = ARRAY_SIZE(pptp_args) + pppd_argc + 1;
+ char *args[args_len];
+
+ /* Populate args[] from pptp_args[] and pppd_argv[] */
+ memcpy(args, pptp_args, sizeof(pptp_args));
+ memcpy(args + ARRAY_SIZE(pptp_args), pppd_argv,
+ sizeof(char *) * pppd_argc);
+ args[args_len - 1] = NULL;
+
+ execvp("pppd", args);
+ log_print(FATAL, "Exec() %s", strerror(errno));
+ exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */
+ }
+
+ log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
+
+ret:
+ close(pptp_fd);
+}
diff --git a/mtpd.h b/mtpd.h
index 8e7799b..290a583 100644
--- a/mtpd.h
+++ b/mtpd.h
@@ -70,6 +70,9 @@
void log_print(int level, char *format, ...);
void create_socket(int family, int type, char *server, char *port);
void start_pppd(int pppox);
+void start_pppd_ol2tp(int tunnel_fd, int session_fd, int tunnel_id,
+ int session_id);
+void start_pppd_pptp(int pptp_fd);
/* Each protocol must implement everything defined in this structure. Note that
* timeout intervals are in milliseconds, where zero means forever. To indicate
diff --git a/pptp.c b/pptp.c
index c748d1a..80eb24a 100644
--- a/pptp.c
+++ b/pptp.c
@@ -19,15 +19,19 @@
* Data packets are handled by PPPoPNS driver which can be found in Android
* kernel tree. */
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
#include <arpa/inet.h>
#include <linux/netdevice.h>
#include <linux/if_pppox.h>
+#include <linux/types.h>
#include "mtpd.h"
@@ -72,9 +76,10 @@
#define HEADER_SIZE 8
#define MIN_MESSAGE_SIZE 10
-static uint16_t local;
-static uint16_t remote;
+static __be16 local;
+static __be16 remote;
static uint16_t state;
+static const char *remote_name; /* server host name or IP address */
#define MAX_PACKET_LENGTH 220
@@ -207,14 +212,16 @@
if (incoming.header.type == CONTROL_MESSAGE) {
return 1;
}
- log_print(DEBUG, "Ignored non-control message (type = %d)",
- ntohs(incoming.header.type));
+ log_print(DEBUG, "Ignored non-control message (type = %u)",
+ (unsigned)ntohs(incoming.header.type));
}
return 0;
}
static int pptp_connect(char **arguments)
{
+ remote_name = arguments[0];
+
create_socket(AF_UNSPEC, SOCK_STREAM, arguments[0], arguments[1]);
log_print(DEBUG, "Sending SCCRQ");
@@ -229,10 +236,40 @@
return 0;
}
-static int create_pppox()
+/**
+ * Check if upstream kernel implementation is enabled.
+ *
+ * @return true if upstream PPTP is enabled in kernel and false otherwise
+ */
+static bool check_pptp(void)
{
- int pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OPNS);
+ int fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_PPTP);
+
+ if (fd < 0) {
+ return false;
+ } else {
+ close(fd);
+ return true;
+ }
+}
+
+/**
+ * Create OPNS session.
+ *
+ * @deprecated It will be removed soon in favor of upstream PPTP.
+ *
+ * @return PPPoX socket file descriptor
+ */
+static int create_pppox_opns(void)
+{
+ int pppox;
+
+ log_print(WARNING, "Using deprecated OPNS protocol. "
+ "Its support will be removed soon. "
+ "Please enable PPTP support in your kernel");
+
log_print(INFO, "Creating PPPoX socket");
+ pppox = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OPNS);
if (pppox == -1) {
log_print(FATAL, "Socket() %s", strerror(errno));
@@ -253,6 +290,135 @@
return pppox;
}
+/**
+ * Get IP address by host name.
+ *
+ * @param name Host name to get IP address for
+ *
+ * @return IP address for given host name
+ */
+static struct in_addr get_addr_by_name(const char *name)
+{
+ struct addrinfo hints;
+ struct addrinfo *res, *rp;
+ struct in_addr addr;
+ int err;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET; /* allow only IPv4 */
+ hints.ai_socktype = SOCK_DGRAM; /* UDP */
+ hints.ai_protocol = 0; /* any protocol */
+
+ err = getaddrinfo(name, NULL, &hints, &res);
+ if (err) {
+ log_print(FATAL, "%s: getaddrinfo: %s", __func__, gai_strerror(err));
+ exit(SYSTEM_ERROR);
+ }
+
+ for (rp = res; rp != NULL; rp = rp->ai_next) {
+ /* For now we only support IPv4 */
+ if (rp->ai_family == AF_INET) {
+ addr = ((struct sockaddr_in *)rp->ai_addr)->sin_addr;
+ break;
+ }
+ }
+
+ if (rp == NULL) {
+ log_print(FATAL, "%s: No IPv4 addresses found", __func__);
+ freeaddrinfo(res);
+ exit(SYSTEM_ERROR);
+ }
+
+ freeaddrinfo(res);
+
+ return addr;
+}
+
+/**
+ * Get local IP address.
+ *
+ * Make a socket connection with remote server and then call getsockname() on
+ * the connected socket. This will return the local IP address.
+ *
+ * @param remote_addr Server IP address
+ *
+ * @return Local IP address
+ */
+static struct in_addr get_local_addr(struct in_addr remote_addr)
+{
+ int sock;
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+
+ addr_len = sizeof(struct sockaddr_in);
+ addr.sin_addr = remote_addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(0);
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ log_print(FATAL, "%s: Socket() %s", __func__, strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(addr))) {
+ close(sock);
+ log_print(FATAL, "%s: Connect() %s", __func__, strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ getsockname(sock, (struct sockaddr*)&addr, &addr_len);
+ close(sock);
+
+ return addr.sin_addr;
+}
+
+/**
+ * Create PPTP session.
+ *
+ * @return PPTP socket file descriptor
+ */
+static int create_pppox_pptp(void)
+{
+ int pptp_fd;
+ struct sockaddr_pppox src, dst;
+ struct in_addr remote_addr; /* server IP address */
+ struct in_addr local_addr; /* client IP address */
+
+ remote_addr = get_addr_by_name(remote_name);
+ local_addr = get_local_addr(remote_addr);
+
+ src.sa_family = AF_PPPOX;
+ src.sa_protocol = PX_PROTO_PPTP;
+ src.sa_addr.pptp.call_id = ntohs(local);
+ src.sa_addr.pptp.sin_addr = local_addr;
+
+ dst.sa_family = AF_PPPOX;
+ dst.sa_protocol = PX_PROTO_PPTP;
+ dst.sa_addr.pptp.call_id = ntohs(remote);
+ dst.sa_addr.pptp.sin_addr = remote_addr;
+
+ pptp_fd = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_PPTP);
+ if (pptp_fd < 0) {
+ log_print(FATAL, "Failed to create PPTP socket (%s)", strerror(errno));
+ exit(SYSTEM_ERROR);
+ }
+
+ if (bind(pptp_fd, (struct sockaddr*)&src, sizeof(src))) {
+ log_print(FATAL, "Failed to bind PPTP socket (%s)", strerror(errno));
+ close(pptp_fd);
+ exit(SYSTEM_ERROR);
+ }
+
+ if (connect(pptp_fd, (struct sockaddr*)&dst, sizeof(dst))) {
+ log_print(FATAL, "Failed to connect PPTP socket (%s)", strerror(errno));
+ close(pptp_fd);
+ exit(SYSTEM_ERROR);
+ }
+
+ return pptp_fd;
+}
+
static int pptp_process()
{
int result = recv_packet();
@@ -284,7 +450,7 @@
local = random();
}
log_print(DEBUG, "Received SCCRP -> Sending OCRQ "
- "(local = %d)", local);
+ "(local = %u)", (unsigned)ntohs(local));
log_print(INFO, "Tunnel established");
state = OCRQ;
set_message(OCRQ);
@@ -309,10 +475,16 @@
if (state == OCRQ && incoming.ocrp.peer == local) {
if (ESTABLISHED(incoming.ocrp.result)) {
remote = incoming.ocrp.call;
- log_print(DEBUG, "Received OCRQ (remote = %d)", remote);
+ log_print(DEBUG, "Received OCRQ (remote = %u)",
+ (unsigned)ntohs(remote));
log_print(INFO, "Session established");
state = OCRP;
- start_pppd(create_pppox());
+
+ if (check_pptp())
+ start_pppd_pptp(create_pppox_pptp());
+ else
+ start_pppd(create_pppox_opns());
+
return 0;
}
log_print(DEBUG, "Received OCRP (result = %d)",
@@ -333,7 +505,8 @@
* outgoing calls. However, some implementation only acts as PNS and
* always uses CCRQ to clear a call, so here we still handle it. */
if (state == OCRP && incoming.ccrq.call == remote) {
- log_print(DEBUG, "Received CCRQ (remote = %d)", remote);
+ log_print(DEBUG, "Received CCRQ (remote = %u)",
+ (unsigned)ntohs(remote));
log_print(INFO, "Remote server hung up");
return -REMOTE_REQUESTED;
}
@@ -341,7 +514,8 @@
case CDN:
if (state == OCRP && incoming.cdn.call == remote) {
- log_print(DEBUG, "Received CDN (remote = %d)", remote);
+ log_print(DEBUG, "Received CDN (remote = %u)",
+ (unsigned)ntohs(remote));
log_print(INFO, "Remote server hung up");
return -REMOTE_REQUESTED;
}
@@ -361,8 +535,9 @@
return 0;
case ICRQ:
- log_print(DEBUG, "Received ICRQ (remote = %d) -> Sending ICRP "
- "with error", incoming.icrq.call);
+ log_print(DEBUG, "Received ICRQ (remote = %u, call = %u) -> "
+ "Sending ICRP with error", (unsigned)ntohs(remote),
+ (unsigned)ntohs(incoming.icrq.call));
set_message(ICRP);
outgoing.icrp.peer = incoming.icrq.call;
outgoing.icrp.result = RESULT_ERROR;
@@ -370,8 +545,9 @@
return 0;
case OCRQ:
- log_print(DEBUG, "Received OCRQ (remote = %d) -> Sending OCRP "
- "with error", incoming.ocrq.call);
+ log_print(DEBUG, "Received OCRQ (remote = %u, call = %u) -> "
+ "Sending OCRP with error", (unsigned)ntohs(remote),
+ (unsigned)ntohs(incoming.ocrq.call));
set_message(OCRP);
outgoing.ocrp.peer = incoming.ocrq.call;
outgoing.ocrp.result = RESULT_ERROR;