X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fopenwrt.git;a=blobdiff_plain;f=package%2Fppp%2Fpatches%2F500-add-pptp-plugin.patch;fp=package%2Fppp%2Fpatches%2F500-add-pptp-plugin.patch;h=0000000000000000000000000000000000000000;hp=d984e1b1628fff9fa4c57fca2f6f3da016feef77;hb=405e21d16731b2764ab82aaaadcf36a813b105f7;hpb=d0ec348ded6f715b43b396b06ccb10599b37969d diff --git a/package/ppp/patches/500-add-pptp-plugin.patch b/package/ppp/patches/500-add-pptp-plugin.patch deleted file mode 100644 index d984e1b162..0000000000 --- a/package/ppp/patches/500-add-pptp-plugin.patch +++ /dev/null @@ -1,3065 +0,0 @@ ---- a/configure -+++ b/configure -@@ -195,7 +195,7 @@ if [ -d "$ksrc" ]; then - mkmkf $ksrc/Makedefs$compiletype Makedefs.com - for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/rp-pppoe \ - pppd/plugins/radius pppd/plugins/pppoatm \ -- pppd/plugins/pppol2tp; do -+ pppd/plugins/pppol2tp pppd/plugins/pptp ; do - mkmkf $dir/Makefile.$makext $dir/Makefile - done - if [ -f $ksrc/Makefile.$makext$archvariant ]; then ---- a/pppd/plugins/Makefile.linux -+++ b/pppd/plugins/Makefile.linux -@@ -9,7 +9,7 @@ BINDIR = $(DESTDIR)/sbin - MANDIR = $(DESTDIR)/share/man/man8 - LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION) - --SUBDIRS := rp-pppoe pppoatm pppol2tp -+SUBDIRS := rp-pppoe pppoatm pppol2tp pptp - # Uncomment the next line to include the radius authentication plugin - SUBDIRS += radius - PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so ---- /dev/null -+++ b/pppd/plugins/pptp/Makefile.linux -@@ -0,0 +1,31 @@ -+# -+# This program may be distributed according to the terms of the GNU -+# General Public License, version 2 or (at your option) any later version. -+# -+# $Id: Makefile.linux,v 1.9 2012/05/04 21:48:00 dgolle Exp $ -+#*********************************************************************** -+ -+DESTDIR = $(INSTROOT)@DESTDIR@ -+LIBDIR = $(DESTDIR)/lib/pppd/$(PPPDVERSION) -+ -+PPPDVERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h) -+ -+INSTALL = install -+ -+COPTS=-O2 -g -+CFLAGS = $(COPTS) -I. -I../.. -I../../../include -fPIC -DPPPD_VERSION=\"$(PPPDVERSION)\" -+all: pptp.so -+ -+%.o: %.c -+ $(CC) $(CFLAGS) -c -o $@ $< -+ -+pptp.so: dirutil.o orckit_quirks.o pptp.o pptp_callmgr.o pptp_ctrl.o pptp_quirks.o util.o vector.o -+ $(CC) -o pptp.so -shared dirutil.o orckit_quirks.o pptp.o pptp_callmgr.o pptp_ctrl.o pptp_quirks.o util.o vector.o -+ -+install: all -+ $(INSTALL) -d -m 755 $(LIBDIR) -+ $(INSTALL) -c -m 4550 pptp.so $(LIBDIR) -+ -+clean: -+ rm -f *.o *.so -+ ---- /dev/null -+++ b/pppd/plugins/pptp/dirutil.c -@@ -0,0 +1,68 @@ -+/* dirutil.c ... directory utilities. -+ * C. Scott Ananian -+ * -+ * $Id: dirutil.c,v 1.2 2003/06/17 17:25:47 reink Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "dirutil.h" -+ -+/* Returned malloc'ed string representing basename */ -+char *basenamex(char *pathname) -+{ -+ char *dup = strdup(pathname); -+ char *ptr = strrchr(stripslash(dup), '/'); -+ if (ptr == NULL) return dup; -+ ptr = strdup(ptr+1); -+ free(dup); -+ return ptr; -+} -+ -+/* Return malloc'ed string representing directory name (no trailing slash) */ -+char *dirnamex(char *pathname) -+{ -+ char *dup = strdup(pathname); -+ char *ptr = strrchr(stripslash(dup), '/'); -+ if (ptr == NULL) { free(dup); return strdup("."); } -+ if (ptr == dup && dup[0] == '/') ptr++; -+ *ptr = '\0'; -+ return dup; -+} -+ -+/* In-place modify a string to remove trailing slashes. Returns arg. -+ * stripslash("/") returns "/"; -+ */ -+char *stripslash(char *pathname) { -+ int len = strlen(pathname); -+ while (len > 1 && pathname[len - 1] == '/') -+ pathname[--len] = '\0'; -+ return pathname; -+} -+ -+/* ensure dirname exists, creating it if necessary. */ -+int make_valid_path(char *dir, mode_t mode) -+{ -+ struct stat st; -+ char *tmp = NULL, *path = stripslash(strdup(dir)); -+ int retval; -+ if (stat(path, &st) == 0) { /* file exists */ -+ if (S_ISDIR(st.st_mode)) { retval = 1; goto end; } -+ else { retval = 0; goto end; } /* not a directory. Oops. */ -+ } -+ /* Directory doesn't exist. Let's make it. */ -+ /* Make parent first. */ -+ if (!make_valid_path(tmp = dirnamex(path), mode)) { retval = 0; goto end; } -+ /* Now make this 'un. */ -+ if (mkdir(path, mode) < 0) { retval = 0; goto end; } -+ /* Success. */ -+ retval = 1; -+ -+end: -+ if (tmp != NULL) free(tmp); -+ if (path != NULL) free(path); -+ return retval; -+} ---- /dev/null -+++ b/pppd/plugins/pptp/dirutil.h -@@ -0,0 +1,14 @@ -+/* dirutil.h ... directory utilities. -+ * C. Scott Ananian -+ * -+ * $Id: dirutil.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $ -+ */ -+ -+/* Returned malloc'ed string representing basename */ -+char *basenamex(char *pathname); -+/* Return malloc'ed string representing directory name (no trailing slash) */ -+char *dirnamex(char *pathname); -+/* In-place modify a string to remove trailing slashes. Returns arg. */ -+char *stripslash(char *pathname); -+/* ensure dirname exists, creating it if necessary. */ -+int make_valid_path(char *dirname, mode_t mode); ---- /dev/null -+++ b/pppd/plugins/pptp/orckit_quirks.c -@@ -0,0 +1,86 @@ -+/* orckit_quirks.c ...... fix quirks in orckit adsl modems -+ * mulix -+ * -+ * $Id: orckit_quirks.c,v 1.3 2002/03/01 01:23:36 quozl Exp $ -+ */ -+ -+#include -+#include -+#include -+#include "pptp_msg.h" -+#include "pptp_options.h" -+#include "pptp_ctrl.h" -+#include "util.h" -+ -+ -+ -+/* return 0 on success, non zero otherwise */ -+int -+orckit_atur3_build_hook(struct pptp_out_call_rqst* packet) -+{ -+ unsigned int name_length = 10; -+ -+ struct pptp_out_call_rqst fixed_packet = { -+ PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST), -+ 0, /* hton16(call->callid) */ -+ 0, /* hton16(call->sernum) */ -+ hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX), -+ hton32(PPTP_BEARER_DIGITAL), hton32(PPTP_FRAME_ANY), -+ hton16(PPTP_WINDOW), 0, hton16(name_length), 0, -+ {'R','E','L','A','Y','_','P','P','P','1',0}, {0} -+ }; -+ -+ if (!packet) -+ return -1; -+ -+ memcpy(packet, &fixed_packet, sizeof(*packet)); -+ -+ return 0; -+} -+ -+/* return 0 on success, non zero otherwise */ -+int -+orckit_atur3_set_link_hook(struct pptp_set_link_info* packet, -+ int peer_call_id) -+{ -+ struct pptp_set_link_info fixed_packet = { -+ PPTP_HEADER_CTRL(PPTP_SET_LINK_INFO), -+ hton16(peer_call_id), -+ 0, -+ 0xffffffff, -+ 0xffffffff}; -+ -+ if (!packet) -+ return -1; -+ -+ memcpy(packet, &fixed_packet, sizeof(*packet)); -+ return 0; -+} -+ -+/* return 0 on success, non 0 otherwise */ -+int -+orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet) -+{ -+ struct pptp_start_ctrl_conn fixed_packet = { -+ {0}, /* we'll set the header later */ -+ hton16(PPTP_VERSION), 0, 0, -+ hton32(PPTP_FRAME_ASYNC), hton32(PPTP_BEARER_ANALOG), -+ hton16(0) /* max channels */, -+ hton16(0x6021), -+ {'R','E','L','A','Y','_','P','P','P','1',0}, /* hostname */ -+ {'M','S',' ','W','i','n',' ','N','T',0} /* vendor */ -+ }; -+ -+ if (!packet) -+ return -1; -+ -+ /* grab the header from the original packet, since we dont -+ know if this is a request or a reply */ -+ memcpy(&fixed_packet.header, &packet->header, sizeof(struct pptp_header)); -+ -+ /* and now overwrite the full packet, effectively preserving the header */ -+ memcpy(packet, &fixed_packet, sizeof(*packet)); -+ return 0; -+} -+ -+ ---- /dev/null -+++ b/pppd/plugins/pptp/orckit_quirks.h -@@ -0,0 +1,27 @@ -+/* orckit_quirks.h ...... fix quirks in orckit adsl modems -+ * mulix -+ * -+ * $Id: orckit_quirks.h,v 1.2 2001/11/23 03:42:51 quozl Exp $ -+ */ -+ -+#ifndef INC_ORCKIT_QUIRKS_H_ -+#define INC_ORCKIT_QUIRKS_H_ -+ -+#include "pptp_options.h" -+#include "pptp_ctrl.h" -+#include "pptp_msg.h" -+ -+/* return 0 on success, non zero otherwise */ -+int -+orckit_atur3_build_hook(struct pptp_out_call_rqst* packt); -+ -+/* return 0 on success, non zero otherwise */ -+int -+orckit_atur3_set_link_hook(struct pptp_set_link_info* packet, -+ int peer_call_id); -+ -+/* return 0 on success, non zero otherwise */ -+int -+orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet); -+ -+#endif /* INC_ORCKIT_QUIRKS_H_ */ ---- /dev/null -+++ b/pppd/plugins/pptp/pppd-pptp.8 -@@ -0,0 +1,68 @@ -+.\" manual page [] for PPTP plugin for pppd 2.4 -+.\" $Id: pppd-pptp.8,v 1.0 2007/10/17 13:27:17 kad Exp $ -+.\" SH section heading -+.\" SS subsection heading -+.\" LP paragraph -+.\" IP indented paragraph -+.\" TP hanging label -+.TH PPPD-PPTP 8 -+.SH NAME -+pptp.so \- PPTP VPN plugin for -+.BR pppd (8) -+.SH SYNOPSIS -+.B pppd -+[ -+.I options -+] -+plugin pptp.so -+.SH DESCRIPTION -+.LP -+The PPTP plugin for pppd performs interaction with pptp kernel module -+and has built-in call manager (client part of PPTP). -+It pasees necessary paremeters from \fIoptions\fR into kernel module -+to configure ppp-pptp channel. If it runs in client mode, then additionally -+call manager starts up. PPTPD daemon automaticaly invokes this plugin -+in server mode and passes necessary options, so additional configuration -+is not needed. -+ -+.SH OPTIONS for client mode -+The PPTP plugin introduces one additional pppd option: -+.TP -+.BI "pptp_server " server " (required)" -+Specifies ip address or hostname of pptp server. -+.TP -+.BI "pptp_window " packets " (optional)" -+The amount of sliding window size. -+Set to 0 to turn off sliding window. -+ to 3-10 for low speed connections. -+ to >10 for hi speed connections. -+Default is 50 -+.TP -+.BI "pptp_phone " phone " (optional)" -+The phone string that sended to pptp server. -+.SH USAGE -+Sample configuration file: -+.nf -+plugin "pptp.so" -+pptp_server 192.168.0.1 -+pptp_window 100 -+name myname -+remotename pptp -+noauth -+refuse-eap -+refuse-chap -+refuse-mschap -+nobsdcomp -+nodeflate -+novj -+novjccomp -+require-mppe-128 -+lcp-echo-interval 20 -+lcp-echo-failure 3 -+.fi -+ -+.SH SEE ALSO -+.BR pppd (8) " " pptpd (8) " " pptpd.conf (5) -+ -+.SH AUTHOR -+xeb xeb@mail.ru ---- /dev/null -+++ b/pppd/plugins/pptp/pptp.c -@@ -0,0 +1,323 @@ -+/*************************************************************************** -+ * Copyright (C) 2006 by Kozlov D. * -+ * some cleanup done (C) 2012 by Daniel Golle * -+ * * -+ * This program is free software; you can redistribute it and/or modify * -+ * it under the terms of the GNU General Public License as published by * -+ * the Free Software Foundation; either version 2 of the License, or * -+ * (at your option) any later version. * -+ * * -+ * This program is distributed in the hope that it will be useful, * -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of * -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -+ * GNU General Public License for more details. * -+ * * -+ * You should have received a copy of the GNU General Public License * -+ * along with this program; if not, write to the * -+ * Free Software Foundation, Inc., * -+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -+ ***************************************************************************/ -+ -+#define PPTP_VERSION "1.00" -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pppd.h" -+#include "fsm.h" -+#include "lcp.h" -+#include "ipcp.h" -+#include "ccp.h" -+#include "pathnames.h" -+ -+#include "pptp_callmgr.h" -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+ -+extern char** environ; -+ -+char pppd_version[] = PPPD_VERSION; -+extern int new_style_driver; -+ -+ -+char *pptp_server = NULL; -+char *pptp_client = NULL; -+char *pptp_phone = NULL; -+int pptp_window=50; -+int pptp_sock=-1; -+struct in_addr localbind = { INADDR_NONE }; -+ -+static int callmgr_sock; -+static int pptp_fd; -+int call_ID; -+ -+static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window); -+static void launch_callmgr(int call_is,struct in_addr inetaddr, char *phonenr,int window); -+static int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *peer_call_id); -+ -+static option_t Options[] = -+{ -+ { "pptp_server", o_string, &pptp_server, -+ "PPTP Server" }, -+ { "pptp_client", o_string, &pptp_client, -+ "PPTP Client" }, -+ { "pptp_sock",o_int, &pptp_sock, -+ "PPTP socket" }, -+ { "pptp_phone", o_string, &pptp_phone, -+ "PPTP Phone number" }, -+ { "pptp_window",o_int, &pptp_window, -+ "PPTP window" }, -+ { NULL } -+}; -+ -+static int pptp_connect(void); -+static void pptp_disconnect(void); -+ -+struct channel pptp_channel = { -+ options: Options, -+ check_options: NULL, -+ connect: &pptp_connect, -+ disconnect: &pptp_disconnect, -+ establish_ppp: &generic_establish_ppp, -+ disestablish_ppp: &generic_disestablish_ppp, -+ close: NULL, -+ cleanup: NULL -+}; -+ -+static int pptp_start_server(void) -+{ -+ pptp_fd=pptp_sock; -+ sprintf(ppp_devnam,"pptp (%s)",pptp_client); -+ -+ return pptp_fd; -+} -+static int pptp_start_client(void) -+{ -+ socklen_t len; -+ struct sockaddr_pppox src_addr,dst_addr; -+ struct hostent *hostinfo; -+ -+ hostinfo=gethostbyname(pptp_server); -+ if (!hostinfo) -+ { -+ error("PPTP: Unknown host %s\n", pptp_server); -+ return -1; -+ } -+ dst_addr.sa_addr.pptp.sin_addr=*(struct in_addr*)hostinfo->h_addr; -+ { -+ int sock; -+ struct sockaddr_in addr; -+ len=sizeof(addr); -+ addr.sin_addr=dst_addr.sa_addr.pptp.sin_addr; -+ addr.sin_family=AF_INET; -+ addr.sin_port=htons(1700); -+ sock=socket(AF_INET,SOCK_DGRAM,0); -+ if (connect(sock,(struct sockaddr*)&addr,sizeof(addr))) -+ { -+ close(sock); -+ error("PPTP: connect failed (%s)\n",strerror(errno)); -+ return -1; -+ } -+ getsockname(sock,(struct sockaddr*)&addr,&len); -+ src_addr.sa_addr.pptp.sin_addr=addr.sin_addr; -+ close(sock); -+ } -+ -+ src_addr.sa_family=AF_PPPOX; -+ src_addr.sa_protocol=PX_PROTO_PPTP; -+ src_addr.sa_addr.pptp.call_id=0; -+ -+ dst_addr.sa_family=AF_PPPOX; -+ dst_addr.sa_protocol=PX_PROTO_PPTP; -+ dst_addr.sa_addr.pptp.call_id=0; -+ -+ pptp_fd=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP); -+ if (pptp_fd<0) -+ { -+ error("PPTP: failed to create PPTP socket (%s)\n",strerror(errno)); -+ return -1; -+ } -+ if (bind(pptp_fd,(struct sockaddr*)&src_addr,sizeof(src_addr))) -+ { -+ close(pptp_fd); -+ error("PPTP: failed to bind PPTP socket (%s)\n",strerror(errno)); -+ return -1; -+ } -+ len=sizeof(src_addr); -+ getsockname(pptp_fd,(struct sockaddr*)&src_addr,&len); -+ call_ID=src_addr.sa_addr.pptp.call_id; -+ -+ do { -+ /* -+ * Open connection to call manager (Launch call manager if necessary.) -+ */ -+ callmgr_sock = open_callmgr(src_addr.sa_addr.pptp.call_id,dst_addr.sa_addr.pptp.sin_addr, pptp_phone, pptp_window); -+ if (callmgr_sock<0) -+ { -+ close(pptp_fd); -+ return -1; -+ } -+ /* Exchange PIDs, get call ID */ -+ } while (get_call_id(callmgr_sock, getpid(), getpid(), &dst_addr.sa_addr.pptp.call_id) < 0); -+ -+ if (connect(pptp_fd,(struct sockaddr*)&dst_addr,sizeof(dst_addr))) -+ { -+ close(callmgr_sock); -+ close(pptp_fd); -+ error("PPTP: failed to connect PPTP socket (%s)\n",strerror(errno)); -+ return -1; -+ } -+ -+ sprintf(ppp_devnam,"pptp (%s)",pptp_server); -+ -+ return pptp_fd; -+} -+static int pptp_connect(void) -+{ -+ if ((!pptp_server && !pptp_client) || (pptp_server && pptp_client)) -+ { -+ fatal("PPTP: unknown mode (you must specify pptp_server or pptp_client option)"); -+ return -1; -+ } -+ -+ if (pptp_server) return pptp_start_client(); -+ return pptp_start_server(); -+} -+ -+static void pptp_disconnect(void) -+{ -+ if (pptp_server) close(callmgr_sock); -+ close(pptp_fd); -+} -+ -+static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window) -+{ -+ /* Try to open unix domain socket to call manager. */ -+ struct sockaddr_un where; -+ const int NUM_TRIES = 3; -+ int i, fd; -+ pid_t pid; -+ int status; -+ /* Open socket */ -+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) -+ { -+ fatal("Could not create unix domain socket: %s", strerror(errno)); -+ } -+ /* Make address */ -+ callmgr_name_unixsock(&where, inetaddr, localbind); -+ for (i = 0; i < NUM_TRIES; i++) -+ { -+ if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) -+ { -+ /* couldn't connect. We'll have to launch this guy. */ -+ -+ unlink (where.sun_path); -+ -+ /* fork and launch call manager process */ -+ switch (pid = fork()) -+ { -+ case -1: /* failure */ -+ fatal("fork() to launch call manager failed."); -+ case 0: /* child */ -+ { -+ /* close the pty and gre in the call manager */ -+ close(fd); -+ close(pptp_fd); -+ launch_callmgr(call_id,inetaddr,phonenr,window); -+ } -+ default: /* parent */ -+ waitpid(pid, &status, 0); -+ if (status!= 0) -+ { -+ close(fd); -+ error("Call manager exited with error %d", status); -+ return -1; -+ } -+ break; -+ } -+ sleep(1); -+ } -+ else return fd; -+ } -+ close(fd); -+ error("Could not launch call manager after %d tries.", i); -+ return -1; /* make gcc happy */ -+} -+ -+/*** call the call manager main ***********************************************/ -+static void launch_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window) -+{ -+ dbglog("pptp: call manager for %s\n", inet_ntoa(inetaddr)); -+ dbglog("window size:\t%d\n",window); -+ if (phonenr) dbglog("phone number:\t'%s'\n",phonenr); -+ dbglog("call id:\t%d\n",call_id); -+ exit(callmgr_main(inetaddr, phonenr, window, call_id)); -+} -+ -+/*** exchange data with the call manager *************************************/ -+/* XXX need better error checking XXX */ -+static int get_call_id(int sock, pid_t gre, pid_t pppd, -+ u_int16_t *peer_call_id) -+{ -+ u_int16_t m_call_id, m_peer_call_id; -+ /* write pid's to socket */ -+ /* don't bother with network byte order, because pid's are meaningless -+ * outside the local host. -+ */ -+ int rc; -+ rc = write(sock, &gre, sizeof(gre)); -+ if (rc != sizeof(gre)) -+ return -1; -+ rc = write(sock, &pppd, sizeof(pppd)); -+ if (rc != sizeof(pppd)) -+ return -1; -+ rc = read(sock, &m_call_id, sizeof(m_call_id)); -+ if (rc != sizeof(m_call_id)) -+ return -1; -+ rc = read(sock, &m_peer_call_id, sizeof(m_peer_call_id)); -+ if (rc != sizeof(m_peer_call_id)) -+ return -1; -+ /* -+ * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX -+ * (Rhialto: I am assuming for now that timeouts are not relevant -+ * here, because the read and write calls would return -1 (fail) when -+ * the peer goes away during the process. We know it is (or was) -+ * running because the connect() call succeeded.) -+ * (James: on the other hand, if the route to the peer goes away, we -+ * wouldn't get told by read() or write() for quite some time.) -+ */ -+ *peer_call_id = m_peer_call_id; -+ return 0; -+} -+ -+void plugin_init(void) -+{ -+ add_options(Options); -+ -+ info("PPTP plugin version %s", PPTP_VERSION); -+ -+ the_channel = &pptp_channel; -+ modem = 0; -+} ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_callmgr.c -@@ -0,0 +1,381 @@ -+/* pptp_callmgr.c ... Call manager for PPTP connections. -+ * Handles TCP port 1723 protocol. -+ * C. Scott Ananian -+ * -+ * $Id: pptp_callmgr.c,v 1.20 2005/03/31 07:42:39 quozl Exp $ -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pptp_callmgr.h" -+#include "pptp_ctrl.h" -+#include "pptp_msg.h" -+#include "dirutil.h" -+#include "vector.h" -+#include "util.h" -+#include "pppd.h" -+ -+extern struct in_addr localbind; /* from pptp.c */ -+extern int call_ID; -+ -+int open_inetsock(struct in_addr inetaddr); -+int open_unixsock(struct in_addr inetaddr); -+void close_inetsock(int fd, struct in_addr inetaddr); -+void close_unixsock(int fd, struct in_addr inetaddr); -+ -+sigjmp_buf callmgr_env; -+ -+void callmgr_sighandler(int sig) { -+ /* TODO: according to signal(2), siglongjmp() is unsafe used here */ -+ siglongjmp (callmgr_env, 1); -+} -+ -+void callmgr_do_nothing(int sig) { -+ /* do nothing signal handler */ -+} -+ -+struct local_callinfo { -+ int unix_sock; -+ pid_t pid[2]; -+}; -+ -+struct local_conninfo { -+ VECTOR * call_list; -+ fd_set * call_set; -+}; -+ -+/* Call callback */ -+void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state) -+{ -+ struct local_callinfo *lci; -+ struct local_conninfo *conninfo; -+ u_int16_t call_id[2]; -+ switch(state) { -+ case CALL_OPEN_DONE: -+ /* okey dokey. This means that the call_id and peer_call_id are -+ * now valid, so lets send them on to our friends who requested -+ * this call. */ -+ lci = pptp_call_closure_get(conn, call); assert(lci != NULL); -+ pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]); -+ write(lci->unix_sock, &call_id, sizeof(call_id)); -+ /* Our duty to the fatherland is now complete. */ -+ break; -+ case CALL_OPEN_FAIL: -+ case CALL_CLOSE_RQST: -+ case CALL_CLOSE_DONE: -+ /* don't need to do anything here, except make sure tables -+ * are sync'ed */ -+ dbglog("Closing connection (call state)"); -+ conninfo = pptp_conn_closure_get(conn); -+ lci = pptp_call_closure_get(conn, call); -+ assert(lci != NULL && conninfo != NULL); -+ if (vector_contains(conninfo->call_list, lci->unix_sock)) { -+ vector_remove(conninfo->call_list, lci->unix_sock); -+ close(lci->unix_sock); -+ FD_CLR(lci->unix_sock, conninfo->call_set); -+ } -+ break; -+ default: -+ dbglog("Unhandled call callback state [%d].", (int) state); -+ break; -+ } -+} -+ -+/****************************************************************************** -+ * NOTE ABOUT 'VOLATILE': -+ * several variables here get a volatile qualifier to silence warnings -+ * from older (before 3.0) gccs. if the longjmp stuff is removed, -+ * the volatile qualifiers should be removed as well. -+ *****************************************************************************/ -+ -+/*** Call Manager *************************************************************/ -+int callmgr_main(struct in_addr inetaddr, char phonenr[], int window, int pcallid) -+{ -+ int inet_sock, unix_sock; -+ fd_set call_set; -+ PPTP_CONN * conn; -+ VECTOR * call_list; -+ int max_fd = 0; -+ volatile int first = 1; -+ int retval; -+ int i; -+ if (pcallid>0) call_ID=pcallid; -+ -+ /* Step 1: Open sockets. */ -+ if ((inet_sock = open_inetsock(inetaddr)) < 0) -+ fatal("Could not open control connection to %s", inet_ntoa(inetaddr)); -+ dbglog("control connection"); -+ if ((unix_sock = open_unixsock(inetaddr)) < 0) -+ fatal("Could not open unix socket for %s", inet_ntoa(inetaddr)); -+ /* Step 1b: FORK and return status to calling process. */ -+ dbglog("unix_sock"); -+ -+ switch (fork()) { -+ case 0: /* child. stick around. */ -+ break; -+ case -1: /* failure. Fatal. */ -+ fatal("Could not fork."); -+ default: /* Parent. Return status to caller. */ -+ exit(0); -+ } -+ /* re-open stderr as /dev/null to release it */ -+ file2fd("/dev/null", "wb", STDERR_FILENO); -+ /* Step 1c: Clean up unix socket on TERM */ -+ if (sigsetjmp(callmgr_env, 1) != 0) -+ goto cleanup; -+ signal(SIGINT, callmgr_sighandler); -+ signal(SIGTERM, callmgr_sighandler); -+ signal(SIGPIPE, callmgr_do_nothing); -+ signal(SIGUSR1, callmgr_do_nothing); /* signal state change -+ wake up accept */ -+ /* Step 2: Open control connection and register callback */ -+ if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) { -+ close(unix_sock); close(inet_sock); fatal("Could not open connection."); -+ } -+ FD_ZERO(&call_set); -+ call_list = vector_create(); -+ { -+ struct local_conninfo *conninfo = malloc(sizeof(*conninfo)); -+ if (conninfo == NULL) { -+ close(unix_sock); close(inet_sock); fatal("No memory."); -+ } -+ conninfo->call_list = call_list; -+ conninfo->call_set = &call_set; -+ pptp_conn_closure_put(conn, conninfo); -+ } -+ if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown; -+ /* Step 3: Get FD_SETs */ -+ max_fd = unix_sock; -+ do { -+ int rc; -+ fd_set read_set = call_set, write_set; -+ FD_ZERO (&write_set); -+ if (pptp_conn_established(conn)) { -+ FD_SET (unix_sock, &read_set); -+ if (unix_sock > max_fd) max_fd = unix_sock; -+ } -+ pptp_fd_set(conn, &read_set, &write_set, &max_fd); -+ for (; max_fd > 0 ; max_fd--) { -+ if (FD_ISSET (max_fd, &read_set) || -+ FD_ISSET (max_fd, &write_set)) -+ break; -+ } -+ /* Step 4: Wait on INET or UNIX event */ -+ if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) { -+ if (errno == EBADF) break; -+ /* a signal or somesuch. */ -+ continue; -+ } -+ /* Step 5a: Handle INET events */ -+ rc = pptp_dispatch(conn, &read_set, &write_set); -+ if (rc < 0) -+ break; -+ /* Step 5b: Handle new connection to UNIX socket */ -+ if (FD_ISSET(unix_sock, &read_set)) { -+ /* New call! */ -+ struct sockaddr_un from; -+ int len = sizeof(from); -+ PPTP_CALL * call; -+ struct local_callinfo *lci; -+ int s; -+ /* Accept the socket */ -+ FD_CLR (unix_sock, &read_set); -+ if ((s = accept(unix_sock, (struct sockaddr *) &from, &len)) < 0) { -+ warn("Socket not accepted: %s", strerror(errno)); -+ goto skip_accept; -+ } -+ /* Allocate memory for local call information structure. */ -+ if ((lci = malloc(sizeof(*lci))) == NULL) { -+ warn("Out of memory."); close(s); goto skip_accept; -+ } -+ lci->unix_sock = s; -+ /* Give the initiator time to write the PIDs while we open -+ * the call */ -+ call = pptp_call_open(conn, call_ID,call_callback, phonenr,window); -+ /* Read and store the associated pids */ -+ read(s, &lci->pid[0], sizeof(lci->pid[0])); -+ read(s, &lci->pid[1], sizeof(lci->pid[1])); -+ /* associate the local information with the call */ -+ pptp_call_closure_put(conn, call, (void *) lci); -+ /* The rest is done on callback. */ -+ /* Keep alive; wait for close */ -+ retval = vector_insert(call_list, s, call); assert(retval); -+ if (s > max_fd) max_fd = s; -+ FD_SET(s, &call_set); -+ first = 0; -+ } -+skip_accept: /* Step 5c: Handle socket close */ -+ for (i = 0; i < max_fd + 1; i++) -+ if (FD_ISSET(i, &read_set)) { -+ /* close it */ -+ PPTP_CALL * call; -+ retval = vector_search(call_list, i, &call); -+ if (retval) { -+ struct local_callinfo *lci = -+ pptp_call_closure_get(conn, call); -+ dbglog("Closing connection (unhandled)"); -+ free(lci); -+ /* soft shutdown. Callback will do hard shutdown later */ -+ pptp_call_close(conn, call); -+ vector_remove(call_list, i); -+ } -+ FD_CLR(i, &call_set); -+ close(i); -+ } -+ } while (vector_size(call_list) > 0 || first); -+shutdown: -+ { -+ int rc; -+ fd_set read_set, write_set; -+ struct timeval tv; -+ signal(SIGINT, callmgr_do_nothing); -+ signal(SIGTERM, callmgr_do_nothing); -+ /* warn("Shutdown"); */ -+ /* kill all open calls */ -+ for (i = 0; i < vector_size(call_list); i++) { -+ PPTP_CALL *call = vector_get_Nth(call_list, i); -+ dbglog("Closing connection (shutdown)"); -+ pptp_call_close(conn, call); -+ } -+ /* attempt to dispatch these messages */ -+ FD_ZERO(&read_set); -+ FD_ZERO(&write_set); -+ pptp_fd_set(conn, &read_set, &write_set, &max_fd); -+ tv.tv_sec = 0; -+ tv.tv_usec = 0; -+ select(max_fd + 1, &read_set, &write_set, NULL, &tv); -+ rc = pptp_dispatch(conn, &read_set, &write_set); -+ if (rc > 0) { -+ /* wait for a respond, a timeout because there might not be one */ -+ FD_ZERO(&read_set); -+ FD_ZERO(&write_set); -+ pptp_fd_set(conn, &read_set, &write_set, &max_fd); -+ tv.tv_sec = 2; -+ tv.tv_usec = 0; -+ select(max_fd + 1, &read_set, &write_set, NULL, &tv); -+ rc = pptp_dispatch(conn, &read_set, &write_set); -+ if (rc > 0) { -+ if (i > 0) sleep(2); -+ /* no more open calls. Close the connection. */ -+ pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN); -+ /* wait for a respond, a timeout because there might not be one */ -+ FD_ZERO(&read_set); -+ FD_ZERO(&write_set); -+ pptp_fd_set(conn, &read_set, &write_set, &max_fd); -+ tv.tv_sec = 2; -+ tv.tv_usec = 0; -+ select(max_fd + 1, &read_set, &write_set, NULL, &tv); -+ pptp_dispatch(conn, &read_set, &write_set); -+ if (rc > 0) sleep(2); -+ } -+ } -+ /* with extreme prejudice */ -+ pptp_conn_destroy(conn); -+ vector_destroy(call_list); -+ } -+cleanup: -+ signal(SIGINT, callmgr_do_nothing); -+ signal(SIGTERM, callmgr_do_nothing); -+ close_inetsock(inet_sock, inetaddr); -+ close_unixsock(unix_sock, inetaddr); -+ return 0; -+} -+ -+/*** open_inetsock ************************************************************/ -+int open_inetsock(struct in_addr inetaddr) -+{ -+ struct sockaddr_in dest, src; -+ int s; -+ dest.sin_family = AF_INET; -+ dest.sin_port = htons(PPTP_PORT); -+ dest.sin_addr = inetaddr; -+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ warn("socket: %s", strerror(errno)); -+ return s; -+ } -+ if (localbind.s_addr != INADDR_NONE) { -+ bzero(&src, sizeof(src)); -+ src.sin_family = AF_INET; -+ src.sin_addr = localbind; -+ if (bind(s, (struct sockaddr *) &src, sizeof(src)) != 0) { -+ warn("bind: %s", strerror(errno)); -+ close(s); return -1; -+ } -+ } -+ if (connect(s, (struct sockaddr *) &dest, sizeof(dest)) < 0) { -+ warn("connect: %s", strerror(errno)); -+ close(s); return -1; -+ } -+ return s; -+} -+ -+/*** open_unixsock ************************************************************/ -+int open_unixsock(struct in_addr inetaddr) -+{ -+ struct sockaddr_un where; -+ struct stat st; -+ char *dir; -+ int s; -+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { -+ warn("socket: %s", strerror(errno)); -+ return s; -+ } -+ callmgr_name_unixsock( &where, inetaddr, localbind); -+ if (stat(where.sun_path, &st) >= 0) -+ { -+ warn("Call manager for %s is already running.", inet_ntoa(inetaddr)); -+ close(s); return -1; -+ } -+ /* Make sure path is valid. */ -+ dir = dirnamex(where.sun_path); -+ if (!make_valid_path(dir, 0770)) -+ fatal("Could not make path to %s: %s", where.sun_path, strerror(errno)); -+ free(dir); -+ if (bind(s, (struct sockaddr *) &where, sizeof(where)) < 0) { -+ warn("bind: %s", strerror(errno)); -+ close(s); return -1; -+ } -+ chmod(where.sun_path, 0777); -+ listen(s, 127); -+ return s; -+} -+ -+/*** close_inetsock ***********************************************************/ -+void close_inetsock(int fd, struct in_addr inetaddr) -+{ -+ close(fd); -+} -+ -+/*** close_unixsock ***********************************************************/ -+void close_unixsock(int fd, struct in_addr inetaddr) -+{ -+ struct sockaddr_un where; -+ close(fd); -+ callmgr_name_unixsock(&where, inetaddr, localbind); -+ unlink(where.sun_path); -+} -+ -+/*** make a unix socket address ***********************************************/ -+void callmgr_name_unixsock(struct sockaddr_un *where, -+ struct in_addr inetaddr, -+ struct in_addr localbind) -+{ -+ char localaddr[16], remoteaddr[16]; -+ where->sun_family = AF_UNIX; -+ strncpy(localaddr, inet_ntoa(localbind), 16); -+ strncpy(remoteaddr, inet_ntoa(inetaddr), 16); -+ snprintf(where->sun_path, sizeof(where->sun_path), -+ PPTP_SOCKET_PREFIX "%s:%i", remoteaddr,call_ID); -+} ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_callmgr.h -@@ -0,0 +1,17 @@ -+/* pptp_callmgr.h ... Call manager for PPTP connections. -+ * Handles TCP port 1723 protocol. -+ * C. Scott Ananian -+ * -+ * $Id: pptp_callmgr.h,v 1.3 2003/02/17 00:22:17 quozl Exp $ -+ */ -+ -+#define PPTP_SOCKET_PREFIX "/var/run/pptp/" -+ -+int callmgr_main(struct in_addr inetaddr, -+ char phonenr[], -+ int window, -+ int pcallid); -+ -+void callmgr_name_unixsock(struct sockaddr_un *where, -+ struct in_addr inetaddr, -+ struct in_addr localbind); ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_ctrl.c -@@ -0,0 +1,1077 @@ -+/* pptp_ctrl.c ... handle PPTP control connection. -+ * C. Scott Ananian -+ * -+ * $Id: pptp_ctrl.c,v 1.31 2005/03/31 07:42:39 quozl Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pptp_msg.h" -+#include "pptp_ctrl.h" -+#include "pptp_options.h" -+#include "vector.h" -+#include "util.h" -+#include "pptp_quirks.h" -+ -+/* BECAUSE OF SIGNAL LIMITATIONS, EACH PROCESS CAN ONLY MANAGE ONE -+ * CONNECTION. SO THIS 'PPTP_CONN' STRUCTURE IS A BIT MISLEADING. -+ * WE'LL KEEP CONNECTION-SPECIFIC INFORMATION IN THERE ANYWAY (AS -+ * OPPOSED TO USING GLOBAL VARIABLES), BUT BEWARE THAT THE ENTIRE -+ * UNIX SIGNAL-HANDLING SEMANTICS WOULD HAVE TO CHANGE (OR THE -+ * TIME-OUT CODE DRASTICALLY REWRITTEN) BEFORE YOU COULD DO A -+ * PPTP_CONN_OPEN MORE THAN ONCE PER PROCESS AND GET AWAY WITH IT. -+ */ -+ -+/* This structure contains connection-specific information that the -+ * signal handler needs to see. Thus, it needs to be in a global -+ * variable. If you end up using pthreads or something (why not -+ * just processes?), this would have to be placed in a thread-specific -+ * data area, using pthread_get|set_specific, etc., so I've -+ * conveniently encapsulated it for you. -+ * [linux threads will have to support thread-specific signals -+ * before this would work at all, which, as of this writing -+ * (linux-threads v0.6, linux kernel 2.1.72), it does not.] -+ */ -+ -+/* Globals */ -+ -+/* control the number of times echo packets will be logged */ -+static int nlogecho = 10; -+ -+static struct thread_specific { -+ struct sigaction old_sigaction; /* evil signals */ -+ PPTP_CONN * conn; -+} global; -+ -+#define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */ -+ -+struct PPTP_CONN { -+ int inet_sock; -+ /* Connection States */ -+ enum { -+ CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED -+ } conn_state; /* on startup: CONN_IDLE */ -+ /* Keep-alive states */ -+ enum { -+ KA_NONE, KA_OUTSTANDING -+ } ka_state; /* on startup: KA_NONE */ -+ /* Keep-alive ID; monotonically increasing (watch wrap-around!) */ -+ u_int32_t ka_id; /* on startup: 1 */ -+ /* Other properties. */ -+ u_int16_t version; -+ u_int16_t firmware_rev; -+ u_int8_t hostname[64], vendor[64]; -+ /* XXX these are only PNS properties, currently XXX */ -+ /* Call assignment information. */ -+ u_int16_t call_serial_number; -+ VECTOR *call; -+ void * closure; -+ pptp_conn_cb callback; -+ /******* IO buffers ******/ -+ char * read_buffer, *write_buffer; -+ size_t read_alloc, write_alloc; -+ size_t read_size, write_size; -+}; -+ -+struct PPTP_CALL { -+ /* Call properties */ -+ enum { -+ PPTP_CALL_PAC, PPTP_CALL_PNS -+ } call_type; -+ union { -+ enum pptp_pac_state { -+ PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS -+ } pac; -+ enum pptp_pns_state { -+ PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT -+ } pns; -+ } state; -+ u_int16_t call_id, peer_call_id; -+ u_int16_t sernum; -+ u_int32_t speed; -+ /* For user data: */ -+ pptp_call_cb callback; -+ void * closure; -+}; -+ -+ -+/* PPTP error codes: ----------------------------------------------*/ -+ -+/* (General Error Codes) */ -+static const struct { -+ const char *name, *desc; -+} pptp_general_errors[] = { -+#define PPTP_GENERAL_ERROR_NONE 0 -+ { "(None)", "No general error" }, -+#define PPTP_GENERAL_ERROR_NOT_CONNECTED 1 -+ { "(Not-Connected)", "No control connection exists yet for this " -+ "PAC-PNS pair" }, -+#define PPTP_GENERAL_ERROR_BAD_FORMAT 2 -+ { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" }, -+#define PPTP_GENERAL_ERROR_BAD_VALUE 3 -+ { "(Bad-Value)", "One of the field values was out of range or " -+ "reserved field was non-zero" }, -+#define PPTP_GENERAL_ERROR_NO_RESOURCE 4 -+ { "(No-Resource)", "Insufficient resources to handle this command now" }, -+#define PPTP_GENERAL_ERROR_BAD_CALLID 5 -+ { "(Bad-Call ID)", "The Call ID is invalid in this context" }, -+#define PPTP_GENERAL_ERROR_PAC_ERROR 6 -+ { "(PAC-Error)", "A generic vendor-specific error occured in the PAC" } -+}; -+ -+#define MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \ -+ sizeof(pptp_general_errors[0]) - 1) -+ -+/* Outgoing Call Reply Result Codes */ -+static const char *pptp_out_call_reply_result[] = { -+/* 0 */ "Unknown Result Code", -+/* 1 */ "Connected", -+/* 2 */ "General Error", -+/* 3 */ "No Carrier Detected", -+/* 4 */ "Busy Signal", -+/* 5 */ "No Dial Tone", -+/* 6 */ "Time Out", -+/* 7 */ "Not Accepted, Call is administratively prohibited" }; -+ -+#define MAX_OUT_CALL_REPLY_RESULT 7 -+ -+/* Call Disconnect Notify Result Codes */ -+static const char *pptp_call_disc_ntfy[] = { -+/* 0 */ "Unknown Result Code", -+/* 1 */ "Lost Carrier", -+/* 2 */ "General Error", -+/* 3 */ "Administrative Shutdown", -+/* 4 */ "(your) Request" }; -+ -+#define MAX_CALL_DISC_NTFY 4 -+ -+/* Call Disconnect Notify Result Codes */ -+static const char *pptp_start_ctrl_conn_rply[] = { -+/* 0 */ "Unknown Result Code", -+/* 1 */ "Successful Channel Establishment", -+/* 2 */ "General Error", -+/* 3 */ "Command Channel Already Exists", -+/* 4 */ "Requester is not Authorized" }; -+ -+#define MAX_START_CTRL_CONN_REPLY 4 -+ -+/* timing options */ -+int idle_wait = PPTP_TIMEOUT; -+int max_echo_wait = PPTP_TIMEOUT; -+ -+/* Local prototypes */ -+static void pptp_reset_timer(void); -+static void pptp_handle_timer(); -+/* Write/read as much as we can without blocking. */ -+int pptp_write_some(PPTP_CONN * conn); -+int pptp_read_some(PPTP_CONN * conn); -+/* Make valid packets from read_buffer */ -+int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size); -+/* Add packet to write_buffer */ -+int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size); -+/* Dispatch packets (general) */ -+int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size); -+/* Dispatch packets (control messages) */ -+int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size); -+/* Set link info, for pptp servers that need it. -+ this is a noop, unless the user specified a quirk and -+ there's a set_link hook defined in the quirks table -+ for that quirk */ -+void pptp_set_link(PPTP_CONN * conn, int peer_call_id); -+ -+/*** log error information in control packets *********************************/ -+static void ctrlp_error( int result, int error, int cause, -+ const char *result_text[], int max_result) -+{ -+ if( cause >= 0) -+ warn("Result code is %d '%s'. Error code is %d, Cause code is %d", -+ result, result_text[result <= max_result ? result : 0], error, -+ cause ); -+ else -+ warn("Reply result code is %d '%s'. Error code is %d", -+ result, result_text[result <= max_result ? result : 0], error); -+ if ((error > 0) && (error <= MAX_GENERAL_ERROR)){ -+ if( result != PPTP_RESULT_GENERAL_ERROR ) -+ warn("Result code is something else then \"general error\", " -+ "so the following error is probably bogus."); -+ warn("Error is '%s', Error message: '%s'", -+ pptp_general_errors[error].name, -+ pptp_general_errors[error].desc); -+ } -+} -+ -+static const char *ctrl_msg_types[] = { -+ "invalid control message type", -+/* (Control Connection Management) */ -+ "Start-Control-Connection-Request", /* 1 */ -+ "Start-Control-Connection-Reply", /* 2 */ -+ "Stop-Control-Connection-Request", /* 3 */ -+ "Stop-Control-Connection-Reply", /* 4 */ -+ "Echo-Request", /* 5 */ -+ "Echo-Reply", /* 6 */ -+/* (Call Management) */ -+ "Outgoing-Call-Request", /* 7 */ -+ "Outgoing-Call-Reply", /* 8 */ -+ "Incoming-Call-Request", /* 9 */ -+ "Incoming-Call-Reply", /* 10 */ -+ "Incoming-Call-Connected", /* 11 */ -+ "Call-Clear-Request", /* 12 */ -+ "Call-Disconnect-Notify", /* 13 */ -+/* (Error Reporting) */ -+ "WAN-Error-Notify", /* 14 */ -+/* (PPP Session Control) */ -+ "Set-Link-Info" /* 15 */ -+}; -+#define MAX_CTRLMSG_TYPE 15 -+ -+/*** report a sent packet ****************************************************/ -+static void ctrlp_rep( void * buffer, int size, int isbuff) -+{ -+ struct pptp_header *packet = buffer; -+ unsigned int type; -+ if(size < sizeof(struct pptp_header)) return; -+ type = ntoh16(packet->ctrl_type); -+ /* FIXME: do not report sending echo requests as long as they are -+ * sent in a signal handler. This may dead lock as the syslog call -+ * is not reentrant */ -+ if( type == PPTP_ECHO_RQST ) return; -+ /* don't keep reporting sending of echo's */ -+ if( (type == PPTP_ECHO_RQST || type == PPTP_ECHO_RPLY) && nlogecho <= 0 ) return; -+ dbglog("%s control packet type is %d '%s'\n",isbuff ? "Buffered" : "Sent", -+ type, ctrl_msg_types[type <= MAX_CTRLMSG_TYPE ? type : 0]); -+ -+} -+ -+ -+ -+/* Open new pptp_connection. Returns NULL on failure. */ -+PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback) -+{ -+ PPTP_CONN *conn; -+ /* Allocate structure */ -+ if ((conn = malloc(sizeof(*conn))) == NULL) return NULL; -+ if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; } -+ /* Initialize */ -+ conn->inet_sock = inet_sock; -+ conn->conn_state = CONN_IDLE; -+ conn->ka_state = KA_NONE; -+ conn->ka_id = 1; -+ conn->call_serial_number = 0; -+ conn->callback = callback; -+ /* Create I/O buffers */ -+ conn->read_size = conn->write_size = 0; -+ conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE; -+ conn->read_buffer = -+ malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc); -+ conn->write_buffer = -+ malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc); -+ if (conn->read_buffer == NULL || conn->write_buffer == NULL) { -+ if (conn->read_buffer != NULL) free(conn->read_buffer); -+ if (conn->write_buffer != NULL) free(conn->write_buffer); -+ vector_destroy(conn->call); free(conn); return NULL; -+ } -+ /* Make this socket non-blocking. */ -+ fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK); -+ /* Request connection from server, if this is a client */ -+ if (isclient) { -+ struct pptp_start_ctrl_conn packet = { -+ PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST), -+ hton16(PPTP_VERSION), 0, 0, -+ hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP), -+ hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), -+ PPTP_HOSTNAME, PPTP_VENDOR -+ }; -+ /* fix this packet, if necessary */ -+ int idx, rc; -+ idx = get_quirk_index(); -+ if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) { -+ if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet))) -+ warn("calling the start_ctrl_conn hook failed (%d)", rc); -+ } -+ if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) -+ conn->conn_state = CONN_WAIT_CTL_REPLY; -+ else -+ return NULL; /* could not send initial start request. */ -+ } -+ /* Set up interval/keep-alive timer */ -+ /* First, register handler for SIGALRM */ -+ sigpipe_create(); -+ sigpipe_assign(SIGALRM); -+ global.conn = conn; -+ /* Reset event timer */ -+ pptp_reset_timer(); -+ /* all done. */ -+ return conn; -+} -+ -+int pptp_conn_established(PPTP_CONN *conn) { -+ return (conn->conn_state == CONN_ESTABLISHED); -+} -+ -+/* This currently *only* works for client call requests. -+ * We need to do something else to allocate calls for incoming requests. -+ */ -+PPTP_CALL * pptp_call_open(PPTP_CONN * conn, int call_id,pptp_call_cb callback, -+ char *phonenr,int window) -+{ -+ PPTP_CALL * call; -+ int idx, rc; -+ /* Send off the call request */ -+ struct pptp_out_call_rqst packet = { -+ PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST), -+ 0,0, /*call_id, sernum */ -+ hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX), -+ hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP), -+ hton16(window), 0, 0, 0, {0}, {0} -+ }; -+ assert(conn && conn->call); -+ assert(conn->conn_state == CONN_ESTABLISHED); -+ /* Assign call id */ -+ if (!call_id && !vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &call_id)) -+ /* no more calls available! */ -+ return NULL; -+ /* allocate structure. */ -+ if ((call = malloc(sizeof(*call))) == NULL) return NULL; -+ /* Initialize call structure */ -+ call->call_type = PPTP_CALL_PNS; -+ call->state.pns = PNS_IDLE; -+ call->call_id = (u_int16_t) call_id; -+ call->sernum = conn->call_serial_number++; -+ call->callback = callback; -+ call->closure = NULL; -+ packet.call_id = htons(call->call_id); -+ packet.call_sernum = htons(call->sernum); -+ /* if we have a quirk, build a new packet to fit it */ -+ idx = get_quirk_index(); -+ if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) { -+ if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet))) -+ warn("calling the out_call_rqst hook failed (%d)", rc); -+ } -+ /* fill in the phone number if it was specified */ -+ if (phonenr) { -+ strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num)); -+ packet.phone_len = strlen(phonenr); -+ if( packet.phone_len > sizeof(packet.phone_num)) -+ packet.phone_len = sizeof(packet.phone_num); -+ packet.phone_len = hton16 (packet.phone_len); -+ } -+ if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) { -+ pptp_reset_timer(); -+ call->state.pns = PNS_WAIT_REPLY; -+ /* and add it to the call vector */ -+ vector_insert(conn->call, call_id, call); -+ return call; -+ } else { /* oops, unsuccessful. Deallocate. */ -+ free(call); -+ return NULL; -+ } -+} -+ -+/*** pptp_call_close **********************************************************/ -+void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call) -+{ -+ struct pptp_call_clear_rqst rqst = { -+ PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0 -+ }; -+ assert(conn && conn->call); assert(call); -+ assert(vector_contains(conn->call, call->call_id)); -+ /* haven't thought about PAC yet */ -+ assert(call->call_type == PPTP_CALL_PNS); -+ assert(call->state.pns != PNS_IDLE); -+ rqst.call_id = hton16(call->call_id); -+ /* don't check state against WAIT_DISCONNECT... allow multiple disconnect -+ * requests to be made. -+ */ -+ pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst)); -+ pptp_reset_timer(); -+ call->state.pns = PNS_WAIT_DISCONNECT; -+ /* call structure will be freed when we have confirmation of disconnect. */ -+} -+ -+/*** hard close ***************************************************************/ -+void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call) -+{ -+ assert(conn && conn->call); assert(call); -+ assert(vector_contains(conn->call, call->call_id)); -+ /* notify */ -+ if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE); -+ /* deallocate */ -+ vector_remove(conn->call, call->call_id); -+ free(call); -+} -+ -+/*** this is a soft close *****************************************************/ -+void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason) -+{ -+ struct pptp_stop_ctrl_conn rqst = { -+ PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), -+ hton8(close_reason), 0, 0 -+ }; -+ int i; -+ assert(conn && conn->call); -+ /* avoid repeated close attempts */ -+ if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY) -+ return; -+ /* close open calls, if any */ -+ for (i = 0; i < vector_size(conn->call); i++) -+ pptp_call_close(conn, vector_get_Nth(conn->call, i)); -+ /* now close connection */ -+ info("Closing PPTP connection"); -+ pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst)); -+ pptp_reset_timer(); /* wait 60 seconds for reply */ -+ conn->conn_state = CONN_WAIT_STOP_REPLY; -+ return; -+} -+ -+/*** this is a hard close *****************************************************/ -+void pptp_conn_destroy(PPTP_CONN * conn) -+{ -+ int i; -+ assert(conn != NULL); assert(conn->call != NULL); -+ /* destroy all open calls */ -+ for (i = 0; i < vector_size(conn->call); i++) -+ pptp_call_destroy(conn, vector_get_Nth(conn->call, i)); -+ /* notify */ -+ if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE); -+ sigpipe_close(); -+ close(conn->inet_sock); -+ /* deallocate */ -+ vector_destroy(conn->call); -+ free(conn); -+} -+ -+/*** Deal with messages, in a non-blocking manner -+ * Add file descriptors used by pptp to fd_set. -+ */ -+void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, -+ int * max_fd) -+{ -+ assert(conn && conn->call); -+ /* Add fd to write_set if there are outstanding writes. */ -+ if (conn->write_size > 0) -+ FD_SET(conn->inet_sock, write_set); -+ /* Always add fd to read_set. (always want something to read) */ -+ FD_SET(conn->inet_sock, read_set); -+ if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock; -+ /* Add signal pipe file descriptor to set */ -+ int sig_fd = sigpipe_fd(); -+ FD_SET(sig_fd, read_set); -+ if (*max_fd < sig_fd) *max_fd = sig_fd; -+} -+ -+/*** handle any pptp file descriptors set in fd_set, and clear them ***********/ -+int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set) -+{ -+ int r = 0; -+ assert(conn && conn->call); -+ /* Check for signals */ -+ if (FD_ISSET(sigpipe_fd(), read_set)) { -+ if (sigpipe_read() == SIGALRM) pptp_handle_timer(); -+ FD_CLR(sigpipe_fd(), read_set); -+ } -+ /* Check write_set could be set. */ -+ if (FD_ISSET(conn->inet_sock, write_set)) { -+ FD_CLR(conn->inet_sock, write_set); -+ if (conn->write_size > 0) -+ r = pptp_write_some(conn);/* write as much as we can without blocking */ -+ } -+ /* Check read_set */ -+ if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) { -+ void *buffer; size_t size; -+ FD_CLR(conn->inet_sock, read_set); -+ r = pptp_read_some(conn); /* read as much as we can without blocking */ -+ if (r < 0) -+ return r; -+ /* make packets of the buffer, while we can. */ -+ while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) { -+ r = pptp_dispatch_packet(conn, buffer, size); -+ free(buffer); -+ } -+ } -+ /* That's all, folks. Simple, eh? */ -+ return r; -+} -+ -+/*** Non-blocking write *******************************************************/ -+int pptp_write_some(PPTP_CONN * conn) { -+ ssize_t retval; -+ assert(conn && conn->call); -+ retval = write(conn->inet_sock, conn->write_buffer, conn->write_size); -+ if (retval < 0) { /* error. */ -+ if (errno == EAGAIN || errno == EINTR) { -+ return 0; -+ } else { /* a real error */ -+ warn("write error: %s", strerror(errno)); -+ return -1; -+ } -+ } -+ assert(retval <= conn->write_size); -+ conn->write_size -= retval; -+ memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size); -+ ctrlp_rep(conn->write_buffer, retval, 0); -+ return 0; -+} -+ -+/*** Non-blocking read ********************************************************/ -+int pptp_read_some(PPTP_CONN * conn) -+{ -+ ssize_t retval; -+ assert(conn && conn->call); -+ if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */ -+ char *new_buffer = realloc(conn->read_buffer, -+ sizeof(*(conn->read_buffer)) * conn->read_alloc * 2); -+ if (new_buffer == NULL) { -+ warn("Out of memory"); return -1; -+ } -+ conn->read_alloc *= 2; -+ conn->read_buffer = new_buffer; -+ } -+ retval = read(conn->inet_sock, conn->read_buffer + conn->read_size, -+ conn->read_alloc - conn->read_size); -+ if (retval == 0) { -+ warn("read returned zero, peer has closed"); -+ return -1; -+ } -+ if (retval < 0) { -+ if (errno == EINTR || errno == EAGAIN) -+ return 0; -+ else { /* a real error */ -+ warn("read error: %s", strerror(errno)); -+ return -1; -+ } -+ } -+ conn->read_size += retval; -+ assert(conn->read_size <= conn->read_alloc); -+ return 0; -+} -+ -+/*** Packet formation *********************************************************/ -+int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size) -+{ -+ struct pptp_header *header; -+ size_t bad_bytes = 0; -+ assert(conn && conn->call); assert(buf != NULL); assert(size != NULL); -+ /* Give up unless there are at least sizeof(pptp_header) bytes */ -+ while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) { -+ /* Throw out bytes until we have a valid header. */ -+ header = (struct pptp_header *) (conn->read_buffer + bad_bytes); -+ if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout; -+ if (ntoh16(header->reserved0) != 0) -+ warn("reserved0 field is not zero! (0x%x) Cisco feature? \n", -+ ntoh16(header->reserved0)); -+ if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout; -+ if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout; -+ /* well. I guess it's good. Let's see if we've got it all. */ -+ if (ntoh16(header->length) > (conn->read_size-bad_bytes)) -+ /* nope. Let's wait until we've got it, then. */ -+ goto flushbadbytes; -+ /* One last check: */ -+ if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) && -+ (ntoh16(header->length) != -+ PPTP_CTRL_SIZE(ntoh16(header->ctrl_type)))) -+ goto throwitout; -+ /* well, I guess we've got it. */ -+ *size = ntoh16(header->length); -+ *buf = malloc(*size); -+ if (*buf == NULL) { warn("Out of memory."); return 0; /* ack! */ } -+ memcpy(*buf, conn->read_buffer + bad_bytes, *size); -+ /* Delete this packet from the read_buffer. */ -+ conn->read_size -= (bad_bytes + *size); -+ memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size, -+ conn->read_size); -+ if (bad_bytes > 0) -+ warn("%lu bad bytes thrown away.", (unsigned long) bad_bytes); -+ return 1; -+throwitout: -+ bad_bytes++; -+ } -+flushbadbytes: -+ /* no more packets. Let's get rid of those bad bytes */ -+ conn->read_size -= bad_bytes; -+ memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size); -+ if (bad_bytes > 0) -+ warn("%lu bad bytes thrown away.", (unsigned long) bad_bytes); -+ return 0; -+} -+ -+/*** pptp_send_ctrl_packet ****************************************************/ -+int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size) -+{ -+ assert(conn && conn->call); assert(buffer); -+ if( conn->write_size > 0) pptp_write_some( conn); -+ if( conn->write_size == 0) { -+ ssize_t retval; -+ retval = write(conn->inet_sock, buffer, size); -+ if (retval < 0) { /* error. */ -+ if (errno == EAGAIN || errno == EINTR) { -+ /* ignore */; -+ retval = 0; -+ } else { /* a real error */ -+ warn("write error: %s", strerror(errno)); -+ pptp_conn_destroy(conn); /* shut down fast. */ -+ return 0; -+ } -+ } -+ ctrlp_rep( buffer, retval, 0); -+ size -= retval; -+ if( size <= 0) return 1; -+ } -+ /* Shove anything not written into the write buffer */ -+ if (conn->write_size + size > conn->write_alloc) { /* need more memory */ -+ char *new_buffer = realloc(conn->write_buffer, -+ sizeof(*(conn->write_buffer)) * conn->write_alloc * 2); -+ if (new_buffer == NULL) { -+ warn("Out of memory"); return 0; -+ } -+ conn->write_alloc *= 2; -+ conn->write_buffer = new_buffer; -+ } -+ memcpy(conn->write_buffer + conn->write_size, buffer, size); -+ conn->write_size += size; -+ ctrlp_rep( buffer,size,1); -+ return 1; -+} -+ -+/*** Packet Dispatch **********************************************************/ -+int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size) -+{ -+ int r = 0; -+ struct pptp_header *header = (struct pptp_header *)buffer; -+ assert(conn && conn->call); assert(buffer); -+ assert(ntoh32(header->magic) == PPTP_MAGIC); -+ assert(ntoh16(header->length) == size); -+ switch (ntoh16(header->pptp_type)) { -+ case PPTP_MESSAGE_CONTROL: -+ r = ctrlp_disp(conn, buffer, size); -+ break; -+ case PPTP_MESSAGE_MANAGE: -+ /* MANAGEMENT messages aren't even part of the spec right now. */ -+ dbglog("PPTP management message received, but not understood."); -+ break; -+ default: -+ dbglog("Unknown PPTP control message type received: %u", -+ (unsigned int) ntoh16(header->pptp_type)); -+ break; -+ } -+ return r; -+} -+ -+/*** log echo request/replies *************************************************/ -+static void logecho( int type) -+{ -+ /* hack to stop flooding the log files (the most interesting part is right -+ * after the connection built-up) */ -+ if( nlogecho > 0) { -+ dbglog("Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply"); -+ if( --nlogecho == 0) -+ dbglog("no more Echo Reply/Request packets will be reported."); -+ } -+} -+ -+/*** pptp_dispatch_ctrl_packet ************************************************/ -+int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size) -+{ -+ struct pptp_header *header = (struct pptp_header *)buffer; -+ u_int8_t close_reason = PPTP_STOP_NONE; -+ assert(conn && conn->call); assert(buffer); -+ assert(ntoh32(header->magic) == PPTP_MAGIC); -+ assert(ntoh16(header->length) == size); -+ assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL); -+ if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) { -+ warn("Invalid packet received [type: %d; length: %d].", -+ (int) ntoh16(header->ctrl_type), (int) size); -+ return 0; -+ } -+ switch (ntoh16(header->ctrl_type)) { -+ /* ----------- STANDARD Start-Session MESSAGES ------------ */ -+ case PPTP_START_CTRL_CONN_RQST: -+ { -+ struct pptp_start_ctrl_conn *packet = -+ (struct pptp_start_ctrl_conn *) buffer; -+ struct pptp_start_ctrl_conn reply = { -+ PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY), -+ hton16(PPTP_VERSION), 0, 0, -+ hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP), -+ hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), -+ PPTP_HOSTNAME, PPTP_VENDOR }; -+ int idx, rc; -+ dbglog("Received Start Control Connection Request"); -+ /* fix this packet, if necessary */ -+ idx = get_quirk_index(); -+ if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) { -+ if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply))) -+ warn("calling the start_ctrl_conn hook failed (%d)", rc); -+ } -+ if (conn->conn_state == CONN_IDLE) { -+ if (ntoh16(packet->version) < PPTP_VERSION) { -+ /* Can't support this (earlier) PPTP_VERSION */ -+ reply.version = packet->version; -+ /* protocol version not supported */ -+ reply.result_code = hton8(5); -+ pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); -+ pptp_reset_timer(); /* give sender a chance for a retry */ -+ } else { /* same or greater version */ -+ if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { -+ conn->conn_state = CONN_ESTABLISHED; -+ dbglog("server connection ESTABLISHED."); -+ pptp_reset_timer(); -+ } -+ } -+ } -+ break; -+ } -+ case PPTP_START_CTRL_CONN_RPLY: -+ { -+ struct pptp_start_ctrl_conn *packet = -+ (struct pptp_start_ctrl_conn *) buffer; -+ dbglog("Received Start Control Connection Reply"); -+ if (conn->conn_state == CONN_WAIT_CTL_REPLY) { -+ /* XXX handle collision XXX [see rfc] */ -+ if (ntoh16(packet->version) != PPTP_VERSION) { -+ if (conn->callback != NULL) -+ conn->callback(conn, CONN_OPEN_FAIL); -+ close_reason = PPTP_STOP_PROTOCOL; -+ goto pptp_conn_close; -+ } -+ if (ntoh8(packet->result_code) != 1 && -+ /* J'ai change le if () afin que la connection ne se ferme -+ * pas pour un "rien" :p adel@cybercable.fr - -+ * -+ * Don't close the connection if the result code is zero -+ * (feature found in certain ADSL modems) -+ */ -+ ntoh8(packet->result_code) != 0) { -+ dbglog("Negative reply received to our Start Control " -+ "Connection Request"); -+ ctrlp_error(packet->result_code, packet->error_code, -+ -1, pptp_start_ctrl_conn_rply, -+ MAX_START_CTRL_CONN_REPLY); -+ if (conn->callback != NULL) -+ conn->callback(conn, CONN_OPEN_FAIL); -+ close_reason = PPTP_STOP_PROTOCOL; -+ goto pptp_conn_close; -+ } -+ conn->conn_state = CONN_ESTABLISHED; -+ /* log session properties */ -+ conn->version = ntoh16(packet->version); -+ conn->firmware_rev = ntoh16(packet->firmware_rev); -+ memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname)); -+ memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor)); -+ pptp_reset_timer(); /* 60 seconds until keep-alive */ -+ dbglog("Client connection established."); -+ if (conn->callback != NULL) -+ conn->callback(conn, CONN_OPEN_DONE); -+ } /* else goto pptp_conn_close; */ -+ break; -+ } -+ /* ----------- STANDARD Stop-Session MESSAGES ------------ */ -+ case PPTP_STOP_CTRL_CONN_RQST: -+ { -+ /* conn_state should be CONN_ESTABLISHED, but it could be -+ * something else */ -+ struct pptp_stop_ctrl_conn reply = { -+ PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), -+ hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0 -+ }; -+ dbglog("Received Stop Control Connection Request."); -+ if (conn->conn_state == CONN_IDLE) break; -+ if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { -+ if (conn->callback != NULL) -+ conn->callback(conn, CONN_CLOSE_RQST); -+ conn->conn_state = CONN_IDLE; -+ return -1; -+ } -+ break; -+ } -+ case PPTP_STOP_CTRL_CONN_RPLY: -+ { -+ dbglog("Received Stop Control Connection Reply."); -+ /* conn_state should be CONN_WAIT_STOP_REPLY, but it -+ * could be something else */ -+ if (conn->conn_state == CONN_IDLE) break; -+ conn->conn_state = CONN_IDLE; -+ return -1; -+ } -+ /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */ -+ case PPTP_ECHO_RPLY: -+ { -+ struct pptp_echo_rply *packet = -+ (struct pptp_echo_rply *) buffer; -+ logecho( PPTP_ECHO_RPLY); -+ if ((conn->ka_state == KA_OUTSTANDING) && -+ (ntoh32(packet->identifier) == conn->ka_id)) { -+ conn->ka_id++; -+ conn->ka_state = KA_NONE; -+ pptp_reset_timer(); -+ } -+ break; -+ } -+ case PPTP_ECHO_RQST: -+ { -+ struct pptp_echo_rqst *packet = -+ (struct pptp_echo_rqst *) buffer; -+ struct pptp_echo_rply reply = { -+ PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), -+ packet->identifier, /* skip hton32(ntoh32(id)) */ -+ hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0 -+ }; -+ logecho( PPTP_ECHO_RQST); -+ pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); -+ pptp_reset_timer(); -+ break; -+ } -+ /* ----------- OUTGOING CALL MESSAGES ------------ */ -+ case PPTP_OUT_CALL_RQST: -+ { -+ struct pptp_out_call_rqst *packet = -+ (struct pptp_out_call_rqst *)buffer; -+ struct pptp_out_call_rply reply = { -+ PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY), -+ 0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0, -+ hton32(PPTP_CONNECT_SPEED), -+ hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0 -+ }; -+ dbglog("Received Outgoing Call Request."); -+ /* XXX PAC: eventually this should make an outgoing call. XXX */ -+ reply.result_code = hton8(7); /* outgoing calls verboten */ -+ pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); -+ break; -+ } -+ case PPTP_OUT_CALL_RPLY: -+ { -+ struct pptp_out_call_rply *packet = -+ (struct pptp_out_call_rply *)buffer; -+ PPTP_CALL * call; -+ u_int16_t callid = ntoh16(packet->call_id_peer); -+ dbglog("Received Outgoing Call Reply."); -+ if (!vector_search(conn->call, (int) callid, &call)) { -+ dbglog("PPTP_OUT_CALL_RPLY received for non-existant call: " -+ "peer call ID (us) %d call ID (them) %d.", -+ callid, ntoh16(packet->call_id)); -+ break; -+ } -+ if (call->call_type != PPTP_CALL_PNS) { -+ dbglog("Ack! How did this call_type get here?"); /* XXX? */ -+ break; -+ } -+ if (call->state.pns != PNS_WAIT_REPLY) { -+ warn("Unexpected(?) Outgoing Call Reply will be ignored."); -+ break; -+ } -+ /* check for errors */ -+ if (packet->result_code != 1) { -+ /* An error. Log it verbosely. */ -+ dbglog("Our outgoing call request [callid %d] has not been " -+ "accepted.", (int) callid); -+ ctrlp_error(packet->result_code, packet->error_code, -+ packet->cause_code, pptp_out_call_reply_result, -+ MAX_OUT_CALL_REPLY_RESULT); -+ call->state.pns = PNS_IDLE; -+ if (call->callback != NULL) -+ call->callback(conn, call, CALL_OPEN_FAIL); -+ pptp_call_destroy(conn, call); -+ } else { -+ /* connection established */ -+ call->state.pns = PNS_ESTABLISHED; -+ call->peer_call_id = ntoh16(packet->call_id); -+ call->speed = ntoh32(packet->speed); -+ pptp_reset_timer(); -+ /* call pptp_set_link. unless the user specified a quirk -+ and this quirk has a set_link hook, this is a noop */ -+ pptp_set_link(conn, call->peer_call_id); -+ if (call->callback != NULL) -+ call->callback(conn, call, CALL_OPEN_DONE); -+ dbglog("Outgoing call established (call ID %u, peer's " -+ "call ID %u).\n", call->call_id, call->peer_call_id); -+ } -+ break; -+ } -+ /* ----------- INCOMING CALL MESSAGES ------------ */ -+ /* XXX write me XXX */ -+ /* ----------- CALL CONTROL MESSAGES ------------ */ -+ case PPTP_CALL_CLEAR_RQST: -+ { -+ struct pptp_call_clear_rqst *packet = -+ (struct pptp_call_clear_rqst *)buffer; -+ struct pptp_call_clear_ntfy reply = { -+ PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id, -+ 1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0} -+ }; -+ dbglog("Received Call Clear Request."); -+ if (vector_contains(conn->call, ntoh16(packet->call_id))) { -+ PPTP_CALL * call; -+ vector_search(conn->call, ntoh16(packet->call_id), &call); -+ if (call->callback != NULL) -+ call->callback(conn, call, CALL_CLOSE_RQST); -+ pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); -+ pptp_call_destroy(conn, call); -+ dbglog("Call closed (RQST) (call id %d)", (int) call->call_id); -+ } -+ break; -+ } -+ case PPTP_CALL_CLEAR_NTFY: -+ { -+ struct pptp_call_clear_ntfy *packet = -+ (struct pptp_call_clear_ntfy *)buffer; -+ dbglog("Call disconnect notification received (call id %d)", -+ ntoh16(packet->call_id)); -+ if (vector_contains(conn->call, ntoh16(packet->call_id))) { -+ PPTP_CALL * call; -+ ctrlp_error(packet->result_code, packet->error_code, -+ packet->cause_code, pptp_call_disc_ntfy, -+ MAX_CALL_DISC_NTFY); -+ vector_search(conn->call, ntoh16(packet->call_id), &call); -+ pptp_call_destroy(conn, call); -+ } -+ /* XXX we could log call stats here XXX */ -+ /* XXX not all servers send this XXX */ -+ break; -+ } -+ case PPTP_SET_LINK_INFO: -+ { -+ /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */ -+ /* this is really dealt with in the HDLC deencapsulation, anyway. */ -+ struct pptp_set_link_info *packet = -+ (struct pptp_set_link_info *)buffer; -+ /* log it. */ -+ dbglog("PPTP_SET_LINK_INFO received from peer_callid %u", -+ (unsigned int) ntoh16(packet->call_id_peer)); -+ dbglog(" send_accm is %08lX, recv_accm is %08lX", -+ (unsigned long) ntoh32(packet->send_accm), -+ (unsigned long) ntoh32(packet->recv_accm)); -+ if (!(ntoh32(packet->send_accm) == 0 && -+ ntoh32(packet->recv_accm) == 0)) -+ warn("Non-zero Async Control Character Maps are not supported!"); -+ break; -+ } -+ default: -+ dbglog("Unrecognized Packet %d received.", -+ (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type)); -+ /* goto pptp_conn_close; */ -+ break; -+ } -+ return 0; -+pptp_conn_close: -+ warn("pptp_conn_close(%d)", (int) close_reason); -+ pptp_conn_close(conn, close_reason); -+ return 0; -+} -+ -+/*** pptp_set_link **************************************************************/ -+void pptp_set_link(PPTP_CONN* conn, int peer_call_id) -+{ -+ int idx, rc; -+ /* if we need to send a set_link packet because of buggy -+ hardware or pptp server, do it now */ -+ if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) { -+ struct pptp_set_link_info packet; -+ if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id))) -+ warn("calling the set_link hook failed (%d)", rc); -+ if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) { -+ pptp_reset_timer(); -+ } -+ } -+} -+ -+/*** Get info from call structure *********************************************/ -+/* NOTE: The peer_call_id is undefined until we get a server response. */ -+void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call, -+ u_int16_t * call_id, u_int16_t * peer_call_id) -+{ -+ assert(conn != NULL); assert(call != NULL); -+ *call_id = call->call_id; -+ *peer_call_id = call->peer_call_id; -+} -+ -+/*** pptp_call_closure_put ****************************************************/ -+void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl) -+{ -+ assert(conn != NULL); assert(call != NULL); -+ call->closure = cl; -+} -+ -+/*** pptp_call_closure_get ****************************************************/ -+void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call) -+{ -+ assert(conn != NULL); assert(call != NULL); -+ return call->closure; -+} -+ -+/*** pptp_conn_closure_put ****************************************************/ -+void pptp_conn_closure_put(PPTP_CONN * conn, void *cl) -+{ -+ assert(conn != NULL); -+ conn->closure = cl; -+} -+ -+/*** pptp_conn_closure_get ****************************************************/ -+void * pptp_conn_closure_get(PPTP_CONN * conn) -+{ -+ assert(conn != NULL); -+ return conn->closure; -+} -+ -+/*** Reset keep-alive timer ***************************************************/ -+static void pptp_reset_timer(void) -+{ -+ const struct itimerval tv = { { 0, 0 }, /* stop on time-out */ -+ { idle_wait, 0 } }; -+ if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL); -+} -+ -+ -+/*** Handle keep-alive timer **************************************************/ -+static void pptp_handle_timer() -+{ -+ int i; -+ /* "Keep Alives and Timers, 1": check connection state */ -+ if (global.conn->conn_state != CONN_ESTABLISHED) { -+ if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) -+ /* hard close. */ -+ pptp_conn_destroy(global.conn); -+ else /* soft close */ -+ pptp_conn_close(global.conn, PPTP_STOP_NONE); -+ } -+ /* "Keep Alives and Timers, 2": check echo status */ -+ if (global.conn->ka_state == KA_OUTSTANDING) { -+ /* no response to keep-alive */ -+ info("closing control connection due to missing echo reply"); -+ pptp_conn_close(global.conn, PPTP_STOP_NONE); -+ } else { /* ka_state == NONE */ /* send keep-alive */ -+ struct pptp_echo_rqst rqst = { -+ PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) }; -+ pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst)); -+ global.conn->ka_state = KA_OUTSTANDING; -+ } -+ /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */ -+ for (i = 0; i < vector_size(global.conn->call); i++) { -+ PPTP_CALL * call = vector_get_Nth(global.conn->call, i); -+ if (call->call_type == PPTP_CALL_PNS) { -+ if (call->state.pns == PNS_WAIT_REPLY) { -+ /* send close request */ -+ pptp_call_close(global.conn, call); -+ assert(call->state.pns == PNS_WAIT_DISCONNECT); -+ } else if (call->state.pns == PNS_WAIT_DISCONNECT) { -+ /* hard-close the call */ -+ pptp_call_destroy(global.conn, call); -+ } -+ } else if (call->call_type == PPTP_CALL_PAC) { -+ if (call->state.pac == PAC_WAIT_REPLY) { -+ /* XXX FIXME -- drop the PAC connection XXX */ -+ } else if (call->state.pac == PAC_WAIT_CS_ANS) { -+ /* XXX FIXME -- drop the PAC connection XXX */ -+ } -+ } -+ } -+ pptp_reset_timer(); -+} ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_ctrl.h -@@ -0,0 +1,57 @@ -+/* pptp_ctrl.h ... handle PPTP control connection. -+ * C. Scott Ananian -+ * -+ * $Id: pptp_ctrl.h,v 1.5 2004/11/09 01:42:32 quozl Exp $ -+ */ -+ -+#ifndef INC_PPTP_CTRL_H -+#define INC_PPTP_CTRL_H -+#include -+ -+typedef struct PPTP_CONN PPTP_CONN; -+typedef struct PPTP_CALL PPTP_CALL; -+ -+enum call_state { CALL_OPEN_RQST, CALL_OPEN_DONE, CALL_OPEN_FAIL, -+ CALL_CLOSE_RQST, CALL_CLOSE_DONE }; -+enum conn_state { CONN_OPEN_RQST, CONN_OPEN_DONE, CONN_OPEN_FAIL, -+ CONN_CLOSE_RQST, CONN_CLOSE_DONE }; -+ -+typedef void (*pptp_call_cb)(PPTP_CONN*, PPTP_CALL*, enum call_state); -+typedef void (*pptp_conn_cb)(PPTP_CONN*, enum conn_state); -+ -+/* if 'isclient' is true, then will send 'conn open' packet to other host. -+ * not necessary if this is being opened by a server process after -+ * receiving a conn_open packet from client. -+ */ -+PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, -+ pptp_conn_cb callback); -+PPTP_CALL * pptp_call_open(PPTP_CONN * conn, int call_id, -+ pptp_call_cb callback, char *phonenr,int window); -+int pptp_conn_established(PPTP_CONN * conn); -+/* soft close. Will callback on completion. */ -+void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call); -+/* hard close. */ -+void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call); -+/* soft close. Will callback on completion. */ -+void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason); -+/* hard close */ -+void pptp_conn_destroy(PPTP_CONN * conn); -+ -+/* Add file descriptors used by pptp to fd_set. */ -+void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int *max_fd); -+/* handle any pptp file descriptors set in fd_set, and clear them */ -+int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set); -+ -+/* Get info about connection, call */ -+void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call, -+ u_int16_t * call_id, u_int16_t * peer_call_id); -+/* Arbitrary user data about this call/connection. -+ * It is the caller's responsibility to free this data before calling -+ * pptp_call|conn_close() -+ */ -+void * pptp_conn_closure_get(PPTP_CONN * conn); -+void pptp_conn_closure_put(PPTP_CONN * conn, void *cl); -+void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call); -+void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl); -+ -+#endif /* INC_PPTP_CTRL_H */ ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_msg.h -@@ -0,0 +1,303 @@ -+/* pptp.h: packet structures and magic constants for the PPTP protocol -+ * C. Scott Ananian -+ * -+ * $Id: pptp_msg.h,v 1.3 2003/02/15 10:37:21 quozl Exp $ -+ */ -+ -+#ifndef INC_PPTP_H -+#define INC_PPTP_H -+ -+/* Grab definitions of int16, int32, etc. */ -+#include -+/* define "portable" htons, etc. */ -+#define hton8(x) (x) -+#define ntoh8(x) (x) -+#define hton16(x) htons(x) -+#define ntoh16(x) ntohs(x) -+#define hton32(x) htonl(x) -+#define ntoh32(x) ntohl(x) -+ -+/* PPTP magic numbers: ----------------------------------------- */ -+ -+#define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */ -+#define PPTP_PORT 1723 /* PPTP TCP port number */ -+#define PPTP_PROTO 47 /* PPTP IP protocol number */ -+ -+/* Control Connection Message Types: --------------------------- */ -+ -+#define PPTP_MESSAGE_CONTROL 1 -+#define PPTP_MESSAGE_MANAGE 2 -+ -+/* Control Message Types: -------------------------------------- */ -+ -+/* (Control Connection Management) */ -+#define PPTP_START_CTRL_CONN_RQST 1 -+#define PPTP_START_CTRL_CONN_RPLY 2 -+#define PPTP_STOP_CTRL_CONN_RQST 3 -+#define PPTP_STOP_CTRL_CONN_RPLY 4 -+#define PPTP_ECHO_RQST 5 -+#define PPTP_ECHO_RPLY 6 -+ -+/* (Call Management) */ -+#define PPTP_OUT_CALL_RQST 7 -+#define PPTP_OUT_CALL_RPLY 8 -+#define PPTP_IN_CALL_RQST 9 -+#define PPTP_IN_CALL_RPLY 10 -+#define PPTP_IN_CALL_CONNECT 11 -+#define PPTP_CALL_CLEAR_RQST 12 -+#define PPTP_CALL_CLEAR_NTFY 13 -+ -+/* (Error Reporting) */ -+#define PPTP_WAN_ERR_NTFY 14 -+ -+/* (PPP Session Control) */ -+#define PPTP_SET_LINK_INFO 15 -+ -+/* PPTP version information: --------------------------------------*/ -+#define PPTP_VERSION_STRING "1.00" -+#define PPTP_VERSION 0x100 -+#define PPTP_FIRMWARE_STRING "0.01" -+#define PPTP_FIRMWARE_VERSION 0x001 -+ -+/* PPTP capabilities: ---------------------------------------------*/ -+ -+/* (Framing capabilities for msg sender) */ -+#define PPTP_FRAME_ASYNC 1 -+#define PPTP_FRAME_SYNC 2 -+#define PPTP_FRAME_ANY 3 -+ -+/* (Bearer capabilities for msg sender) */ -+#define PPTP_BEARER_ANALOG 1 -+#define PPTP_BEARER_DIGITAL 2 -+#define PPTP_BEARER_ANY 3 -+ -+#define PPTP_RESULT_GENERAL_ERROR 2 -+ -+/* (Reasons to close a connection) */ -+#define PPTP_STOP_NONE 1 /* no good reason */ -+#define PPTP_STOP_PROTOCOL 2 /* can't support peer's protocol version */ -+#define PPTP_STOP_LOCAL_SHUTDOWN 3 /* requester is being shut down */ -+ -+/* PPTP datagram structures (all data in network byte order): ----------*/ -+ -+struct pptp_header { -+ u_int16_t length; /* message length in octets, including header */ -+ u_int16_t pptp_type; /* PPTP message type. 1 for control message. */ -+ u_int32_t magic; /* this should be PPTP_MAGIC. */ -+ u_int16_t ctrl_type; /* Control message type (0-15) */ -+ u_int16_t reserved0; /* reserved. MUST BE ZERO. */ -+}; -+ -+struct pptp_start_ctrl_conn { /* for control message types 1 and 2 */ -+ struct pptp_header header; -+ -+ u_int16_t version; /* PPTP protocol version. = PPTP_VERSION */ -+ u_int8_t result_code; /* these two fields should be zero on rqst msg*/ -+ u_int8_t error_code; /* 0 unless result_code==2 (General Error) */ -+ u_int32_t framing_cap; /* Framing capabilities */ -+ u_int32_t bearer_cap; /* Bearer Capabilities */ -+ u_int16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */ -+ u_int16_t firmware_rev; /* Firmware or Software Revision */ -+ u_int8_t hostname[64]; /* Host Name (64 octets, zero terminated) */ -+ u_int8_t vendor[64]; /* Vendor string (64 octets, zero term.) */ -+ /* MS says that end of hostname/vendor fields should be filled with */ -+ /* octets of value 0, but Win95 PPTP driver doesn't do this. */ -+}; -+ -+struct pptp_stop_ctrl_conn { /* for control message types 3 and 4 */ -+ struct pptp_header header; -+ -+ u_int8_t reason_result; /* reason for rqst, result for rply */ -+ u_int8_t error_code; /* MUST be 0, unless rply result==2 (general err)*/ -+ u_int16_t reserved1; /* MUST be 0 */ -+}; -+ -+struct pptp_echo_rqst { /* for control message type 5 */ -+ struct pptp_header header; -+ u_int32_t identifier; /* arbitrary value set by sender which is used */ -+ /* to match up reply and request */ -+}; -+ -+struct pptp_echo_rply { /* for control message type 6 */ -+ struct pptp_header header; -+ u_int32_t identifier; /* should correspond to id of rqst */ -+ u_int8_t result_code; -+ u_int8_t error_code; /* =0, unless result_code==2 (general error) */ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+}; -+ -+struct pptp_out_call_rqst { /* for control message type 7 */ -+ struct pptp_header header; -+ u_int16_t call_id; /* Call ID (unique id used to multiplex data) */ -+ u_int16_t call_sernum; /* Call Serial Number (used for logging) */ -+ u_int32_t bps_min; /* Minimum BPS (lowest acceptable line speed) */ -+ u_int32_t bps_max; /* Maximum BPS (highest acceptable line speed) */ -+ u_int32_t bearer; /* Bearer type */ -+ u_int32_t framing; /* Framing type */ -+ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ -+ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ -+ u_int16_t phone_len; /* Phone Number Length (num. of valid digits) */ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+ u_int8_t phone_num[64]; /* Phone Number (64 octets, null term.) */ -+ u_int8_t subaddress[64]; /* Subaddress (64 octets, null term.) */ -+}; -+ -+struct pptp_out_call_rply { /* for control message type 8 */ -+ struct pptp_header header; -+ u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ -+ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ -+ u_int8_t result_code; /* Result Code (1 is no errors) */ -+ u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ -+ u_int16_t cause_code; /* Cause Code (addt'l failure information) */ -+ u_int32_t speed; /* Connect Speed (in BPS) */ -+ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ -+ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ -+ u_int32_t channel; /* Physical Channel ID (for logging) */ -+}; -+ -+struct pptp_in_call_rqst { /* for control message type 9 */ -+ struct pptp_header header; -+ u_int16_t call_id; /* Call ID (unique id used to multiplex data) */ -+ u_int16_t call_sernum; /* Call Serial Number (used for logging) */ -+ u_int32_t bearer; /* Bearer type */ -+ u_int32_t channel; /* Physical Channel ID (for logging) */ -+ u_int16_t dialed_len; /* Dialed Number Length (# of valid digits) */ -+ u_int16_t dialing_len; /* Dialing Number Length (# of valid digits) */ -+ u_int8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.) */ -+ u_int8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.) */ -+ u_int8_t subaddress[64]; /* Subaddress (64 octets, zero term.) */ -+}; -+ -+struct pptp_in_call_rply { /* for control message type 10 */ -+ struct pptp_header header; -+ u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ -+ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ -+ u_int8_t result_code; /* Result Code (1 is no errors) */ -+ u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ -+ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ -+ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+}; -+ -+struct pptp_in_call_connect { /* for control message type 11 */ -+ struct pptp_header header; -+ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+ u_int32_t speed; /* Connect Speed (in BPS) */ -+ u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ -+ u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ -+ u_int32_t framing; /* Framing type */ -+}; -+ -+struct pptp_call_clear_rqst { /* for control message type 12 */ -+ struct pptp_header header; -+ u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+}; -+ -+struct pptp_call_clear_ntfy { /* for control message type 13 */ -+ struct pptp_header header; -+ u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ -+ u_int8_t result_code; /* Result Code */ -+ u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ -+ u_int16_t cause_code; /* Cause Code (for ISDN, is Q.931 cause code) */ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+ u_int8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */ -+}; -+ -+struct pptp_wan_err_ntfy { /* for control message type 14 */ -+ struct pptp_header header; -+ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+ u_int32_t crc_errors; /* CRC errors */ -+ u_int32_t frame_errors; /* Framing errors */ -+ u_int32_t hard_errors; /* Hardware overruns */ -+ u_int32_t buff_errors; /* Buffer overruns */ -+ u_int32_t time_errors; /* Time-out errors */ -+ u_int32_t align_errors; /* Alignment errors */ -+}; -+ -+struct pptp_set_link_info { /* for control message type 15 */ -+ struct pptp_header header; -+ u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */ -+ u_int16_t reserved1; /* MUST BE ZERO */ -+ u_int32_t send_accm; /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/ -+ u_int32_t recv_accm; /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/ -+}; -+ -+/* helpful #defines: -------------------------------------------- */ -+#define pptp_isvalid_ctrl(header, type, length) \ -+ (!( ( ntoh16(((struct pptp_header *)header)->length) < (length) ) || \ -+ ( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type) ) || \ -+ ( ntoh32(((struct pptp_header *)header)->magic) !=PPTP_MAGIC) || \ -+ ( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \ -+ ( ntoh16(((struct pptp_header *)header)->reserved0) !=0 ) )) -+ -+#define PPTP_HEADER_CTRL(type) \ -+{ hton16(PPTP_CTRL_SIZE(type)), \ -+ hton16(PPTP_MESSAGE_CONTROL), \ -+ hton32(PPTP_MAGIC), \ -+ hton16(type), 0 } -+ -+#define PPTP_CTRL_SIZE(type) ( \ -+(type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn): \ -+(type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn): \ -+(type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn): \ -+(type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn): \ -+(type==PPTP_ECHO_RQST )?sizeof(struct pptp_echo_rqst): \ -+(type==PPTP_ECHO_RPLY )?sizeof(struct pptp_echo_rply): \ -+(type==PPTP_OUT_CALL_RQST )?sizeof(struct pptp_out_call_rqst): \ -+(type==PPTP_OUT_CALL_RPLY )?sizeof(struct pptp_out_call_rply): \ -+(type==PPTP_IN_CALL_RQST )?sizeof(struct pptp_in_call_rqst): \ -+(type==PPTP_IN_CALL_RPLY )?sizeof(struct pptp_in_call_rply): \ -+(type==PPTP_IN_CALL_CONNECT )?sizeof(struct pptp_in_call_connect): \ -+(type==PPTP_CALL_CLEAR_RQST )?sizeof(struct pptp_call_clear_rqst): \ -+(type==PPTP_CALL_CLEAR_NTFY )?sizeof(struct pptp_call_clear_ntfy): \ -+(type==PPTP_WAN_ERR_NTFY )?sizeof(struct pptp_wan_err_ntfy): \ -+(type==PPTP_SET_LINK_INFO )?sizeof(struct pptp_set_link_info): \ -+0) -+#define max(a,b) (((a)>(b))?(a):(b)) -+#define PPTP_CTRL_SIZE_MAX ( \ -+max(sizeof(struct pptp_start_ctrl_conn), \ -+max(sizeof(struct pptp_echo_rqst), \ -+max(sizeof(struct pptp_echo_rply), \ -+max(sizeof(struct pptp_out_call_rqst), \ -+max(sizeof(struct pptp_out_call_rply), \ -+max(sizeof(struct pptp_in_call_rqst), \ -+max(sizeof(struct pptp_in_call_rply), \ -+max(sizeof(struct pptp_in_call_connect), \ -+max(sizeof(struct pptp_call_clear_rqst), \ -+max(sizeof(struct pptp_call_clear_ntfy), \ -+max(sizeof(struct pptp_wan_err_ntfy), \ -+max(sizeof(struct pptp_set_link_info), 0))))))))))))) -+ -+ -+/* gre header structure: -------------------------------------------- */ -+ -+#define PPTP_GRE_PROTO 0x880B -+#define PPTP_GRE_VER 0x1 -+ -+#define PPTP_GRE_FLAG_C 0x80 -+#define PPTP_GRE_FLAG_R 0x40 -+#define PPTP_GRE_FLAG_K 0x20 -+#define PPTP_GRE_FLAG_S 0x10 -+#define PPTP_GRE_FLAG_A 0x80 -+ -+#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C) -+#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R) -+#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K) -+#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S) -+#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A) -+ -+struct pptp_gre_header { -+ u_int8_t flags; /* bitfield */ -+ u_int8_t ver; /* should be PPTP_GRE_VER (enhanced GRE) */ -+ u_int16_t protocol; /* should be PPTP_GRE_PROTO (ppp-encaps) */ -+ u_int16_t payload_len; /* size of ppp payload, not inc. gre header */ -+ u_int16_t call_id; /* peer's call_id for this session */ -+ u_int32_t seq; /* sequence number. Present if S==1 */ -+ u_int32_t ack; /* seq number of highest packet recieved by */ -+ /* sender in this session */ -+}; -+ -+#endif /* INC_PPTP_H */ ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_options.h -@@ -0,0 +1,41 @@ -+/* pptp_options.h ...... various constants used in the PPTP protocol. -+ * #define STANDARD to emulate NT 4.0 exactly. -+ * C. Scott Ananian -+ * -+ * $Id: pptp_options.h,v 1.3 2004/11/09 01:42:32 quozl Exp $ -+ */ -+ -+#ifndef INC_PPTP_OPTIONS_H -+#define INC_PPTP_OPTIONS_H -+ -+#undef PPTP_FIRMWARE_STRING -+#undef PPTP_FIRMWARE_VERSION -+#define PPTP_BUF_MAX 65536 -+#define PPTP_TIMEOUT 60 /* seconds */ -+extern int idle_wait; -+extern int max_echo_wait; -+#define PPTP_CONNECT_SPEED 1000000000 -+#define PPTP_WINDOW 3 -+#define PPTP_DELAY 0 -+#define PPTP_BPS_MIN 2400 -+#define PPTP_BPS_MAX 1000000000 -+ -+#ifndef STANDARD -+#define PPTP_MAX_CHANNELS 65535 -+#define PPTP_FIRMWARE_STRING "0.01" -+#define PPTP_FIRMWARE_VERSION 0x001 -+#define PPTP_HOSTNAME {'l','o','c','a','l',0} -+#define PPTP_VENDOR {'c','a','n','a','n','i','a','n',0} -+#define PPTP_FRAME_CAP PPTP_FRAME_ANY -+#define PPTP_BEARER_CAP PPTP_BEARER_ANY -+#else -+#define PPTP_MAX_CHANNELS 5 -+#define PPTP_FIRMWARE_STRING "0.01" -+#define PPTP_FIRMWARE_VERSION 0 -+#define PPTP_HOSTNAME {'l','o','c','a','l',0} -+#define PPTP_VENDOR {'N','T',0} -+#define PPTP_FRAME_CAP 2 -+#define PPTP_BEARER_CAP 1 -+#endif -+ -+#endif /* INC_PPTP_OPTIONS_H */ ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_quirks.c -@@ -0,0 +1,54 @@ -+/* pptp_quirks.c ...... various options to fix quirks found in buggy adsl modems -+ * mulix -+ * -+ * $Id: pptp_quirks.c,v 1.2 2001/11/23 03:42:51 quozl Exp $ -+ */ -+ -+#include -+#include "orckit_quirks.h" -+#include "pptp_quirks.h" -+ -+static int quirk_index = -1; -+ -+struct pptp_fixup pptp_fixups[] = { -+ {BEZEQ_ISRAEL, ORCKIT, ORCKIT_ATUR3, -+ orckit_atur3_build_hook, -+ orckit_atur3_start_ctrl_conn_hook, -+ orckit_atur3_set_link_hook} -+}; -+ -+static int fixups_sz = sizeof(pptp_fixups)/sizeof(pptp_fixups[0]); -+ -+/* return 0 on success, non 0 otherwise */ -+int set_quirk_index(int index) -+{ -+ if (index >= 0 && index < fixups_sz) { -+ quirk_index = index; -+ return 0; -+ } -+ -+ return -1; -+} -+ -+int get_quirk_index() -+{ -+ return quirk_index; -+} -+ -+/* return the index for this isp in the quirks table, -1 if not found */ -+int find_quirk(const char* isp_name) -+{ -+ int i = 0; -+ if (isp_name) { -+ while (i < fixups_sz && pptp_fixups[i].isp) { -+ if (!strcmp(pptp_fixups[i].isp, isp_name)) { -+ return i; -+ } -+ ++i; -+ } -+ } -+ -+ return -1; -+} -+ -+ ---- /dev/null -+++ b/pppd/plugins/pptp/pptp_quirks.h -@@ -0,0 +1,59 @@ -+/* pptp_quirks.h ...... various options to fix quirks found in buggy adsl modems -+ * mulix -+ * -+ * $Id: pptp_quirks.h,v 1.1 2001/11/20 06:30:10 quozl Exp $ -+ */ -+ -+#ifndef INC_PPTP_QUIRKS_H -+#define INC_PPTP_QUIRKS_H -+ -+/* isp defs - correspond to slots in the fixups table */ -+#define BEZEQ_ISRAEL "BEZEQ_ISRAEL" -+ -+/* vendor defs */ -+ -+#define ORCKIT 1 -+#define ALCATEL 2 -+ -+/* device defs */ -+ -+#define ORCKIT_ATUR2 1 -+#define ORCKIT_ATUR3 2 -+ -+#include "pptp_msg.h" -+#include "pptp_ctrl.h" -+ -+struct pptp_fixup { -+ const char* isp; /* which isp? e.g. Bezeq in Israel */ -+ int vendor; /* which vendor? e.g. Orckit */ -+ int device; /* which device? e.g. Orckit Atur3 */ -+ -+ /* use this hook to build your own out call request packet */ -+ int (*out_call_rqst_hook)(struct pptp_out_call_rqst* packet); -+ -+ /* use this hook to build your own start control connection packet */ -+ /* note that this hook is called from two different places, depending -+ on whether this is a request or reply */ -+ int (*start_ctrl_conn)(struct pptp_start_ctrl_conn* packet); -+ -+ /* use this hook if you need to send a 'set_link' packet once -+ the connection is established */ -+ int (*set_link_hook)(struct pptp_set_link_info* packet, -+ int peer_call_id); -+}; -+ -+extern struct pptp_fixup pptp_fixups[]; -+ -+/* find the index for this isp in the quirks table */ -+/* return the index on success, -1 if not found */ -+int find_quirk(const char* isp_name); -+ -+/* set the global quirk index. return 0 on success, non 0 otherwise */ -+int set_quirk_index(int index); -+ -+/* get the global quirk index. return the index on success, -+ -1 if no quirk is defined */ -+int get_quirk_index(); -+ -+ -+#endif /* INC_PPTP_QUIRKS_H */ ---- /dev/null -+++ b/pppd/plugins/pptp/util.c -@@ -0,0 +1,109 @@ -+/* util.c ....... error message utilities. -+ * C. Scott Ananian -+ * -+ * $Id: util.c,v 1.11 2005/08/22 00:49:48 quozl Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "util.h" -+ -+#define MAKE_STRING(label) \ -+va_list ap; \ -+char buf[256], string[256]; \ -+va_start(ap, format); \ -+vsnprintf(buf, sizeof(buf), format, ap); \ -+snprintf(string, sizeof(string), "%s %s[%s:%s:%d]: %s", \ -+ log_string, label, func, file, line, buf); \ -+va_end(ap) -+ -+/*** connect a file to a file descriptor **************************************/ -+int file2fd(const char *path, const char *mode, int fd) -+{ -+ int ok = 0; -+ FILE *file = NULL; -+ file = fopen(path, mode); -+ if (file != NULL && dup2(fileno(file), fd) != -1) -+ ok = 1; -+ if (file) fclose(file); -+ return ok; -+} -+ -+/* signal to pipe delivery implementation */ -+#include -+#include -+#include -+#include -+ -+/* pipe private to process */ -+static int sigpipe[2]; -+ -+/* create a signal pipe, returns 0 for success, -1 with errno for failure */ -+int sigpipe_create() -+{ -+ int rc; -+ -+ rc = pipe(sigpipe); -+ if (rc < 0) return rc; -+ -+ fcntl(sigpipe[0], F_SETFD, FD_CLOEXEC); -+ fcntl(sigpipe[1], F_SETFD, FD_CLOEXEC); -+ -+#ifdef O_NONBLOCK -+#define FLAG_TO_SET O_NONBLOCK -+#else -+#ifdef SYSV -+#define FLAG_TO_SET O_NDELAY -+#else /* BSD */ -+#define FLAG_TO_SET FNDELAY -+#endif -+#endif -+ -+ rc = fcntl(sigpipe[1], F_GETFL); -+ if (rc != -1) -+ rc = fcntl(sigpipe[1], F_SETFL, rc | FLAG_TO_SET); -+ if (rc < 0) return rc; -+ return 0; -+#undef FLAG_TO_SET -+} -+ -+/* generic handler for signals, writes signal number to pipe */ -+void sigpipe_handler(int signum) -+{ -+ write(sigpipe[1], &signum, sizeof(signum)); -+ signal(signum, sigpipe_handler); -+} -+ -+/* assign a signal number to the pipe */ -+void sigpipe_assign(int signum) -+{ -+ struct sigaction sa; -+ -+ memset(&sa, 0, sizeof(sa)); -+ sa.sa_handler = sigpipe_handler; -+ sigaction(signum, &sa, NULL); -+} -+ -+/* return the signal pipe read file descriptor for select(2) */ -+int sigpipe_fd() -+{ -+ return sigpipe[0]; -+} -+ -+/* read and return the pending signal from the pipe */ -+int sigpipe_read() -+{ -+ int signum; -+ read(sigpipe[0], &signum, sizeof(signum)); -+ return signum; -+} -+ -+void sigpipe_close() -+{ -+ close(sigpipe[0]); -+ close(sigpipe[1]); -+} -+ ---- /dev/null -+++ b/pppd/plugins/pptp/util.h -@@ -0,0 +1,31 @@ -+/* util.h ....... error message utilities. -+ * C. Scott Ananian -+ * -+ * $Id: util.h,v 1.6 2005/03/10 01:18:20 quozl Exp $ -+ */ -+ -+#ifndef INC_UTIL_H -+#define INC_UTIL_H -+ -+int file2fd(const char *path, const char *mode, int fd); -+ -+/* signal to pipe delivery implementation */ -+ -+/* create a signal pipe, returns 0 for success, -1 with errno for failure */ -+int sigpipe_create(); -+ -+/* generic handler for signals, writes signal number to pipe */ -+void sigpipe_handler(int signum); -+ -+/* assign a signal number to the pipe */ -+void sigpipe_assign(int signum); -+ -+/* return the signal pipe read file descriptor for select(2) */ -+int sigpipe_fd(); -+ -+/* read and return the pending signal from the pipe */ -+int sigpipe_read(); -+ -+void sigpipe_close(); -+ -+#endif /* INC_UTIL_H */ ---- /dev/null -+++ b/pppd/plugins/pptp/vector.c -@@ -0,0 +1,209 @@ -+/* vector.c ..... store a vector of PPTP_CALL information and search it -+ * efficiently. -+ * C. Scott Ananian -+ * -+ * $Id: vector.c,v 1.3 2003/06/17 10:12:55 reink Exp $ -+ */ -+ -+#include -+#include -+#include -+#include "pptp_ctrl.h" -+#include "vector.h" -+/* #define VECTOR_DEBUG */ -+#ifndef TRUE -+#define TRUE 1 -+#endif -+#ifndef FALSE -+#define FALSE 0 -+#endif -+ -+struct vector_item { -+ int key; -+ PPTP_CALL *call; -+}; -+ -+struct vector_struct { -+ struct vector_item *item; -+ int size; -+ int alloc; -+#ifdef VECTOR_DEBUG -+ int key_max; -+#endif -+}; -+ -+static struct vector_item *binary_search(VECTOR *v, int key); -+ -+/*** vector_create ************************************************************/ -+VECTOR *vector_create() -+{ -+ const int INITIAL_SIZE = 4; -+ -+ VECTOR *v = malloc(sizeof(*v)); -+ if (v == NULL) return v; -+ -+ v->size = 0; -+ v->alloc = INITIAL_SIZE; -+ v->item = malloc(sizeof(*(v->item)) * (v->alloc)); -+#ifdef VECTOR_DEBUG -+ v->key_max = -1; -+#endif -+ if (v->item == NULL) { free(v); return NULL; } -+ else return v; -+} -+ -+/*** vector_destroy ***********************************************************/ -+void vector_destroy(VECTOR *v) -+{ -+ free(v->item); -+#ifdef VECTOR_DEBUG -+ v->item = NULL; -+#endif -+ free(v); -+} -+ -+/*** vector_size **************************************************************/ -+int vector_size(VECTOR *v) -+{ -+ assert(v != NULL); -+ return v->size; -+} -+ -+/*** vector_insert************************************************************* -+ * nice thing about file descriptors is that we are assured by POSIX -+ * that they are monotonically increasing. -+ */ -+int vector_insert(VECTOR *v, int key, PPTP_CALL * call) -+{ -+ int i; -+ assert(v != NULL && call != NULL); -+ assert(!vector_contains(v, key)); -+#ifdef VECTOR_DEBUG -+ assert(v->key_max < key); -+#endif -+ if (!(v->size < v->alloc)) { -+ void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc); -+ if (tmp != NULL) { -+ v->alloc *= 2; -+ v->item = tmp; -+ } else return FALSE; /* failed to alloc memory. */ -+ } -+ assert(v->size < v->alloc); -+ /* for safety, we make this work in the general case; -+ * but this is optimized for adding call to the end of the vector. -+ */ -+ for(i = v->size - 1; i >= 0; i--) -+ if (v->item[i].key < key) -+ break; -+ /* insert after item i */ -+ memmove(&v->item[i + 2], &v->item[i + 1], -+ (v->size - i - 1) * sizeof(*(v->item))); -+ v->item[i + 1].key = key; -+ v->item[i + 1].call = call; -+ v->size++; -+#ifdef VECTOR_DEBUG -+ if (v->key_max < key) /* ie, always. */ -+ v->key_max = key; -+#endif -+ return TRUE; -+} -+ -+/*** vector_remove ************************************************************/ -+int vector_remove(VECTOR *v, int key) -+{ -+ struct vector_item *tmp; -+ assert(v != NULL); -+ if ((tmp =binary_search(v,key)) == NULL) return FALSE; -+ assert(tmp >= v->item && tmp < v->item + v->size); -+ memmove(tmp, tmp + 1, (v->size - (v->item - tmp) - 1) * sizeof(*(v->item))); -+ v->size--; -+ return TRUE; -+} -+ -+/*** vector_search ************************************************************/ -+int vector_search(VECTOR *v, int key, PPTP_CALL **call) -+{ -+ struct vector_item *tmp; -+ assert(v != NULL); -+ tmp = binary_search(v, key); -+ if (tmp ==NULL) return FALSE; -+ *call = tmp->call; -+ return TRUE; -+} -+ -+/*** vector_contains **********************************************************/ -+int vector_contains(VECTOR *v, int key) -+{ -+ assert(v != NULL); -+ return (binary_search(v, key) != NULL); -+} -+ -+/*** vector_item **************************************************************/ -+static struct vector_item *binary_search(VECTOR *v, int key) -+{ -+ int l,r,x; -+ l = 0; -+ r = v->size - 1; -+ while (r >= l) { -+ x = (l + r)/2; -+ if (key < v->item[x].key) r = x - 1; else l = x + 1; -+ if (key == v->item[x].key) return &(v->item[x]); -+ } -+ return NULL; -+} -+ -+/*** vector_scan *************************************************************** -+ * Hmm. Let's be fancy and use a binary search for the first -+ * unused key, taking advantage of the list is stored sorted; ie -+ * we can look at pointers and keys at two different locations, -+ * and if (ptr1 - ptr2) = (key1 - key2) then all the slots -+ * between ptr1 and ptr2 are filled. Note that ptr1-ptr2 should -+ * never be greater than key1-key2 (no duplicate keys!)... we -+ * check for this. -+ */ -+int vector_scan(VECTOR *v, int lo, int hi, int *key) -+{ -+ int l,r,x; -+ assert(v != NULL); -+ assert(key != NULL); -+ if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; } -+ /* our array bounds */ -+ l = 0; r = v->size - 1; -+ while (r > l) { -+ /* check for a free spot right after l */ -+ if (v->item[l].key + 1 < v->item[l + 1].key) { /* found it! */ -+ *key = v->item[l].key + 1; -+ return TRUE; -+ } -+ /* no dice. Let's see if the free spot is before or after the midpoint */ -+ x = (l + r)/2; -+ /* Okay, we have right (r), left (l) and the probe (x). */ -+ assert(x - l <= v->item[x].key - v->item[l].key); -+ assert(r - x <= v->item[r].key - v->item[x].key); -+ if (x - l < v->item[x].key - v->item[l].key) -+ /* room between l and x */ -+ r = x; -+ else /* no room between l and x */ -+ if (r - x < v->item[r].key - v->item[x].key) -+ /* room between x and r */ -+ l = x; -+ else /* no room between x and r, either */ -+ break; /* game over, man. */ -+ } -+ /* no room found in already allocated space. Check to see if -+ * there's free space above allocated entries. */ -+ if (v->item[v->size - 1].key < hi) { -+ *key = v->item[v->size - 1].key + 1; -+ return TRUE; -+ } -+ /* outta luck */ -+ return FALSE; -+} -+ -+/*** vector_get_Nth ***********************************************************/ -+PPTP_CALL * vector_get_Nth(VECTOR *v, int n) -+{ -+ assert(v != NULL); -+ assert(0 <= n && n < vector_size(v)); -+ return v->item[n].call; -+} ---- /dev/null -+++ b/pppd/plugins/pptp/vector.h -@@ -0,0 +1,31 @@ -+/* vector.h ..... store a vector of PPTP_CALL information and search it -+ * efficiently. -+ * C. Scott Ananian -+ * -+ * $Id: vector.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $ -+ */ -+ -+#ifndef INC_VECTOR_H -+#define INC_VECTOR_H -+ -+#include "pptp_ctrl.h" /* for definition of PPTP_CALL */ -+ -+typedef struct vector_struct VECTOR; -+ -+VECTOR *vector_create(); -+void vector_destroy(VECTOR *v); -+ -+int vector_size(VECTOR *v); -+ -+/* vector_insert and vector_search return TRUE on success, FALSE on failure. */ -+int vector_insert(VECTOR *v, int key, PPTP_CALL * call); -+int vector_remove(VECTOR *v, int key); -+int vector_search(VECTOR *v, int key, PPTP_CALL ** call); -+/* vector_contains returns FALSE if not found, TRUE if found. */ -+int vector_contains(VECTOR *v, int key); -+/* find first unused key. Returns TRUE on success, FALSE if no. */ -+int vector_scan(VECTOR *v, int lo, int hi, int *key); -+/* get a specific PPTP_CALL ... useful only when iterating. */ -+PPTP_CALL * vector_get_Nth(VECTOR *v, int n); -+ -+#endif /* INC_VECTOR_H */