summaryrefslogtreecommitdiff
path: root/accel-pptpd
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2010-08-03 13:28:53 +0400
committerKozlov Dmitry <dima@server>2010-08-03 13:28:53 +0400
commit5a2d6079eba1c7e2a9479cb10d714b5a97bbfe4f (patch)
treee72134e47e1491580af15e3eccbba451f13fdd42 /accel-pptpd
parentba8e1a64e75930a161afac9048e7d03b7f880644 (diff)
downloadaccel-ppp-5a2d6079eba1c7e2a9479cb10d714b5a97bbfe4f.tar.gz
accel-ppp-5a2d6079eba1c7e2a9479cb10d714b5a97bbfe4f.zip
initiating work on accel-pptpd, replacement of modified poptop
Diffstat (limited to 'accel-pptpd')
-rw-r--r--accel-pptpd/CMakeLists.txt16
-rw-r--r--accel-pptpd/ctrl.c380
-rw-r--r--accel-pptpd/events.h18
-rw-r--r--accel-pptpd/if_pppox.h227
-rw-r--r--accel-pptpd/list.h252
-rw-r--r--accel-pptpd/log.c111
-rw-r--r--accel-pptpd/log.h25
-rw-r--r--accel-pptpd/ppp.c174
-rw-r--r--accel-pptpd/ppp.h125
-rw-r--r--accel-pptpd/ppp_fsm.c477
-rw-r--r--accel-pptpd/ppp_fsm.h91
-rw-r--r--accel-pptpd/ppp_lcp.c229
-rw-r--r--accel-pptpd/pptp_prot.h297
-rw-r--r--accel-pptpd/pptpd.c134
-rw-r--r--accel-pptpd/pptpd.h26
-rw-r--r--accel-pptpd/triton/CMakeLists.txt13
-rw-r--r--accel-pptpd/triton/conf_file.c185
-rw-r--r--accel-pptpd/triton/conf_file.h16
-rw-r--r--accel-pptpd/triton/coroutine.c153
-rw-r--r--accel-pptpd/triton/event.c155
-rw-r--r--accel-pptpd/triton/list.h249
-rw-r--r--accel-pptpd/triton/loader.c55
-rw-r--r--accel-pptpd/triton/md.c342
-rw-r--r--accel-pptpd/triton/options.c46
-rw-r--r--accel-pptpd/triton/timer.c244
-rw-r--r--accel-pptpd/triton/triton.h78
-rw-r--r--accel-pptpd/triton/triton_p.h140
27 files changed, 4258 insertions, 0 deletions
diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt
new file mode 100644
index 00000000..5ee16fd2
--- /dev/null
+++ b/accel-pptpd/CMakeLists.txt
@@ -0,0 +1,16 @@
+PROJECT (pptpd)
+cmake_minimum_required(VERSION 2.6)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+
+ADD_SUBDIRECTORY(triton)
+
+ADD_EXECUTABLE(pptpd
+ pptpd.c
+ ctrl.c
+ log.c
+ ppp.c
+ ppp_fsm.c
+ ppp_lcp.c
+)
+TARGET_LINK_LIBRARIES(pptpd pthread triton) \ No newline at end of file
diff --git a/accel-pptpd/ctrl.c b/accel-pptpd/ctrl.c
new file mode 100644
index 00000000..3fbc6e82
--- /dev/null
+++ b/accel-pptpd/ctrl.c
@@ -0,0 +1,380 @@
+/*
+* C Implementation: ctrl
+*
+* Description:
+*
+*
+* Author: <xeb@mail.ru>, (C) 2009
+*
+* Copyright: See COPYING file that comes with this distribution
+*
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "if_pppox.h"
+
+#include "list.h"
+#include "pptp_prot.h"
+#include "triton/triton.h"
+#include "pptpd.h"
+#include "log.h"
+#include "ppp.h"
+
+
+#define TIMEOUT 10000
+
+#define STATE_IDLE 0
+#define STATE_ESTB 1
+#define STATE_FIN 10
+
+struct pptp_conn_t
+{
+ struct triton_md_handler_t *h;
+ int state;
+
+ u_int8_t *in_buf;
+ int in_size;
+ u_int8_t *out_buf;
+ int out_size;
+ int out_pos;
+
+ struct ppp_t *ppp;
+};
+
+static void pptp_read(struct triton_md_handler_t *h);
+static void pptp_write(struct triton_md_handler_t *h);
+static void pptp_timeout(struct triton_md_handler_t *h);
+
+static void ctrl_read(struct triton_md_handler_t *h)
+{
+ struct triton_md_handler_t *hc;
+ struct pptp_conn_t *conn;
+
+ int fd;
+ int n=read(h->fd,&fd,sizeof(fd));
+ if (n!=4)
+ {
+ log_error("too short message from controlling thread\n");
+ return;
+ }
+
+ conn=malloc(sizeof(*conn));
+ memset(conn,0,sizeof(*conn));
+ conn->in_buf=malloc(PPTP_CTRL_SIZE_MAX);
+ conn->out_buf=malloc(PPTP_CTRL_SIZE_MAX);
+
+ hc=malloc(sizeof(*hc));
+ memset(hc,0,sizeof(*hc));
+ hc->fd=fd;
+ hc->twait=TIMEOUT;
+ hc->read=pptp_read;
+ hc->write=pptp_write;
+ hc->timeout=pptp_timeout;
+
+ hc->pd=conn;
+ conn->h=hc;
+
+ conn->ppp=alloc_ppp();
+
+ triton_md_register_handler(hc);
+ triton_md_enable_handler(hc,MD_MODE_READ);
+}
+
+int ctrl_init(struct ctrl_thread_t*ctrl)
+{
+ struct triton_md_handler_t *h=malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->fd=ctrl->pipe_fd[0];
+ h->twait=-1;
+ h->read=ctrl_read;
+ triton_md_register_handler(h);
+ triton_md_enable_handler(h,MD_MODE_READ);
+
+ return 0;
+}
+
+static void disconnect(struct pptp_conn_t *conn)
+{
+ close(conn->h->fd);
+ triton_md_unregister_handler(conn->h);
+ free(conn->h);
+ free(conn);
+}
+
+static int post_msg(struct pptp_conn_t *conn,void *buf,int size)
+{
+ int n;
+ if (conn->out_size)
+ {
+ log_debug("post_msg: buffer is not empty\n");
+ return -1;
+ }
+
+ n=write(conn->h->fd,buf,size);
+ if (n<0)
+ {
+ if (errno==EINTR) n=0;
+ else
+ {
+ log_debug("post_msg: failed to write socket %i\n",errno);
+ return -1;
+ }
+ }
+
+ if (n<size)
+ {
+ memcpy(conn->out_buf,buf+n,size-n);
+ triton_md_enable_handler(conn->h,MD_MODE_WRITE);
+ }
+
+ return 0;
+}
+
+static int send_pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn,int reason,int err_code)
+{
+ struct pptp_stop_ctrl_conn msg={
+ .header=PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST),
+ .reason_result=hton8(reason),
+ .error_code=hton8(err_code),
+ };
+
+ return post_msg(conn,&msg,sizeof(msg));
+}
+
+static int send_pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn,int reason,int err_code)
+{
+ struct pptp_stop_ctrl_conn msg={
+ .header=PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY),
+ .reason_result=hton8(reason),
+ .error_code=hton8(err_code),
+ };
+
+ return post_msg(conn,&msg,sizeof(msg));
+}
+static int pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn)
+{
+ struct pptp_stop_ctrl_conn *msg=(struct pptp_stop_ctrl_conn *)conn->in_buf;
+ log_info("PPTP_STOP_CTRL_CONN_RQST reason=%i error_code=%i\n",msg->reason_result,msg->error_code);
+
+ conn->state=STATE_FIN;
+ conn->h->twait=1000;
+
+ return send_pptp_stop_ctrl_conn_rply(conn,PPTP_CONN_STOP_OK,0);
+}
+
+static int send_pptp_start_ctrl_conn_rply(struct pptp_conn_t *conn,int res_code,int err_code)
+{
+ struct pptp_start_ctrl_conn msg={
+ .header=PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
+ .version=htons(PPTP_VERSION),
+ .result_code=res_code,
+ .error_code=err_code,
+ .framing_cap=htonl(PPTP_FRAME_SYNC),
+ .bearer_cap=htonl(0),
+ .max_channels=htons(1),
+ .firmware_rev=htons(PPTP_FIRMWARE_VERSION),
+ };
+
+ memset(msg.hostname,0,sizeof(msg.hostname));
+ strcpy((char*)msg.hostname,PPTP_HOSTNAME);
+
+ memset(msg.vendor,0,sizeof(msg.vendor));
+ strcpy((char*)msg.vendor,PPTP_VENDOR);
+
+ return post_msg(conn,&msg,sizeof(msg));
+}
+static int pptp_start_ctrl_conn_rqst(struct pptp_conn_t *conn)
+{
+ struct pptp_start_ctrl_conn *msg=(struct pptp_start_ctrl_conn *)conn->in_buf;
+
+ if (conn->state!=STATE_IDLE)
+ {
+ log_info("unexpected PPTP_START_CTRL_CONN_RQST\n");
+ if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_EXISTS,0))
+ return -1;
+ return 0;
+ }
+
+ if (msg->version!=htons(PPTP_VERSION))
+ {
+ log_info("PPTP version mismatch: expecting %x, received %s\n",PPTP_VERSION,msg->version);
+ if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_PROTOCOL,0))
+ return -1;
+ return 0;
+ }
+ if (!(ntohl(msg->framing_cap)&PPTP_FRAME_SYNC))
+ {
+ log_info("connection does not supports sync mode\n");
+ if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_GE,0))
+ return -1;
+ return 0;
+ }
+ if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_SUCCESS,0))
+ return -1;
+
+ conn->state=STATE_ESTB;
+
+ return 0;
+}
+
+static int send_pptp_out_call_rply(struct pptp_conn_t *conn,struct pptp_out_call_rqst *rqst,int call_id,int res_code,int err_code)
+{
+ struct pptp_out_call_rply msg={
+ .header=PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
+ .call_id=htons(call_id),
+ .call_id_peer=rqst->call_id,
+ .result_code=res_code,
+ .error_code=err_code,
+ .cause_code=0,
+ .speed=rqst->bps_max,
+ .recv_size=rqst->recv_size,
+ .delay=0,
+ .channel=0,
+ };
+
+ return post_msg(conn,&msg,sizeof(msg));
+}
+
+static int pptp_out_call_rqst(struct pptp_conn_t *conn)
+{
+ struct pptp_out_call_rqst *msg=(struct pptp_out_call_rqst *)conn->in_buf;
+ struct sockaddr_pppox src_addr,dst_addr;
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+ int pptp_sock;
+
+ if (conn->state!=STATE_ESTB)
+ {
+ log_info("unexpected PPTP_OUT_CALL_RQST\n");
+ if (send_pptp_out_call_rply(conn,msg,0,PPTP_CALL_RES_GE,PPTP_GE_NOCONN))
+ return -1;
+ return 0;
+ }
+
+ src_addr.sa_family=AF_PPPOX;
+ src_addr.sa_protocol=PX_PROTO_PPTP;
+ src_addr.sa_addr.pptp.call_id=0;
+ addrlen=sizeof(addr); getsockname(conn->h->fd,(struct sockaddr*)&addr,&addrlen);
+ src_addr.sa_addr.pptp.sin_addr=addr.sin_addr;
+
+ dst_addr.sa_family=AF_PPPOX;
+ dst_addr.sa_protocol=PX_PROTO_PPTP;
+ dst_addr.sa_addr.pptp.call_id=htons(msg->call_id);
+ addrlen=sizeof(addr); getpeername(conn->h->fd,(struct sockaddr*)&addr,&addrlen);
+ dst_addr.sa_addr.pptp.sin_addr=addr.sin_addr;
+
+ pptp_sock=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP);
+ if (pptp_sock<0)
+ {
+ log_error("failed to create PPTP socket (%s)\n",strerror(errno));
+ return -1;
+ }
+ if (bind(pptp_sock,(struct sockaddr*)&src_addr,sizeof(src_addr)))
+ {
+ log_error("failed to bind PPTP socket (%s)\n",strerror(errno));
+ close(pptp_sock);
+ return -1;
+ }
+ addrlen=sizeof(src_addr);
+ getsockname(pptp_sock,(struct sockaddr*)&src_addr,&addrlen);
+
+ if (connect(pptp_sock,(struct sockaddr*)&dst_addr,sizeof(dst_addr)))
+ {
+ log_error("failed to connect PPTP socket (%s)\n",strerror(errno));
+ close(pptp_sock);
+ return -1;
+ }
+
+ if (send_pptp_out_call_rply(conn,msg,src_addr.sa_addr.pptp.call_id,PPTP_CALL_RES_OK,0))
+ return -1;
+
+ conn->ppp->fd=pptp_sock;
+ conn->ppp->chan_name=strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr));
+ establish_ppp(conn->ppp);
+
+ return 0;
+}
+
+static int process_packet(struct pptp_conn_t *conn)
+{
+ struct pptp_header *hdr=(struct pptp_header *)conn->in_buf;
+ switch(ntohs(hdr->ctrl_type))
+ {
+ case PPTP_START_CTRL_CONN_RQST:
+ return pptp_start_ctrl_conn_rqst(conn);
+ case PPTP_STOP_CTRL_CONN_RQST:
+ return pptp_stop_ctrl_conn_rqst(conn);
+ case PPTP_OUT_CALL_RQST:
+ return pptp_out_call_rqst(conn);
+ }
+ return 0;
+}
+
+static void pptp_read(struct triton_md_handler_t *h)
+{
+ struct pptp_conn_t *conn=(struct pptp_conn_t *)h->pd;
+ struct pptp_header *hdr=(struct pptp_header *)conn->in_buf;
+ int n;
+
+ n=read(h->fd,conn->in_buf,PPTP_CTRL_SIZE_MAX-conn->in_size);
+ if (n<=0)
+ {
+ if (errno==EINTR) return;
+ disconnect(conn);
+ return;
+ }
+ conn->in_size+=n;
+ if (conn->in_size>=sizeof(*hdr))
+ {
+ if (hdr->magic!=htonl(PPTP_MAGIC)) goto drop;
+ if (ntohs(hdr->length)>=PPTP_CTRL_SIZE_MAX) goto drop;
+ if (ntohs(hdr->length)>conn->in_size) goto drop;
+ if (ntohs(hdr->length)==conn->in_size)
+ {
+ if (ntohs(hdr->length)!=PPTP_CTRL_SIZE(ntohs(hdr->ctrl_type))) goto drop;
+ if (process_packet(conn)) goto drop;
+ conn->in_size=0;
+ }
+ }
+ h->twait=TIMEOUT;
+ return;
+drop:
+ disconnect(conn);
+ return;
+}
+static void pptp_write(struct triton_md_handler_t *h)
+{
+ struct pptp_conn_t *conn=(struct pptp_conn_t *)h->pd;
+ int n=write(h->fd,conn->out_buf+conn->out_pos,conn->out_size-conn->out_pos);
+
+ if (n<0)
+ {
+ if (errno==EINTR) n=0;
+ else
+ {
+ log_debug("post_msg: failed to write socket %i\n",errno);
+ disconnect(conn);
+ return;
+ }
+ }
+
+ conn->out_pos+=n;
+ if (conn->out_pos==conn->out_size)
+ {
+ conn->out_pos=0;
+ conn->out_size=0;
+ triton_md_disable_handler(h,MD_MODE_WRITE);
+ }
+ h->twait=TIMEOUT;
+}
+static void pptp_timeout(struct triton_md_handler_t *h)
+{
+}
diff --git a/accel-pptpd/events.h b/accel-pptpd/events.h
new file mode 100644
index 00000000..15704a7a
--- /dev/null
+++ b/accel-pptpd/events.h
@@ -0,0 +1,18 @@
+//
+// C++ Interface: events
+//
+// Description:
+//
+//
+// Author: <xeb@mail.ru>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef EVENTS_H
+#define EVENTS_H
+
+#define EV_PPP_PACKET 1
+
+#endif
diff --git a/accel-pptpd/if_pppox.h b/accel-pptpd/if_pppox.h
new file mode 100644
index 00000000..da327a1c
--- /dev/null
+++ b/accel-pptpd/if_pppox.h
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * Linux PPP over X - Generic PPP transport layer sockets
+ * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516)
+ *
+ * This file supplies definitions required by the PPP over Ethernet driver
+ * (pppox.c). All version information wrt this file is located in pppox.c
+ *
+ * License:
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_IF_PPPOX_H
+#define __LINUX_IF_PPPOX_H
+
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/ppp_channel.h>
+#endif /* __KERNEL__ */
+
+/* For user-space programs to pick up these definitions
+ * which they wouldn't get otherwise without defining __KERNEL__
+ */
+#ifndef AF_PPPOX
+#define AF_PPPOX 24
+#define PF_PPPOX AF_PPPOX
+#endif /* !(AF_PPPOX) */
+
+struct pptp_addr{
+ __u16 call_id;
+ struct in_addr sin_addr;
+};
+/************************************************************************
+ * Protocols supported by AF_PPPOX
+ */
+#define PX_PROTO_OE 0 /* Currently just PPPoE */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
+#define PX_PROTO_PPTP 1
+#define PX_MAX_PROTO 2
+#else
+#define PX_PROTO_PPTP 2
+#define PX_MAX_PROTO 3
+#endif
+
+struct sockaddr_pppox {
+ sa_family_t sa_family; /* address family, AF_PPPOX */
+ unsigned int sa_protocol; /* protocol identifier */
+ union{
+ struct pptp_addr pptp;
+ }sa_addr;
+}__attribute__ ((packed));
+
+
+/*********************************************************************
+ *
+ * ioctl interface for defining forwarding of connections
+ *
+ ********************************************************************/
+
+#define PPPOEIOCSFWD _IOW(0xB1 ,0, size_t)
+#define PPPOEIOCDFWD _IO(0xB1 ,1)
+/*#define PPPOEIOCGFWD _IOWR(0xB1,2, size_t)*/
+
+/* Codes to identify message types */
+#define PADI_CODE 0x09
+#define PADO_CODE 0x07
+#define PADR_CODE 0x19
+#define PADS_CODE 0x65
+#define PADT_CODE 0xa7
+struct pppoe_tag {
+ __u16 tag_type;
+ __u16 tag_len;
+ char tag_data[0];
+} __attribute ((packed));
+
+/* Tag identifiers */
+#define PTT_EOL __constant_htons(0x0000)
+#define PTT_SRV_NAME __constant_htons(0x0101)
+#define PTT_AC_NAME __constant_htons(0x0102)
+#define PTT_HOST_UNIQ __constant_htons(0x0103)
+#define PTT_AC_COOKIE __constant_htons(0x0104)
+#define PTT_VENDOR __constant_htons(0x0105)
+#define PTT_RELAY_SID __constant_htons(0x0110)
+#define PTT_SRV_ERR __constant_htons(0x0201)
+#define PTT_SYS_ERR __constant_htons(0x0202)
+#define PTT_GEN_ERR __constant_htons(0x0203)
+
+struct pppoe_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 ver : 4;
+ __u8 type : 4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 type : 4;
+ __u8 ver : 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 code;
+ __u16 sid;
+ __u16 length;
+ struct pppoe_tag tag[0];
+} __attribute__ ((packed));
+
+
+/* Socket options */
+#define PPTP_SO_TIMEOUT 1
+
+
+#ifdef __KERNEL__
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
+struct pppoe_opt {
+ struct net_device *dev; /* device associated with socket*/
+ struct pppoe_addr pa; /* what this socket is bound to*/
+ struct sockaddr_pppox relay; /* what socket data will be
+ relayed to (PPPoE relaying) */
+};
+#endif
+struct pptp_opt {
+ struct pptp_addr src_addr;
+ struct pptp_addr dst_addr;
+ int timeout;
+ __u32 ack_sent, ack_recv;
+ __u32 seq_sent, seq_recv;
+ int ppp_flags;
+ int flags;
+ struct sk_buff_head skb_buf;
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ struct tq_struct buf_work; //check bufferd packets work
+ struct timer_list buf_timer;
+ #else
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ struct delayed_work buf_work; //check bufferd packets work
+ #else
+ struct work_struct buf_work; //check bufferd packets work
+ #endif
+ #endif
+ struct gre_statistics *stat;
+ spinlock_t xmit_lock;
+ spinlock_t rcv_lock;
+};
+#define PPTP_FLAG_PAUSE 0
+#define PPTP_FLAG_PROC 1
+
+#include <net/sock.h>
+
+struct pppox_sock {
+ /* struct sock must be the first member of pppox_sock */
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ struct ppp_channel chan;
+ struct sock *sk;
+ #else
+ struct sock sk;
+ struct ppp_channel chan;
+ #endif
+ struct pppox_sock *next; /* for hash table */
+ union {
+ struct pppoe_opt pppoe;
+ struct pptp_opt pptp;
+ } proto;
+ unsigned short num;
+};
+#define pppoe_dev proto.pppoe.dev
+#define pppoe_pa proto.pppoe.pa
+#define pppoe_relay proto.pppoe.relay
+
+static inline struct pppox_sock *pppox_sk(struct sock *sk)
+{
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ return (struct pppox_sock *)sk->protinfo.pppox;
+ #else
+ return (struct pppox_sock *)sk;
+ #endif
+}
+
+static inline struct sock *sk_pppox(struct pppox_sock *po)
+{
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ return po->sk;
+ #else
+ return (struct sock *)po;
+ #endif
+}
+
+struct module;
+
+struct pppox_proto {
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ int (*create)(struct socket *sock);
+ #else
+ int (*create)(struct net *net, struct socket *sock);
+ #endif
+ int (*ioctl)(struct socket *sock, unsigned int cmd,
+ unsigned long arg);
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+ struct module *owner;
+ #endif
+};
+
+extern int register_pppox_proto(int proto_num, struct pppox_proto *pp);
+extern void unregister_pppox_proto(int proto_num);
+extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
+extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+
+/* PPPoX socket states */
+enum {
+ PPPOX_NONE = 0, /* initial state */
+ PPPOX_CONNECTED = 1, /* connection established ==TCP_ESTABLISHED */
+ PPPOX_BOUND = 2, /* bound to ppp device */
+ PPPOX_RELAY = 4, /* forwarding is enabled */
+ PPPOX_ZOMBIE = 8, /* dead, but still bound to ppp device */
+ PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* !(__LINUX_IF_PPPOX_H) */
diff --git a/accel-pptpd/list.h b/accel-pptpd/list.h
new file mode 100644
index 00000000..49045b7e
--- /dev/null
+++ b/accel-pptpd/list.h
@@ -0,0 +1,252 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE)
+
+//#include <linux/prefetch.h>
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+void static inline prefetch(void* p){}
+
+typedef struct list_head {
+ struct list_head *next, *prev;
+} list_t;
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a _new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *_new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = _new;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+}
+
+/**
+ * list_add - add a _new entry
+ * @_new: _new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a _new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *_new, struct list_head *head)
+{
+ __list_add(_new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a _new entry
+ * @_new: _new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a _new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+ __list_add(_new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = NULL;//(void *) 0;
+ entry->prev = NULL;//(void *) 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the _new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the _new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+//#endif /* __KERNEL__ || _LVM_H_INCLUDE */
+
+#endif
diff --git a/accel-pptpd/log.c b/accel-pptpd/log.c
new file mode 100644
index 00000000..454e9975
--- /dev/null
+++ b/accel-pptpd/log.c
@@ -0,0 +1,111 @@
+/*
+* C Implementation: log
+*
+* Description:
+*
+*
+* Author: <xeb@mail.ru>, (C) 2009
+*
+* Copyright: See COPYING file that comes with this distribution
+*
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include "log.h"
+
+#define RED_COLOR "\033[1;31m"
+#define GREEN_COLOR "\033[1;32m"
+#define YELLOW_COLOR "\033[1;33m"
+#define BLUE_COLOR "\033[1;34m"
+#define NORMAL_COLOR "\033[0;39m"
+
+#define LOG_ERROR 0
+#define LOG_WARN 1
+#define LOG_INFO 2
+#define LOG_DEBUG 3
+
+static FILE *log_file=NULL;
+static int log_level=1;
+static int log_color=1;
+static const char* level_name[]={"error","warning","info","debug"};
+static const char* level_color[]={RED_COLOR,YELLOW_COLOR,GREEN_COLOR,BLUE_COLOR};
+static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
+
+static int msg_completed=1;
+
+static void do_log(int level,const char *fmt,va_list ap)
+{
+ struct timeval tv;
+
+ pthread_mutex_lock(&lock);
+ gettimeofday(&tv,NULL);
+ if (log_color) fprintf(log_file,"[%s%li.%03li] [%s]%s ",level_color[level],tv.tv_sec,tv.tv_usec/1000,NORMAL_COLOR,level_name[level]);
+ else fprintf(log_file,"[%li.%03li] [%s] ",tv.tv_sec,tv.tv_usec/1000,level_name[level]);
+
+ vfprintf(log_file,fmt,ap);
+
+ msg_completed=fmt[strlen(fmt)-1]=='\n';
+ if (msg_completed) pthread_mutex_unlock(&lock);
+}
+void log_error(const char *fmt,...)
+{
+ if (log_level>=1)
+ {
+ va_list ap;
+ va_start(ap,fmt);
+ do_log(LOG_ERROR,fmt,ap);
+ }
+}
+void log_warn(const char *fmt,...)
+{
+ if (log_level>=2)
+ {
+ va_list ap;
+ va_start(ap,fmt);
+ do_log(LOG_WARN,fmt,ap);
+ }
+}
+void log_info(const char *fmt,...)
+{
+ if (log_level>=3)
+ {
+ va_list ap;
+ va_start(ap,fmt);
+ do_log(LOG_INFO,fmt,ap);
+ }
+}
+void log_debug(const char *fmt,...)
+{
+ if (log_level>=4)
+ {
+ va_list ap;
+ va_start(ap,fmt);
+ do_log(LOG_DEBUG,fmt,ap);
+ }
+}
+
+void log_msg(const char *fmt,...)
+{
+ va_list ap;
+ if (msg_completed) return;
+ va_start(ap,fmt);
+ vfprintf(log_file,fmt,ap);
+ msg_completed=fmt[strlen(fmt)-1]=='\n';
+ if (msg_completed) pthread_mutex_unlock(&lock);
+}
+
+void log_init(FILE *f,int level,int color)
+{
+ log_file=f;
+ log_level=level;
+ log_color=color;
+}
diff --git a/accel-pptpd/log.h b/accel-pptpd/log.h
new file mode 100644
index 00000000..25f9f976
--- /dev/null
+++ b/accel-pptpd/log.h
@@ -0,0 +1,25 @@
+//
+// C++ Interface: log
+//
+// Description:
+//
+//
+// Author: <xeb@mail.ru>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <stdio.h>
+
+void log_init(FILE *f,int level,int color);
+void log_error(const char *fmt,...);
+void log_warn(const char *fmt,...);
+void log_info(const char *fmt,...);
+void log_debug(const char *fmt,...);
+void log_msg(const char *fmt,...);
+
+#endif
diff --git a/accel-pptpd/ppp.c b/accel-pptpd/ppp.c
new file mode 100644
index 00000000..c24987fa
--- /dev/null
+++ b/accel-pptpd/ppp.c
@@ -0,0 +1,174 @@
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+
+#include "triton/triton.h"
+
+#include "ppp.h"
+#include "ppp_fsm.h"
+#include "log.h"
+#include "events.h"
+
+static void ppp_read(struct triton_md_handler_t*);
+static void ppp_write(struct triton_md_handler_t*);
+static void ppp_timeout(struct triton_md_handler_t*);
+
+struct ppp_t *alloc_ppp(void)
+{
+ struct ppp_t *ppp=malloc(sizeof(*ppp));
+ memset(ppp,0,sizeof(*ppp));
+ ppp->out_buf=malloc(PPP_MTU+PPP_HDRLEN);
+ ppp->in_buf=malloc(PPP_MRU+PPP_HDRLEN);
+ ppp->mtu=PPP_MTU;
+ ppp->mru=PPP_MRU;
+ return ppp;
+}
+
+int establish_ppp(struct ppp_t *ppp)
+{
+ /* Open an instance of /dev/ppp and connect the channel to it */
+ if (ioctl(ppp->fd, PPPIOCGCHAN, &ppp->chan_idx)==-1)
+ {
+ log_error("Couldn't get channel number\n");
+ return -1;
+ }
+
+ ppp->chan_fd=open("/dev/ppp", O_RDWR);
+ if (ppp->chan_fd<0)
+ {
+ log_error("Couldn't reopen /dev/ppp\n");
+ return -1;
+ }
+
+ if (ioctl(ppp->chan_fd, PPPIOCATTCHAN, &ppp->chan_idx)<0)
+ {
+ log_error("Couldn't attach to channel %d\n", ppp->chan_idx);
+ goto exit_close_chan;
+ }
+
+ ppp->unit_fd=open("/dev/ppp", O_RDWR);
+ if (ppp->unit_fd<0)
+ {
+ log_error("Couldn't reopen /dev/ppp\n");
+ goto exit_close_chan;
+ }
+
+ ppp->unit_idx=-1;
+ if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx)<0)
+ {
+ log_error("Couldn't create new ppp unit\n");
+ goto exit_clodse_unit;
+ }
+
+ if (ioctl(ppp->chan_fd, PPPIOCCONNECT, &ppp->unit_idx)<0)
+ {
+ log_error("Couldn't attach to PPP unit %d\n", ppp->unit_idx);
+ goto exit_clodse_unit;
+ }
+
+ log_info("connect: ppp%i <--> pptp(%s)\n",ppp->unit_idx,ppp->chan_name);
+
+ ppp->h=malloc(sizeof(*ppp->h));
+ memset(ppp->h,0,sizeof(*ppp->h));
+ ppp->h->pd=ppp;
+ ppp->h->fd=ppp->chan_fd;
+ ppp->h->read=ppp_read;
+ ppp->h->write=ppp_write;
+ ppp->h->timeout=ppp_timeout;
+ ppp->h->twait=-1;
+ triton_md_register_handler(ppp->h);
+ triton_md_enable_handler(ppp->h,MD_MODE_READ);
+ INIT_LIST_HEAD(&ppp->layers);
+
+ ppp->lcp_layer=ppp_lcp_init(ppp);
+ ppp_fsm_open(ppp->lcp_layer);
+ ppp_fsm_lower_up(ppp->lcp_layer);
+
+ return 0;
+
+exit_clodse_unit:
+ close(ppp->unit_fd);
+exit_close_chan:
+ close(ppp->chan_fd);
+ return -1;
+}
+
+int ppp_send(struct ppp_t *ppp, void *data, int size)
+{
+ int n;
+
+ if (ppp->out_buf_size) return -1;
+ if (size>PPP_MTU+PPP_HDRLEN) return -1;
+
+ n=write(ppp->unit_fd,data,size);
+ if (n>=0)
+ {
+ if (n!=ppp->out_buf_size-ppp->out_buf_pos)
+ {
+ ppp->out_buf_pos+=n;
+ triton_md_enable_handler(ppp->h,MD_MODE_WRITE);
+ }
+ }
+ return n;
+}
+
+static void ppp_read(struct triton_md_handler_t*h)
+{
+ struct ppp_t *ppp=(struct ppp_t *)h->pd;
+ struct ppp_hdr_t *hdr=(struct ppp_hdr_t *)(ppp->in_buf+2);
+ u_int16_t proto;
+
+ ppp->in_buf_size=read(h->fd,ppp->in_buf,PPP_MRU+PPP_HDRLEN);
+ //if (ppp->in_buf_size==0)
+ if (ppp->in_buf_size<PPP_HDRLEN+2 || ppp->in_buf_size<ntohs(hdr->len)+2)
+ {
+ log_warn("discarding short packet\n");
+ return;
+ }
+
+ proto=ntohs(*(u_int16_t*)ppp->in_buf);
+ if (proto==PPP_LCP) ppp->lcp_layer->recv(ppp->lcp_layer,hdr);
+ else if (ppp->lcp_layer->fsm_state!=FSM_Opened)
+ {
+ log_warn("discarding non-LCP packet when LCP is not opened\n");
+ return;
+ }else
+ {
+ struct ppp_layer_t *l=NULL;
+ list_for_each_entry(l,&ppp->layers,entry)
+ {
+ if (l->proto==proto) l->recv(l,hdr);
+ }
+
+ if (!l)
+ {
+ log_warn("discarding unknown packet %x\n",proto);
+ }
+ }
+}
+static void ppp_write(struct triton_md_handler_t*h)
+{
+ struct ppp_t *ppp=(struct ppp_t *)h->pd;
+
+ int n=write(ppp->unit_fd,ppp->out_buf+ppp->out_buf_pos,ppp->out_buf_size-ppp->out_buf_pos);
+ if (n>=0)
+ {
+ ppp->out_buf_pos+=n;
+ if (ppp->out_buf_pos==ppp->out_buf_size)
+ {
+ triton_md_disable_handler(ppp->h,MD_MODE_WRITE);
+ ppp->out_buf_pos=0;
+ ppp->out_buf_size=0;
+ }
+ }
+}
+static void ppp_timeout(struct triton_md_handler_t*h)
+{
+
+}
diff --git a/accel-pptpd/ppp.h b/accel-pptpd/ppp.h
new file mode 100644
index 00000000..e640229f
--- /dev/null
+++ b/accel-pptpd/ppp.h
@@ -0,0 +1,125 @@
+#ifndef PPP_H
+#define PPP_H
+
+#include <sys/types.h>
+#include "ppp_fsm.h"
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define PPP_HEADERLEN 4
+#define PPP_MTU 1500
+
+/*
+ * Timeouts.
+ */
+#define DEFTIMEOUT 3 /* Timeout time in seconds */
+#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
+#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP 0x21 /* Internet Protocol */
+#define PPP_AT 0x29 /* AppleTalk Protocol */
+#define PPP_IPX 0x2b /* IPX protocol */
+#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
+#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
+#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */
+#define PPP_COMP 0xfd /* compressed packet */
+#define PPP_IPCP 0x8021 /* IP Control Protocol */
+#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
+#define PPP_IPXCP 0x802b /* IPX Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
+#define PPP_CCP 0x80fd /* Compression Control Protocol */
+#define PPP_ECP 0x8053 /* Encryption Control Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_PAP 0xc023 /* Password Authentication Protocol */
+#define PPP_LQR 0xc025 /* Link Quality Report protocol */
+#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */
+
+
+struct ppp_t
+{
+ struct triton_md_handler_t *h;
+ int fd;
+ int chan_fd;
+ int unit_fd;
+
+ int chan_idx;
+ int unit_idx;
+
+ char *chan_name;
+
+ int mtu,mru;
+ int require_mppe:1;
+ int require_pap:1;
+ int require_chap:1;
+ int require_mschap:1;
+ int require_mschap_v2:1;
+
+ int allow_mppe:1;
+ int allow_pap:1;
+ int allow_chap:1;
+ int allow_mschap:1;
+ int allow_mschap_v2:1;
+
+ int log:1;
+
+ void *out_buf;
+ int out_buf_size;
+ int out_buf_pos;
+
+ void *in_buf;
+ int in_buf_size;
+
+ struct ppp_layer_t *lcp_layer;
+ struct list_head layers;
+};
+
+struct ppp_fsm_handler_t
+{
+ void (*reset_conf)(struct ppp_t *ppp); /* Reset our Configuration Information */
+ int (*conf_length)(struct ppp_t *ppp); /* Length of our Configuration Information */
+ void (*add_conf)(struct ppp_t *ppp, unsigned char *, int *); /* Add our Configuration Information */
+ int (*ack_conf)(struct ppp_t *ppp, unsigned char *,int); /* ACK our Configuration Information */
+ int (*nak_conf)(struct ppp_t *ppp, unsigned char *,int,int); /* NAK our Configuration Information */
+ int (*rej_conf)(struct ppp_t *ppp, unsigned char *,int); /* Reject our Configuration Information */
+ int (*req_conf)(struct ppp_t *ppp, unsigned char *,int *,int); /* Request peer's Configuration Information */
+ void (*opened)(struct ppp_t *ppp); /* Called when fsm reaches OPENED state */
+ void (*down)(struct ppp_t *ppp); /* Called when fsm leaves OPENED state */
+ void (*starting)(struct ppp_t *ppp); /* Called when we want the lower layer */
+ void (*finished)(struct ppp_t *ppp); /* Called when we don't want the lower layer */
+ void (*protreject)(struct ppp_t *ppp,int); /* Called when Protocol-Reject received */
+ void (*retransmit)(struct ppp_t *ppp); /* Retransmission is necessary */
+ int (*extcode)(struct ppp_t *ppp, int, int, unsigned char *, int); /* Called when unknown code received */
+ char *proto_name; /* String name for protocol (for messages) */
+};
+
+struct ppp_hdr_t
+{
+ u_int8_t code;
+ u_int8_t id;
+ u_int16_t len;
+ u_int8_t data[100];
+}__attribute__((packed));
+
+struct ppp_opt_t
+{
+ u_int8_t type;
+ u_int16_t len;
+ u_int8_t data[100];
+}__attribute__((packed));
+
+struct ppp_t *alloc_ppp(void);
+int establish_ppp(struct ppp_t *ppp);
+int ppp_send(struct ppp_t *ppp, void *data, int size);
+
+void ppp_init(void);
+
+struct ppp_layer_t* ppp_lcp_init(struct ppp_t *ppp);
+
+#endif
diff --git a/accel-pptpd/ppp_fsm.c b/accel-pptpd/ppp_fsm.c
new file mode 100644
index 00000000..f966cd07
--- /dev/null
+++ b/accel-pptpd/ppp_fsm.c
@@ -0,0 +1,477 @@
+/*
+* C Implementation: ppp_fsm
+*
+* Description:
+*
+*
+* Author: <xeb@mail.ru>, (C) 2009
+*
+* Copyright: See COPYING file that comes with this distribution
+*
+*/
+
+#include "triton/triton.h"
+#include "ppp.h"
+#include "ppp_fsm.h"
+
+void send_term_req(struct ppp_layer_t *layer);
+void send_term_ack(struct ppp_layer_t *layer);
+void send_echo_reply(struct ppp_layer_t *layer);
+
+static void init_req_counter(struct ppp_layer_t *layer,int timeout);
+static void zero_req_counter(struct ppp_layer_t *layer);
+static int restart_timer_func(struct triton_timer_t*t);
+
+void ppp_fsm_init(struct ppp_layer_t *layer)
+{
+ layer->fsm_state=FSM_Initial;
+ layer->restart_timer.active=0;
+ layer->restart_timer.pd=layer;
+ layer->restart_timer.expire=restart_timer_func;
+ layer->restart_timer.period=3000;
+ layer->restart_counter=0;
+ layer->max_terminate=2;
+ layer->max_configure=10;
+ layer->max_failure=5;
+ layer->seq=0;
+}
+
+void ppp_fsm_lower_up(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Initial:
+ layer->fsm_state=FSM_Closed;
+ break;
+ case FSM_Starting:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_lower_down(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closed:
+ case FSM_Closing:
+ layer->fsm_state=FSM_Initial;
+ break;
+ case FSM_Stopped:
+ if (layer->layer_started) layer->layer_started(layer);
+ layer->fsm_state=FSM_Starting;
+ break;
+ case FSM_Stopping:
+ case FSM_Req_Sent:
+ case FSM_Ack_Rcvd:
+ case FSM_Ack_Sent:
+ layer->fsm_state=FSM_Starting;
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ layer->fsm_state=FSM_Starting;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_open(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Initial:
+ if (layer->layer_started) layer->layer_started(layer);
+ layer->fsm_state=FSM_Starting;
+ break;
+ case FSM_Starting:
+ break;
+ case FSM_Closed:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ case FSM_Closing:
+ case FSM_Stopping:
+ layer->fsm_state=FSM_Stopping;
+ case FSM_Stopped:
+ case FSM_Opened:
+ if (layer->opt_restart)
+ {
+ ppp_fsm_lower_down(layer);
+ ppp_fsm_lower_up(layer);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_close(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Starting:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Initial;
+ break;
+ case FSM_Stopped:
+ layer->fsm_state=FSM_Closed;
+ break;
+ case FSM_Stopping:
+ layer->fsm_state=FSM_Closing;
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ case FSM_Req_Sent:
+ case FSM_Ack_Rcvd:
+ case FSM_Ack_Sent:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_terminate);
+ send_term_req(layer);
+ layer->fsm_state=FSM_Closing;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_timeout0(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closing:
+ case FSM_Stopping:
+ send_term_req(layer);
+ break;
+ case FSM_Ack_Rcvd:
+ layer->fsm_state=FSM_Req_Sent;
+ case FSM_Req_Sent:
+ case FSM_Ack_Sent:
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_timeout1(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closing:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Closed;
+ break;
+ case FSM_Stopping:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Stopped;
+ break;
+ case FSM_Ack_Rcvd:
+ case FSM_Req_Sent:
+ case FSM_Ack_Sent:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Stopped;
+ layer->opt_passive=1;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_conf_req_good(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closed:
+ send_term_ack(layer);
+ break;
+ case FSM_Stopped:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ case FSM_Req_Sent:
+ case FSM_Ack_Sent:
+ if (layer->send_conf_ack) layer->send_conf_ack(layer);
+ layer->fsm_state=FSM_Ack_Sent;
+ break;
+ case FSM_Ack_Rcvd:
+ if (layer->send_conf_ack) layer->send_conf_ack(layer);
+ //tlu
+ if (layer->layer_up) layer->layer_up(layer);
+ layer->fsm_state=FSM_Opened;
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ if (layer->send_conf_ack) layer->send_conf_ack(layer);
+ layer->fsm_state=FSM_Ack_Sent;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_conf_req_bad(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closed:
+ send_term_ack(layer);
+ break;
+ case FSM_Stopped:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ case FSM_Ack_Sent:
+ if (layer->send_conf_rej) layer->send_conf_rej(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ case FSM_Req_Sent:
+ case FSM_Ack_Rcvd:
+ if (layer->send_conf_rej) layer->send_conf_rej(layer);
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ if (layer->send_conf_rej) layer->send_conf_rej(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_conf_ack(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closed:
+ case FSM_Stopped:
+ send_term_ack(layer);
+ break;
+ case FSM_Req_Sent:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ layer->fsm_state=FSM_Ack_Rcvd;
+ break;
+ case FSM_Ack_Rcvd:
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ case FSM_Ack_Sent:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ //tlu
+ if (layer->layer_up) layer->layer_up(layer);
+ layer->fsm_state=FSM_Opened;
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_conf_rej(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closed:
+ case FSM_Stopped:
+ send_term_ack(layer);
+ break;
+ case FSM_Req_Sent:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_failure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ break;
+ case FSM_Ack_Rcvd:
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ case FSM_Ack_Sent:
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_term_req(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ send_term_req(layer);
+ //if (layer->zero_req_cnt) layer->zero_req_cnt(layer);
+ zero_req_counter(layer);
+ layer->fsm_state=FSM_Stopping;
+ break;
+ case FSM_Req_Sent:
+ case FSM_Ack_Rcvd:
+ case FSM_Ack_Sent:
+ send_term_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ default:
+ send_term_req(layer);
+ break;
+ }
+}
+
+void ppp_fsm_recv_term_ack(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Closing:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Closed;
+ break;
+ case FSM_Stopping:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Stopped;
+ break;
+ case FSM_Ack_Rcvd:
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_unk(struct ppp_layer_t *layer)
+{
+ if (layer->send_conf_rej) layer->send_conf_rej(layer);
+}
+
+void ppp_fsm_recv_code_rej_perm(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Ack_Rcvd:
+ layer->fsm_state=FSM_Req_Sent;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_code_rej_bad(struct ppp_layer_t *layer)
+{
+ switch(layer->fsm_state)
+ {
+ case FSM_Opened:
+ if (layer->layer_down) layer->layer_down(layer);
+ //if (layer->init_req_cnt) layer->init_req_cnt(layer);
+ init_req_counter(layer,layer->max_configure);
+ if (layer->send_conf_req) layer->send_conf_req(layer);
+ layer->fsm_state=FSM_Stopping;
+ break;
+ case FSM_Closing:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Closed;
+ break;
+ case FSM_Stopping:
+ case FSM_Req_Sent:
+ case FSM_Ack_Rcvd:
+ case FSM_Ack_Sent:
+ if (layer->layer_finished) layer->layer_finished(layer);
+ layer->fsm_state=FSM_Stopped;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppp_fsm_recv_echo(struct ppp_layer_t *layer)
+{
+ if (layer->fsm_state==FSM_Opened)
+ send_echo_reply(layer);
+}
+
+void send_term_req(struct ppp_layer_t *layer)
+{
+ struct ppp_hdr_t hdr={
+ .code=TERMREQ,
+ .id=++layer->seq,
+ .len=4,
+ };
+
+ ppp_send(layer->ppp,&hdr,hdr.len);
+}
+void send_term_ack(struct ppp_layer_t *layer)
+{
+ struct ppp_hdr_t hdr={
+ .code=TERMACK,
+ .id=layer->recv_id,
+ .len=4,
+ };
+
+ ppp_send(layer->ppp,&hdr,hdr.len);
+}
+void send_echo_reply(struct ppp_layer_t *layer)
+{
+ struct ppp_hdr_t hdr={
+ .code=ECHOREP,
+ .id=layer->recv_id,
+ .len=8,
+ };
+
+ *(int*)hdr.data=layer->magic_num;
+
+ ppp_send(layer->ppp,&hdr,hdr.len);
+}
+
+void ppp_fsm_recv(struct ppp_layer_t *layer)
+{
+}
+
+static void init_req_counter(struct ppp_layer_t *layer,int timeout)
+{
+ triton_timer_del(&layer->restart_timer);
+ triton_timer_add(&layer->restart_timer);
+ layer->restart_counter=timeout;
+}
+static void zero_req_counter(struct ppp_layer_t *layer)
+{
+ triton_timer_del(&layer->restart_timer);
+ triton_timer_add(&layer->restart_timer);
+ layer->restart_counter=0;
+}
+
+static int restart_timer_func(struct triton_timer_t*t)
+{
+ struct ppp_layer_t *layer=(struct ppp_layer_t *)t->pd;
+
+ if (layer->restart_counter)
+ {
+ ppp_fsm_timeout0(layer);
+ layer->restart_counter--;
+ return 1;
+ }
+
+ ppp_fsm_timeout1(layer);
+ return 0;
+}
diff --git a/accel-pptpd/ppp_fsm.h b/accel-pptpd/ppp_fsm.h
new file mode 100644
index 00000000..f07735d1
--- /dev/null
+++ b/accel-pptpd/ppp_fsm.h
@@ -0,0 +1,91 @@
+#ifndef PPP_FSM_H
+#define PPP_FSM_H
+
+#include "list.h"
+
+typedef enum {FSM_Initial=0,FSM_Starting,FSM_Closed,FSM_Stopped,FSM_Closing,FSM_Stopping,FSM_Req_Sent,FSM_Ack_Rcvd,FSM_Ack_Sent,FSM_Opened} FSM_STATE;
+/*
+ * CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ 1 /* Configuration Request */
+#define CONFACK 2 /* Configuration Ack */
+#define CONFNAK 3 /* Configuration Nak */
+#define CONFREJ 4 /* Configuration Reject */
+#define TERMREQ 5 /* Termination Request */
+#define TERMACK 6 /* Termination Ack */
+#define CODEREJ 7 /* Code Reject */
+#define ECHOREQ 9 /* Echo Request */
+#define ECHOREP 10 /* Echo Reply */
+
+struct ppp_hdr_t;
+
+struct lcp_options_t
+{
+ int mru;
+ int auth;
+ int magic;
+ int accomp;
+ int pcomp;
+};
+
+struct ppp_layer_t
+{
+ struct list_head entry;
+ struct ppp_layer_t *lower;
+ struct ppp_layer_t *upper;
+
+ int proto;
+ struct ppp_t *ppp;
+ FSM_STATE fsm_state;
+
+ union
+ {
+ struct lcp_options_t lcp;
+ }options;
+
+ struct triton_timer_t restart_timer;
+ int restart_counter;
+ int max_terminate;
+ int max_configure;
+ int max_failure;
+
+ int seq;
+ int recv_id;
+ int magic_num;
+
+ int opt_restart:1;
+ int opt_passive:1;
+
+ //fsm handling
+ void (*layer_up)(struct ppp_layer_t*);
+ void (*layer_down)(struct ppp_layer_t*);
+ void (*layer_started)(struct ppp_layer_t*);
+ void (*layer_finished)(struct ppp_layer_t*);
+ void (*send_conf_req)(struct ppp_layer_t*);
+ void (*send_conf_ack)(struct ppp_layer_t*);
+ void (*send_conf_nak)(struct ppp_layer_t*);
+ void (*send_conf_rej)(struct ppp_layer_t*);
+
+ void (*recv)(struct ppp_layer_t*,struct ppp_hdr_t*);
+};
+
+void ppp_fsm_init(struct ppp_layer_t*);
+void ppp_fsm_recv(struct ppp_layer_t*);
+
+void ppp_fsm_lower_up(struct ppp_layer_t *layer);
+void ppp_fsm_lower_down(struct ppp_layer_t *layer);
+void ppp_fsm_open(struct ppp_layer_t *layer);
+void ppp_fsm_close(struct ppp_layer_t *layer);
+void ppp_fsm_timeout0(struct ppp_layer_t *layer);
+void ppp_fsm_timeout1(struct ppp_layer_t *layer);
+void ppp_fsm_recv_conf_req_good(struct ppp_layer_t *layer);
+void ppp_fsm_recv_conf_req_bad(struct ppp_layer_t *layer);
+void ppp_fsm_recv_conf_ack(struct ppp_layer_t *layer);
+void ppp_fsm_recv_conf_rej(struct ppp_layer_t *layer);
+void ppp_fsm_recv_term_req(struct ppp_layer_t *layer);
+void ppp_fsm_recv_term_ack(struct ppp_layer_t *layer);
+void ppp_fsm_recv_unk(struct ppp_layer_t *layer);
+void ppp_fsm_recv_code_rej_bad(struct ppp_layer_t *layer);
+void ppp_fsm_recv_echo(struct ppp_layer_t *layer);
+
+#endif
diff --git a/accel-pptpd/ppp_lcp.c b/accel-pptpd/ppp_lcp.c
new file mode 100644
index 00000000..8f9c88b9
--- /dev/null
+++ b/accel-pptpd/ppp_lcp.c
@@ -0,0 +1,229 @@
+#include <stdlib.h>
+#include <string.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <arpa/inet.h>
+
+#include "triton/triton.h"
+
+#include "ppp.h"
+#include "ppp_fsm.h"
+#include "events.h"
+#include "log.h"
+
+char* accomp="allow,disabled";
+char* pcomp="allow,disabled";
+char* auth="pap,mschap-v2";
+char* mppe="allow,disabled";
+char* pwdb="radius";
+
+/*
+ * Options.
+ */
+#define CI_VENDOR 0 /* Vendor Specific */
+#define CI_MRU 1 /* Maximum Receive Unit */
+#define CI_ASYNCMAP 2 /* Async Control Character Map */
+#define CI_AUTHTYPE 3 /* Authentication Type */
+#define CI_QUALITY 4 /* Quality Protocol */
+#define CI_MAGICNUMBER 5 /* Magic Number */
+#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
+#define CI_FCSALTERN 9 /* FCS-Alternatives */
+#define CI_SDP 10 /* Self-Describing-Pad */
+#define CI_NUMBERED 11 /* Numbered-Mode */
+#define CI_CALLBACK 13 /* callback */
+#define CI_MRRU 17 /* max reconstructed receive unit; multilink */
+#define CI_SSNHF 18 /* short sequence numbers for multilink */
+#define CI_EPDISC 19 /* endpoint discriminator */
+#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */
+#define CI_LDISC 23 /* Link-Discriminator */
+#define CI_LCPAUTH 24 /* LCP Authentication */
+#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */
+#define CI_PREFELIS 26 /* Prefix Elision */
+#define CI_MPHDRFMT 27 /* MP Header Format */
+#define CI_I18N 28 /* Internationalization */
+#define CI_SDL 29 /* Simple Data Link */
+
+/*static void layer_up(struct ppp_layer_t*);
+static void layer_down(struct ppp_layer_t*);
+static void layer_started(struct ppp_layer_t*);
+static void layer_finished(struct ppp_layer_t*);*/
+static void send_conf_req(struct ppp_layer_t*);
+static void send_conf_ack(struct ppp_layer_t*);
+static void send_conf_nak(struct ppp_layer_t*);
+static void send_conf_rej(struct ppp_layer_t*);
+static void lcp_recv(struct ppp_layer_t*`);
+
+struct ppp_layer_t* ppp_lcp_init(struct ppp_t *ppp)
+{
+ struct ppp_layer_t *layer=malloc(sizeof(*layer));
+ memset(layer,0,sizeof(*layer));
+
+ layer->proto=PPP_PROTO_LCP;
+ layer->ppp=ppp;
+ ppp_fsm_init(layer);
+
+ layer->recv=lcp_recv;
+ layer->send_conf_req=send_conf_req;
+ layer->send_conf_ack=send_conf_ack;
+ layer->send_conf_nak=send_conf_nak;
+ layer->send_conf_rej=send_conf_rej;
+
+ ppp_fsm_init(layer);
+
+ return layer;
+}
+
+/*void ev_ppp_packet(int proto,struct ppp_t *ppp)
+{
+ struct ppp_hdr_t *hdr;
+
+ if (proto!=PPP_LCP) return;
+ if (ppp->in_buf_size-2<PPP_HEADERLEN)
+ {
+ log_debug("LCP: short packet received\n");
+ return;
+ }
+
+ hdr=(struct ppp_hdr_t *)(ppp->in_buf+2);
+ if (hdr->len<PPP_HEADERLEN)
+ {
+ log_debug("LCP: short packet received\n");
+ return;
+ }
+
+ //ppp_fsm_recv();
+}*/
+
+/*static void layer_up(struct ppp_layer_t*)
+{
+}
+static void layer_down(struct ppp_layer_t*)
+{
+}
+static void layer_started(struct ppp_layer_t*)
+{
+}
+static void layer_finished(struct ppp_layer_t*)
+{
+}*/
+static void send_conf_req(struct ppp_layer_t*l)
+{
+}
+static void send_conf_ack(struct ppp_layer_t*l)
+{
+}
+static void send_conf_nak(struct ppp_layer_t*l)
+{
+}
+static void send_conf_rej(struct ppp_layer_t*l)
+{
+}
+
+static int lcp_recv_conf_req(struct ppp_layer_t*l,u_int8_t *data,int size)
+{
+ struct ppp_opt_t *opt;
+ while(size)
+ {
+ opt=(struct ppp_opt_t *)data;
+ switch(opt->type)
+ {
+ case CI_MRU:
+ l->options.lcp.mru=*(u_int16_t*)data;
+ break;
+ case CI_ASYNCMAP:
+ break;
+ case CI_AUTHTYPE:
+ if (l->ppp->log) log_msg("<auth ");
+ switch(*(u_int16_t*)data)
+ {
+ case PPP_PAP:
+ if (l->ppp->log) log_msg("pap");
+ break;
+ case PPP_EAP:
+ if (l->ppp->log) log_msg("eap");
+ break;
+ case PPP_CHAP:
+ if (l->ppp->log) log_msg("chap");
+ break;
+ /*switch(data[4])
+ {
+ case
+ }*/
+ default:
+ if (l->ppp->log) log_msg("unknown");
+ return -1;
+ }
+ if (l->ppp->log) log_msg(" auth>");
+ case CI_MAGICNUMBER:
+ if (*(u_int32_t*)data==l->magic_num)
+ {
+ log_error("loop detected\n");
+ return -1;
+ }
+ break;
+ case CI_PCOMPRESSION:
+ case CI_ACCOMPRESSION:
+ }
+ }
+ return 0;
+}
+
+static void lcp_recv(struct ppp_layer_t*l)
+{
+ struct ppp_hdr_t *hdr;
+
+ if (l->ppp->in_buf_size-2<PPP_HEADERLEN)
+ {
+ log_debug("LCP: short packet received\n");
+ return;
+ }
+
+ hdr=(struct ppp_hdr_t *)(l->ppp->in_buf+2);
+ if (hdr->len<PPP_HEADERLEN)
+ {
+ log_debug("LCP: short packet received\n");
+ return;
+ }
+
+ l->recv_id=hdr->id;
+ switch(hdr->code)
+ {
+ case CONFREQ:
+ if (lcp_recv_conf_req(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN))
+ ppp_fsm_recv_conf_req_bad(l);
+ else
+ ppp_fsm_recv_conf_req_good(l);
+ break;
+ case CONFACK:
+ lcp_recv_conf_ack(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN);
+ ppp_fsm_recv_conf_ack(l);
+ break;
+ case CONFNAK:
+ lcp_recv_conf_nak(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN);
+ ppp_fsm_recv_conf_nak(l);
+ break;
+ case CONFREJ:
+ lcp_recv_conf_rej(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN);
+ ppp_fsm_recv_conf_rej(l);
+ break;
+ case TERMREQ:
+ ppp_fsm_recv_term_req(l);
+ break;
+ case TERMACK:
+ ppp_fsm_recv_term_ack(l);
+ break;
+ case CODEREJ:
+ ppp_fsm_recv_code_rej_bad(l);
+ break;
+ case ECHOREQ:
+ ppp_fsm_recv_echo_req(l);
+ break;
+ case ECHOREP:
+ lcp_recv_echo_rep(l);
+ break;
+ default:
+ ppp_fsm_recv_unk(l);
+ break;
+ }
+}
diff --git a/accel-pptpd/pptp_prot.h b/accel-pptpd/pptp_prot.h
new file mode 100644
index 00000000..cee250b3
--- /dev/null
+++ b/accel-pptpd/pptp_prot.h
@@ -0,0 +1,297 @@
+#ifndef PPTP_PROT_H
+#define PPTP_PROT_H
+
+#include <sys/types.h>
+
+#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 */
+
+/* PPTP result codes:---------------------------------------- */
+#define PPTP_CONN_RES_SUCCESS 1
+#define PPTP_CONN_RES_GE 2
+#define PPTP_CONN_RES_EXISTS 3
+#define PPTP_CONN_RES_AUTH 4
+#define PPTP_CONN_RES_PROTOCOL 5
+
+#define PPTP_CONN_STOP_OK 1
+#define PPTP_CONN_STOP_GE 2
+
+#define PPTP_CALL_RES_OK 1
+#define PPTP_CALL_RES_GE 2
+
+#define PPTP_GE_NOCONN 1
+
+/* 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
+
+#define PPTP_HOSTNAME "local"
+#define PPTP_VENDOR "cananian"
+
+/* 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. */
+}__attribute__((packed));
+
+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.) */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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.) */
+}__attribute__((packed));
+
+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) */
+}__attribute__((packed));
+
+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.) */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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 */
+}__attribute__((packed));
+
+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)*/
+}__attribute__((packed));
+
+/* 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)))))))))))))
+
+#endif
diff --git a/accel-pptpd/pptpd.c b/accel-pptpd/pptpd.c
new file mode 100644
index 00000000..e29e61fc
--- /dev/null
+++ b/accel-pptpd/pptpd.c
@@ -0,0 +1,134 @@
+/*
+* C Implementation: pptpd
+*
+* Description:
+*
+*
+* Author: <xeb@mail.ru>, (C) 2009
+*
+* Copyright: See COPYING file that comes with this distribution
+*
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "list.h"
+#include "pptp_prot.h"
+#include "triton/triton.h"
+#include "pptpd.h"
+#include "log.h"
+
+static struct ctrl_thread_t *threads=NULL;
+static int threads_count=0;
+
+int start_server(void)
+{
+ int sock,c_sock;
+ int r,min_thr,min_cnt;
+ struct pollfd pfd;
+ struct sockaddr_in addr;
+ socklen_t size;
+
+ sock=socket (PF_INET, SOCK_STREAM, 0);
+ if (sock<0)
+ {
+ log_error("failed to create socket\n");
+ return -1;
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (PPTP_PORT);
+ addr.sin_addr.s_addr = htonl (INADDR_ANY);
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof(sock));
+ if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+ {
+ perror("bind");
+ log_error("failed to bind socket\n");
+ return -1;
+ }
+
+ if (listen (sock, 1000)<0)
+ {
+ log_error("failed to listen socket\n");
+ return -1;
+ }
+
+ pfd.fd=sock;
+ pfd.events=POLLIN;
+
+ while(1)
+ {
+ r=poll(&pfd,1,-1);
+ if (r<0 && errno!=EINTR)
+ {
+ log_error("poll failed\n");
+ return -2;
+ }
+ if (r<=0) continue;
+ if (!(pfd.revents&POLLIN)) continue;
+
+ size=sizeof(addr);
+ c_sock=accept(sock,(struct sockaddr *)&addr,&size);
+ if (c_sock<0)
+ {
+ log_error("client accept failed\n");
+ continue;
+ }
+
+ min_thr=0; min_cnt=65536;
+ for(r=0; r<threads_count; r++)
+ {
+ pthread_mutex_lock(&threads[r].lock);
+ if (threads[r].count<min_cnt)
+ {
+ min_cnt=threads[r].count;
+ min_thr=r;
+ }
+ pthread_mutex_unlock(&threads[r].lock);
+ }
+ write(threads[min_thr].pipe_fd[1],&c_sock,sizeof(c_sock));
+ }
+}
+
+int start_threads(int cnt)
+{
+ int i;
+ if (!cnt) cnt=sysconf(_SC_NPROCESSORS_CONF);
+ threads=malloc(cnt*sizeof(*threads));
+ memset(threads,0,cnt*sizeof(*threads));
+
+ for(i=0; i<cnt; i++)
+ {
+ //threads[i].lock=PTHREAD_MUTEX_INITIALIZER;
+ if (pipe(threads[i].pipe_fd))
+ {
+ log_error("failed to create pipe\n");
+ return -1;
+ }
+ if (triton_run((int(*)(void*))ctrl_init,&threads[i]))
+ {
+ log_error("triton_run failed\n");
+ return -1;
+ }
+ }
+ threads_count=cnt;
+ return 0;
+}
+
+int main(int argc,char **argv)
+{
+ log_init(stdout,4,0);
+ start_threads(0);
+ start_server();
+ return EXIT_SUCCESS;
+}
diff --git a/accel-pptpd/pptpd.h b/accel-pptpd/pptpd.h
new file mode 100644
index 00000000..d98978e5
--- /dev/null
+++ b/accel-pptpd/pptpd.h
@@ -0,0 +1,26 @@
+//
+// C++ Interface: pptpd
+//
+// Description:
+//
+//
+// Author: <xeb@mail.ru>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef PPTPD_H
+#define PPTPD_H
+
+struct ctrl_thread_t
+{
+ pthread_t thr;
+ pthread_mutex_t lock;
+ int count;
+ int pipe_fd[2];
+};
+
+int ctrl_init(struct ctrl_thread_t*);
+
+#endif
diff --git a/accel-pptpd/triton/CMakeLists.txt b/accel-pptpd/triton/CMakeLists.txt
new file mode 100644
index 00000000..868c3eb1
--- /dev/null
+++ b/accel-pptpd/triton/CMakeLists.txt
@@ -0,0 +1,13 @@
+SET(target triton)
+SET(sources_c
+ md.c
+ conf_file.c
+ coroutine.c
+ event.c
+ timer.c
+ options.c
+ loader.c
+)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_LIBRARY(${target} STATIC ${sources_c})
diff --git a/accel-pptpd/triton/conf_file.c b/accel-pptpd/triton/conf_file.c
new file mode 100644
index 00000000..3ddb649e
--- /dev/null
+++ b/accel-pptpd/triton/conf_file.c
@@ -0,0 +1,185 @@
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "conf_file.h"
+#include "triton_p.h"
+
+struct sect_t
+{
+ struct list_head entry;
+
+ struct conf_file_sect_t *sect;
+};
+
+static LIST_HEAD(sections);
+
+static char* skip_space(char *str);
+static char* skip_word(char *str);
+
+static struct conf_file_sect_t *find_sect(const char *name);
+static struct conf_file_sect_t *create_sect(const char *name);
+static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const char *val);
+static struct option_t *find_item(struct conf_file_sect_t *,const char *name);
+
+void conf_file_load(const char *fname)
+{
+ char *buf,*str,*str2;
+ char *path0,*path;
+ int cur_line=0;
+ static struct conf_file_sect_t *cur_sect=NULL;
+ FILE *f=fopen(fname,"r");
+ if (!f)
+ {
+ perror("triton: open conf file");
+ return;
+ }
+
+ buf=(char*)malloc(1024);
+ path0=(char*)malloc(4096);
+ path=(char*)malloc(4096);
+
+ getcwd(path0,1024);
+
+ while(!feof(f))
+ {
+ buf=fgets(buf,1024,f);
+ if (!buf) break;
+ ++cur_line;
+ if (buf[strlen(buf)-1]=='\n')
+ buf[strlen(buf)-1]=0;
+
+ str=skip_space(buf);
+ if (*str=='#' || *str==0) continue;
+ if (strncmp(str,"$include",8)==0)
+ {
+ str=skip_word(str);
+ str=skip_space(str);
+ /*if (*str=='.')
+ {
+ strcpy(path,path0);
+ strcat(path,str+1);
+ str=path;
+ }*/
+ conf_file_load(str);
+ continue;
+ }
+ if (*str=='[')
+ {
+ for (str2=++str; *str2 && *str2!=']'; str2++);
+ if (*str2!=']')
+ {
+//L1:
+ printf("triton: sintax error in conf file %s line %i\n",fname,cur_line);
+ return;
+ }
+ *str2=0;
+ cur_sect=find_sect(str);
+ if (!cur_sect) cur_sect=create_sect(str);
+ continue;
+ }
+ if (!cur_sect)
+ {
+ printf("triton: no section opened in conf file %s line %i\n",fname,cur_line);
+ return;
+ }
+ str2=skip_word(str);
+ if (*str2==' ')
+ {
+ *str2=0;
+ ++str2;
+ }
+ str2=skip_space(str2);
+ if (*str2=='=' || *str2==',')
+ {
+ *str2=0;
+ str2=skip_space(str2+1);
+ if (*str2 && *(str2+1) && *str2=='$' && *(str2+1)=='{')
+ {
+ char *s;
+ struct option_t *opt;
+ for (s=str2+2; *s && *s!='}'; s++);
+ if (*s=='}')
+ {
+ *s=0;
+ str2+=2;
+ }
+ opt=find_item(cur_sect,str2);
+ if (!opt)
+ {
+ printf("triton: parent option not found int conf file %s line %i\n",fname,cur_line);
+ return;
+ }
+ str2=opt->val;
+ }
+ }else str2=NULL;
+ sect_add_item(cur_sect,str,str2);
+ }
+
+ free(buf);
+ free(path);
+ free(path0);
+ fclose(f);
+}
+
+static char* skip_space(char *str)
+{
+ for (; *str && *str==' '; str++);
+ return str;
+}
+static char* skip_word(char *str)
+{
+ for (; *str && (*str!=' ' && *str!='='); str++);
+ return str;
+}
+
+static struct conf_file_sect_t *find_sect(const char *name)
+{
+ struct sect_t *s;
+ list_for_each_entry(s,&sections,entry)
+ {
+ if (strcmp(s->sect->name,name)==0) return s->sect;
+ }
+ return NULL;
+}
+
+static struct conf_file_sect_t *create_sect(const char *name)
+{
+ struct sect_t *s=(struct sect_t *)malloc(sizeof(struct sect_t));
+
+ s->sect=(struct conf_file_sect_t*)malloc(sizeof(struct conf_file_sect_t));
+ s->sect->name=(char*)strdup(name);
+ INIT_LIST_HEAD(&s->sect->items);
+
+ list_add_tail(&s->entry,&sections);
+
+ return s->sect;
+}
+
+static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const char *val)
+{
+ struct option_t *opt=(struct option_t *)malloc(sizeof(struct option_t));
+
+ opt->name=(char*)strdup(name);
+ opt->val=val?(char*)strdup(val):NULL;
+
+ list_add_tail(&opt->entry,&sect->items);
+}
+
+static struct option_t *find_item(struct conf_file_sect_t *sect,const char *name)
+{
+ struct option_t *opt;
+ list_for_each_entry(opt,&sect->items,entry)
+ {
+ if (strcmp(opt->name,name)==0)
+ return opt;
+ }
+
+ return NULL;
+}
+
+struct conf_file_sect_t *conf_file_get_section(const char *name)
+{
+ return find_sect(name);
+}
diff --git a/accel-pptpd/triton/conf_file.h b/accel-pptpd/triton/conf_file.h
new file mode 100644
index 00000000..47ade313
--- /dev/null
+++ b/accel-pptpd/triton/conf_file.h
@@ -0,0 +1,16 @@
+#ifndef CONF_FILE_H
+#define CONF_FILE_H
+
+#include "list.h"
+
+struct conf_file_sect_t
+{
+ const char *name;
+
+ struct list_head items;
+};
+
+void conf_file_load(const char *fname);
+struct conf_file_sect_t *conf_file_get_section(const char *name);
+
+#endif
diff --git a/accel-pptpd/triton/coroutine.c b/accel-pptpd/triton/coroutine.c
new file mode 100644
index 00000000..b2866d0f
--- /dev/null
+++ b/accel-pptpd/triton/coroutine.c
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <string.h>
+
+#include "triton_p.h"
+
+#ifdef USE_CORO
+
+static LIST_HEAD(coroutines);
+asm(".hidden current_coro");
+struct coroutine_t *current_coro=NULL;
+//asm(".hidden sched_uc");
+static ucontext_t sched_uc;
+
+asm(".hidden schedule");
+void schedule(void)
+{
+ struct coroutine_t *coro;
+ struct list_head *p;
+ while(1)
+ {
+ current_coro=NULL;
+ for(p=coroutines.next; p!=&coroutines; p=p->next)
+ {
+ coro=list_entry(p,typeof(*current_coro),entry);
+ if (coro->time.tv_sec)
+ {
+ if (!current_coro) current_coro=coro;
+ else if (coro->time.tv_sec<current_coro->time.tv_sec) continue;
+ else if (coro->time.tv_sec>current_coro->time.tv_sec || coro->time.tv_usec>current_coro->time.tv_usec) current_coro=coro;
+ }
+ }
+ if (current_coro)
+ {
+ get_time(&current_coro->time);
+ swapcontext(&sched_uc,&current_coro->uc);
+ //break;
+ }else
+ {
+ printf("triton: coroutine: bug: no current coro !!!\n");
+ exit(-1);
+ }
+ }
+}
+
+void coroutine_init(void)
+{
+ getcontext(&sched_uc);
+ sched_uc.uc_stack.ss_sp=malloc(DEF_COROUTINE_STACK);
+ sched_uc.uc_stack.ss_size=DEF_COROUTINE_STACK;
+ makecontext(&sched_uc,schedule,0);
+}
+
+void triton_coroutine_schedule()
+{
+ memset(&current_coro->time,0,sizeof(current_coro->time));
+ memset(&current_coro->timeout,0,sizeof(current_coro->timeout));
+ swapcontext(&current_coro->uc,&sched_uc);
+}
+
+long int triton_coroutine_create(int stack_size,triton_coroutine_func func,void *arg,int run)
+{
+ struct coroutine_t *coro=malloc(sizeof(*coro));
+ memset(coro,0,sizeof(*coro));
+
+ if (!stack_size) stack_size=DEF_COROUTINE_STACK;//+SIGSTKSZ;
+
+ getcontext(&coro->uc);
+ coro->uc.uc_link=&sched_uc;
+ coro->uc.uc_stack.ss_sp=malloc(stack_size);
+ coro->uc.uc_stack.ss_size=stack_size;
+ makecontext(&coro->uc,(void (*)(void))func,1,arg);
+
+ if (run) coro->time.tv_sec=1;
+
+ list_add(&coro->entry,&coroutines);
+
+ return (long int)coro;
+}
+void triton_coroutine_delete(long int id)
+{
+ struct coroutine_t *coro=(struct coroutine_t *)id;
+
+ list_del(&coro->entry);
+ free(coro->uc.uc_stack.ss_sp);
+}
+int triton_coroutine_schedule_timeout(int msec)
+{
+ //current_coro->msleep=msec;
+ struct timeval tv;
+ int t;
+ get_time(&current_coro->timeout);
+ current_coro->timeout.tv_sec+=msec/1000;
+ current_coro->timeout.tv_usec+=(msec%1000)*1000;
+ if (current_coro->timeout.tv_usec>=1000000)
+ {
+ current_coro->timeout.tv_sec++;
+ current_coro->timeout.tv_usec-=1000000;
+ }
+ //triton_coroutine_schedule();
+ memset(&current_coro->time,0,sizeof(current_coro->time));
+ //memset(&current_coro->timeout,0,sizeof(current_coro->timeout));
+ swapcontext(&current_coro->uc,&sched_uc);
+ get_time(&tv);
+ t=(current_coro->timeout.tv_sec-tv.tv_sec)*1000+(current_coro->timeout.tv_usec-tv.tv_usec)/1000;
+ if (t<0) t=0;
+ return t;
+}
+void triton_coroutine_wakeup(long int id)
+{
+ struct coroutine_t *coro=(struct coroutine_t *)id;
+ struct coroutine_t *cur_coro=current_coro;
+ get_time(&current_coro->time);
+ current_coro=coro;
+ swapcontext(&cur_coro->uc,&coro->uc);
+}
+
+asm(".hidden coroutine_get_timeout");
+int coroutine_get_timeout(struct timeval *tv)
+{
+ struct coroutine_t *coro;
+ struct list_head *p;
+ int twait,t=-1;
+ for(p=coroutines.next; p!=&coroutines; p=p->next)
+ {
+ coro=list_entry(p,typeof(*coro),entry);
+ if (coro->timeout.tv_sec)
+ {
+ twait=(coro->timeout.tv_sec-tv->tv_sec)*1000+(coro->timeout.tv_usec-tv->tv_usec)/1000;
+ if (t==-1 || twait<t) t=twait;
+ }
+ }
+ return t;
+}
+asm(".hidden coroutine_check_timeout");
+void coroutine_check_timeout(struct timeval *tv)
+{
+ struct coroutine_t *coro;
+ struct list_head *p;
+ for(p=coroutines.next; p!=&coroutines;)
+ {
+ coro=list_entry(p,typeof(*coro),entry);
+ p=p->next;
+ if (coro->timeout.tv_sec && (tv->tv_sec>coro->timeout.tv_sec || (tv->tv_sec==coro->timeout.tv_sec && tv->tv_usec>=coro->timeout.tv_usec)))
+ {
+ triton_coroutine_wakeup((long int)coro);
+ }
+ }
+}
+
+#endif
diff --git a/accel-pptpd/triton/event.c b/accel-pptpd/triton/event.c
new file mode 100644
index 00000000..9daa226b
--- /dev/null
+++ b/accel-pptpd/triton/event.c
@@ -0,0 +1,155 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "triton_p.h"
+
+#define EVENTS1_SIZE 1024
+
+static __thread struct list_head events2;
+static __thread struct event_t *events1;
+static __thread long *args;
+
+asm(".hidden event_init");
+
+static struct event_t *find_event(int ev_id);
+static struct event_t *create_event(int ev_id);
+
+void event_init(void)
+{
+ int i;
+ args=malloc(MAX_ARGS*sizeof(long));
+ events1=(struct event_t *)malloc(EVENTS1_SIZE*sizeof(struct event_t));
+
+ for (i=0; i<EVENTS1_SIZE; i++)
+ {
+ events1[i].ev_id=i;
+ INIT_LIST_HEAD(&events1[i].handlers);
+ }
+
+ INIT_LIST_HEAD(&events2);
+}
+
+void triton_event_register_handler(int ev_id,triton_event_func func,int arg_cnt,...)
+{
+ struct event_t *ev;
+ struct event_handler_t *ev_h;
+
+ ev=find_event(ev_id);
+ if (!ev)
+ ev=create_event(ev_id);
+
+ ev_h=(struct event_handler_t*)malloc(sizeof(struct event_handler_t));
+ memset(ev_h,0,sizeof(*ev_h));
+ ev_h->event_func=func;
+ if (arg_cnt)
+ {
+ va_list p;
+ va_start(p,arg_cnt);
+ ev_h->arg_cnt=arg_cnt;
+ ev_h->args=malloc(arg_cnt*sizeof(long));
+ #ifdef BROKEN_GCC
+ for(i=0; i<arg_cnt; i++)
+ *((int*)ev_h->args+i)=va_arg(p,long);
+ #else
+ memcpy(ev_h->args,p,arg_cnt*sizeof(long));
+ #endif
+ va_end(p);
+ }
+
+ list_add_tail(&ev_h->entry,&ev->handlers);
+}
+void triton_event_unregister_handler(int ev_id,triton_event_func func)
+{
+ struct event_t *ev;
+ struct event_handler_t *ev_h;
+
+ ev=find_event(ev_id);
+ if (!ev)
+ return;
+
+ list_for_each_entry(ev_h,&ev->handlers,entry)
+ {
+ if (ev_h->event_func==func)
+ {
+ list_del(&ev_h->entry);
+ if (ev_h->args) free(ev_h->args);
+ free(ev_h);
+
+ if (list_empty(&ev->handlers) && ev_id>=EVENTS1_SIZE)
+ {
+ list_del(&ev->entry);
+ free(ev);
+ }
+ return;
+ }
+ }
+}
+
+/*#define dyn_call(func,arg_cnt,args)\
+ asm("movl %%esp,%%edi;\n\
+ movl %0,%%esi;\n\
+ movl %1,%%ecx;\n\
+ cld;\n\
+ rep movsl;\n\
+ call *%2;\n"::"m" (args),"m" (arg_cnt),"m" (func):"%edi","%esi","%ecx");*/
+
+void triton_event_fire(int ev_id,int arg_cnt,...)
+{
+ struct event_t *ev;
+ struct event_handler_t *ev_h;
+ struct list_head *p1,*p2;
+ va_list p;
+ //void *args_p=&args;
+ //char pp[ARG_OFFSET+MAX_ARGS*sizeof(int)];
+ //memcpy(pp,__builtin_apply_args(),ARG_OFFSET);
+
+ ev=find_event(ev_id);
+ if (!ev)
+ return;
+
+ list_for_each_safe(p1,p2,&ev->handlers)
+ {
+ ev_h=list_entry(p1,struct event_handler_t,entry);
+ if (ev_h->arg_cnt) memcpy(args,ev_h->args,ev_h->arg_cnt*sizeof(long));
+ va_start(p,arg_cnt);
+ #ifdef BROKEN_GCC
+ for(i=0; i<arg_cnt; i++)
+ args[ev_h->arg_cnt+i]=va_arg(p,long);
+ #else
+ memcpy(args+ev_h->arg_cnt,p,arg_cnt*sizeof(long));
+ #endif
+ //memcpy(pp+ARG_OFFSET,args,(ev_h->arg_cnt+arg_cnt)*sizeof(int));
+ //__builtin_apply(ev_h->event_func,pp,ARG_OFFSET+(ev_h->arg_cnt+arg_cnt)*sizeof(int));
+ //ev_h->event_func(ev_id,arg);
+ //__builtin_apply(ev_h->event_func,args_p,(ev_h->arg_cnt+arg_cnt)*sizeof(int));
+ dyn_call(ev_h->event_func,ev_h->arg_cnt+arg_cnt,args);
+ }
+
+ va_end(p);
+}
+
+static struct event_t *find_event(int ev_id)
+{
+ struct event_t *ev;
+ if (ev_id<EVENTS1_SIZE)
+ return events1+ev_id;
+
+ list_for_each_entry(ev,&events2,entry)
+ {
+ if (ev->ev_id==ev_id)
+ return ev;
+ }
+ return NULL;
+}
+static struct event_t *create_event(int ev_id)
+{
+ struct event_t *ev=(struct event_t *)malloc(sizeof(struct event_t));
+
+ INIT_LIST_HEAD(&ev->handlers);
+
+ list_add_tail(&ev->entry,&events2);
+
+ return ev;
+}
diff --git a/accel-pptpd/triton/list.h b/accel-pptpd/triton/list.h
new file mode 100644
index 00000000..d95dd714
--- /dev/null
+++ b/accel-pptpd/triton/list.h
@@ -0,0 +1,249 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE)
+
+//#include <linux/prefetch.h>
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+typedef struct list_head {
+ struct list_head *next, *prev;
+} list_t;
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+
+static void inline prefetch(void *p){}
+
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = (void *) 0;
+ entry->prev = (void *) 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+//#endif /* __KERNEL__ || _LVM_H_INCLUDE */
+
+#endif
diff --git a/accel-pptpd/triton/loader.c b/accel-pptpd/triton/loader.c
new file mode 100644
index 00000000..33d48315
--- /dev/null
+++ b/accel-pptpd/triton/loader.c
@@ -0,0 +1,55 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include "conf_file.h"
+#include "triton_p.h"
+
+void md_init(void);
+void event_init(void);
+void timer_init(void);
+
+struct thread_arg_t
+{
+ int (*post_init)(void*);
+ void *arg;
+};
+
+void *thread(struct thread_arg_t *arg)
+{
+ printf("triton: starting new thread\n");
+ #ifdef USE_CORO
+ coroutine_init();
+ #endif
+ md_init();
+ event_init();
+ timer_init();
+
+ arg->post_init(arg->arg);
+
+ free(arg);
+
+ //conf_file_load(cf_name);
+ #ifdef USE_CORO
+ schedule();
+ #else
+ md_run();
+ #endif
+
+ return NULL;
+}
+
+int triton_init(const char *conf_file)
+{
+ return 0;
+}
+int triton_run(int (*post_init)(void*),void *arg)
+{
+ pthread_t thr;
+ struct thread_arg_t *thr_arg=malloc(sizeof(*thr_arg));
+ thr_arg->post_init=post_init;
+ thr_arg->arg=arg;
+ return pthread_create(&thr,NULL,(void*(*)(void*))thread,thr_arg);
+}
diff --git a/accel-pptpd/triton/md.c b/accel-pptpd/triton/md.c
new file mode 100644
index 00000000..a0d2fabb
--- /dev/null
+++ b/accel-pptpd/triton/md.c
@@ -0,0 +1,342 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <string.h>
+
+#include "triton_p.h"
+
+#define USE_GET_TIME
+
+static __thread struct list_head handlers;
+static __thread fd_set read_fds;
+static __thread fd_set write_fds;
+static __thread fd_set read_fds0;
+static __thread fd_set write_fds0;
+static __thread int md_term;
+
+asm(".hidden md_init");
+asm(".hidden md_run");
+asm(".hidden md_terminate");
+
+static void _triton_process_events(int wait);
+
+void md_init()
+{
+ INIT_LIST_HEAD(&handlers);
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&write_fds);
+
+ signal(SIGPIPE,SIG_IGN);
+
+ #ifdef USE_CORO
+ triton_coroutine_create(0,md_run,0,1);
+ #endif
+}
+void md_run()
+{
+ md_term=0;
+
+ while(!md_term)
+ {
+ _triton_process_events(1);
+ }
+}
+
+
+#ifdef USE_CORO
+asm(".hidden cur_uc");
+ucontext_t cur_uc;
+#endif
+
+static void _triton_process_events(int wait)
+{
+ int max_fd=0,t;
+ struct md_handler_t *md_h;
+ struct timeval tv1,tv2,twait0;
+ struct list_head *p1,*p2;
+ int twait,n;
+ int _break=0;
+
+ gettimeofday(&tv1,NULL);
+ _break=0;
+
+ if (wait)
+ {
+ twait=timer_prepare(&tv1);
+ #ifdef USE_CORO
+ t=coroutine_get_timeout(&tv1);
+ #else
+ t=-1;
+ #endif
+ if (t>=0 && (twait==-1 || t<twait)) twait=t;
+
+ list_for_each_entry(md_h,&handlers,entry)
+ {
+ if (md_h->in_handler) continue;
+ if (md_h->handler->twait>=0 && (twait==-1 || md_h->handler->twait<twait)) twait=md_h->handler->twait;
+ }
+ }else
+ {
+ twait=0;
+ }
+
+ read_fds0=read_fds; write_fds0=write_fds;
+
+ list_for_each_entry(md_h,&handlers,entry)
+ {
+ if (md_h->in_handler)
+ {
+ FD_CLR(md_h->fd,&read_fds0);
+ FD_CLR(md_h->fd,&write_fds0);
+ }else
+ {
+ if (md_h->fd>max_fd) max_fd=md_h->fd;
+ }
+ }
+
+ twait0=(struct timeval){twait/1000,(twait%1000)*1000};
+ n=select(max_fd+1,&read_fds0,&write_fds0,NULL,twait>=0?&twait0:NULL);
+
+ gettimeofday(&tv2,NULL);
+ twait=(tv2.tv_sec-tv1.tv_sec)*1000+(tv2.tv_usec-tv1.tv_usec)/1000;
+
+ list_for_each_safe(p1,p2,&handlers)
+ {
+ md_h=list_entry(p1,struct md_handler_t,entry);
+ //if (!md_h->del)
+ {
+ if (md_h->handler->twait>=0)
+ {
+ md_h->handler->twait-=twait;
+ if (md_h->handler->twait<=0) md_h->timeout=1;
+ }
+ }
+ }
+
+ timer_check(&tv2);
+ gettimeofday(&tv2,NULL);
+ #ifdef USE_CORO
+ coroutine_check_timeout(&tv2);
+ #endif
+
+ list_for_each_safe(p1,p2,&handlers)
+ {
+ md_h=list_entry(p1,struct md_handler_t,entry);
+ if (md_h->in_handler) continue;
+ if (!md_h->del)
+ {
+ if (md_h->timeout)
+ {
+ md_h->timeout=0;
+ #ifdef USE_CORO
+ md_h->in_handler=1;
+ if (md_h->coro)
+ {
+ long int id=(long int)md_h->coro;
+ md_h->coro=NULL;
+ triton_coroutine_wakeup(id);
+ }else
+ #endif
+ {
+ md_h->handler->timeout(md_h->handler);
+ }
+ md_h->in_handler=0;
+ if (_break) return;
+ }
+ }
+ }
+
+ if (n<0)
+ {
+ perror("triton: md(select)");
+ //goto check_timeout;
+ }
+ if (n>0)
+ {
+ list_for_each_safe(p1,p2,&handlers)
+ {
+ md_h=list_entry(p1,struct md_handler_t,entry);
+ if (md_h->in_handler) continue;
+ if (md_h->del) continue;
+ md_h->in_handler=1;
+ if (FD_ISSET(md_h->fd,&read_fds0))
+ {
+ if (md_h->handler->read==md_h->handler->write)
+ FD_CLR(md_h->fd,&write_fds0);
+
+ #ifdef USE_CORO
+ if (md_h->coro)
+ {
+ long int id=(long int)md_h->coro;
+ md_h->coro=NULL;
+ triton_coroutine_wakeup(id);
+ }else
+ #endif
+ {
+ md_h->handler->read(md_h->handler);
+ }
+ }
+ if (!md_h->del && FD_ISSET(md_h->fd,&write_fds0) && md_h->handler->write)
+ {
+ #ifdef USE_CORO
+ if (md_h->coro)
+ {
+ long int id=(long int)md_h->coro;
+ md_h->coro=NULL;
+ triton_coroutine_wakeup(id);
+ }else
+ #endif
+ {
+ md_h->handler->write(md_h->handler);
+ }
+ }
+ md_h->in_handler=0;
+ if (_break) return;
+ }
+ }
+//check_timeout:
+
+ for(p1=handlers.next; p1!=&handlers;)
+ {
+ md_h=list_entry(p1,struct md_handler_t,entry);
+ p1=p1->next;
+ if (md_h->del)
+ {
+ list_del(&md_h->entry);
+ free(md_h);
+ }
+ }
+
+ if (!wait) _break=1;
+}
+
+void triton_process_events(void)
+{
+ _triton_process_events(0);
+}
+
+void md_terminate()
+{
+ md_term=1;
+}
+
+void triton_md_register_handler(struct triton_md_handler_t *h)
+{
+ struct md_handler_t *md_h;
+
+ list_for_each_entry(md_h,&handlers,entry)
+ {
+ if (md_h->handler==h)
+ {
+ if (!md_h->del)
+ {
+ printf("triton: bug: double triton_md_register_handler\n");
+ abort();
+ }
+ md_h->del=0;
+ md_h->in_handler=0;
+ md_h->coro=0;
+ md_h->fd=0;
+ return;
+ }
+ }
+
+ md_h=(struct md_handler_t *)malloc(sizeof(struct md_handler_t));
+ memset(md_h,0,sizeof(*md_h));
+ md_h->handler=h;
+
+ list_add_tail(&md_h->entry,&handlers);
+}
+void triton_md_unregister_handler(struct triton_md_handler_t *h)
+{
+ struct md_handler_t *md_h;
+
+ list_for_each_entry(md_h,&handlers,entry)
+ {
+ if (md_h->handler==h)
+ {
+ triton_md_disable_handler(h,0);
+ /*list_del(&md_h->entry);
+ free(md_h);
+ return;*/
+ md_h->del=1;
+ return;
+ }
+ }
+}
+void triton_md_enable_handler(struct triton_md_handler_t *h, int mode)
+{
+ struct md_handler_t *md_h;
+
+ list_for_each_entry(md_h,&handlers,entry)
+ {
+ if (md_h->handler==h)
+ {
+ md_h->fd=h->fd;
+ break;
+ }
+ }
+ if (mode)
+ {
+ if (mode&MD_MODE_READ)
+ FD_SET(h->fd,&read_fds);
+ if (mode&MD_MODE_WRITE)
+ FD_SET(h->fd,&write_fds);
+ }else
+ {
+ FD_SET(h->fd,&read_fds);
+ FD_SET(h->fd,&write_fds);
+ }
+}
+void triton_md_disable_handler(struct triton_md_handler_t *h,int mode)
+{
+ if (mode)
+ {
+ if (mode&MD_MODE_READ)
+ FD_CLR(h->fd,&read_fds);
+ if (mode&MD_MODE_WRITE)
+ FD_CLR(h->fd,&write_fds);
+ }else
+ {
+ FD_CLR(h->fd,&read_fds);
+ FD_CLR(h->fd,&write_fds);
+ }
+}
+
+#ifdef USE_CORO
+int triton_md_wait(struct triton_md_handler_t *h)
+{
+ struct md_handler_t *md_h;
+ int res=0;
+
+ list_for_each_entry(md_h,&handlers,entry)
+ {
+ if (md_h->handler==h) break;
+ }
+
+ md_h->in_handler=0;
+
+ md_h->coro=current_coro;
+ triton_coroutine_schedule();
+
+ if (FD_ISSET(md_h->fd,&read_fds0)) res|=MD_MODE_READ;
+ if (FD_ISSET(md_h->fd,&write_fds0)) res|=MD_MODE_WRITE;
+ return res;
+}
+int triton_md_wait2(int fd,int mode,int timeout)
+{
+ int r;
+ struct triton_md_handler_t h=
+ {
+ .fd=fd,
+ .twait=timeout,
+ };
+ triton_md_register_handler(&h);
+ triton_md_enable_handler(&h,mode);
+ r=triton_md_wait(&h);
+ triton_md_unregister_handler(&h);
+ return r;
+}
+#endif
diff --git a/accel-pptpd/triton/options.c b/accel-pptpd/triton/options.c
new file mode 100644
index 00000000..ba7fc564
--- /dev/null
+++ b/accel-pptpd/triton/options.c
@@ -0,0 +1,46 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "triton_p.h"
+#include "conf_file.h"
+
+static struct conf_file_sect_t *sect=NULL;
+
+static const char* find_option(const char *name)
+{
+ struct option_t *opt;
+
+ if (!sect)
+ {
+ sect=conf_file_get_section("options");
+ if (!sect) return 0;
+ }
+
+ list_for_each_entry(opt,&sect->items,entry)
+ {
+ if (strcmp(opt->name,name)==0)
+ return opt->val;
+ }
+
+ return NULL;
+}
+int triton_get_int_option(const char *str)
+{
+ const char *val=find_option(str);
+ if (!val) return 0;
+
+ return atoi(val);
+}
+const char* triton_get_str_option(const char *str)
+{
+ const char *val=find_option(str);
+
+ return val;
+}
+double triton_get_double_option(const char *str)
+{
+ const char *val=find_option(str);
+ if (!val) return 0;
+
+ return atof(val);
+}
diff --git a/accel-pptpd/triton/timer.c b/accel-pptpd/triton/timer.c
new file mode 100644
index 00000000..2ea36cb0
--- /dev/null
+++ b/accel-pptpd/triton/timer.c
@@ -0,0 +1,244 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include "triton_p.h"
+
+static __thread struct list_head timers;
+static __thread struct list_head timers_ss;
+static __thread int in_timer;
+
+asm(".hidden timer_prepare");
+asm(".hidden timer_check");
+asm(".hidden timer_init");
+
+static void tv_add(struct timeval *tv,int msec);
+
+
+void timer_init(void)
+{
+ INIT_LIST_HEAD(&timers);
+ INIT_LIST_HEAD(&timers_ss);
+ in_timer=0;
+}
+
+void triton_timer_add(struct triton_timer_t*tt)
+{
+ struct timer_t *t=(struct timer_t *)malloc(sizeof(struct timer_t));
+
+ t->del=0;
+ t->timer=tt;
+ tt->active=1;
+
+ list_add_tail(&t->entry,&timers);
+}
+void triton_timer_del(struct triton_timer_t*tt)
+{
+ struct timer_t *t;
+
+ list_for_each_entry(t,&timers,entry)
+ {
+ if (t->timer==tt)
+ {
+ tt->active=0;
+ if (in_timer)
+ {
+ t->del=1;
+ }else
+ {
+ list_del(&t->entry);
+ free(t);
+ }
+ return;
+ }
+ }
+}
+void triton_timer_single_shot1(int twait,triton_ss_func func,int arg_cnt,...)
+{
+ struct timeval tv;
+ struct timer_single_shot_t *t=(struct timer_single_shot_t *)malloc(sizeof(struct timer_single_shot_t));
+
+ memset(t,0,sizeof(*t));
+
+ gettimeofday(&tv,NULL);
+
+ tv_add(&tv,twait);
+
+ t->ss_func=func;
+ t->expire_tv=tv;//(struct timeval){tv.tv_sec+twait/1000,tv.tv_usec+(twait%1000)*1000000};
+ if (arg_cnt)
+ {
+ va_list p;
+ va_start(p,arg_cnt);
+ t->arg_cnt=arg_cnt;
+ t->args=malloc(arg_cnt*sizeof(long));
+ #ifdef BROKEN_GCC
+ for(i=0; i<arg_cnt; i++)
+ *((long*)t->args+i)=va_arg(p,long);
+ #else
+ memcpy(t->args,p,arg_cnt*sizeof(long));
+ #endif
+ va_end(p);
+ }
+
+ list_add_tail(&t->entry,&timers_ss);
+}
+void triton_timer_single_shot2(struct timeval *tv,triton_ss_func func,int arg_cnt,...)
+{
+ struct timer_single_shot_t *t=(struct timer_single_shot_t *)malloc(sizeof(struct timer_single_shot_t));
+
+ memset(t,0,sizeof(*t));
+
+ t->ss_func=func;
+ t->expire_tv=*tv;//(struct timeval){tv.tv_sec+twait/1000,tv.tv_usec+(twait%1000)*1000000};
+ if (arg_cnt)
+ {
+ va_list p;
+ va_start(p,arg_cnt);
+ t->arg_cnt=arg_cnt;
+ t->args=malloc(arg_cnt*sizeof(long));
+ #ifdef BROKEN_GCC
+ for(i=0; i<arg_cnt; i++)
+ *((long*)t->args+i)=va_arg(p,long);
+ #else
+ memcpy(t->args,p,arg_cnt*sizeof(long));
+ #endif
+ va_end(p);
+ }
+
+ list_add_tail(&t->entry,&timers_ss);
+}
+void triton_timer_single_shot3(int tv_sec,int tv_usec,triton_ss_func func,int arg_cnt,...)
+{
+ struct timer_single_shot_t *t=(struct timer_single_shot_t *)malloc(sizeof(struct timer_single_shot_t));
+
+ memset(t,0,sizeof(*t));
+
+ t->ss_func=func;
+ t->expire_tv.tv_sec=tv_sec;
+ t->expire_tv.tv_usec=tv_usec;
+ if (arg_cnt)
+ {
+ va_list p;
+ va_start(p,arg_cnt);
+ t->arg_cnt=arg_cnt;
+ t->args=malloc(arg_cnt*sizeof(long));
+ #ifdef BROKEN_GCC
+ for(i=0; i<arg_cnt; i++)
+ *((int*)t->args+i)=va_arg(p,long);
+ #else
+ memcpy(t->args,p,arg_cnt*sizeof(long));
+ #endif
+ va_end(p);
+ }
+
+ list_add_tail(&t->entry,&timers_ss);
+}
+
+int timer_prepare(struct timeval *tv)
+{
+ struct timer_t *t;
+ struct timer_single_shot_t *ss_t;
+
+ int twait=-1,twait0;
+
+ list_for_each_entry(t,&timers,entry)
+ {
+ twait0=(t->timer->expire_tv.tv_sec-tv->tv_sec)*1000+
+ (t->timer->expire_tv.tv_usec-tv->tv_usec)/1000;
+ if (twait0<0) twait0=0;
+ if (twait0>=0 && (twait==-1 || twait0<twait))
+ twait=twait0;
+ }
+
+ if (twait)
+ {
+ list_for_each_entry(ss_t,&timers_ss,entry)
+ {
+ twait0=(ss_t->expire_tv.tv_sec-tv->tv_sec)*1000+
+ (ss_t->expire_tv.tv_usec-tv->tv_usec)/1000;
+ if (twait0<0) twait0=0;
+ if (twait0>=0 && (twait==-1 || twait0<twait))
+ twait=twait0;
+ }
+ }
+
+ return twait;
+}
+
+
+void timer_check(struct timeval *tv)
+{
+ struct timer_t *t;
+ struct timer_single_shot_t *ss_t;
+ struct list_head *p1,*p2;
+ int twait0;
+
+ in_timer=1;
+
+ list_for_each_safe(p1,p2,&timers)
+ {
+ t=list_entry(p1,struct timer_t,entry);
+ if (t->del) continue;
+ twait0=(t->timer->expire_tv.tv_sec-tv->tv_sec)*1000+
+ (t->timer->expire_tv.tv_usec-tv->tv_usec)/1000;
+ if (twait0<=0)
+ {
+ if (!t->timer->expire(t->timer))
+ {
+ t->timer->active=0;
+ list_del(&t->entry);
+ free(t);
+ continue;
+ }
+ if (t->timer->period)
+ {
+ tv_add(&t->timer->expire_tv,t->timer->period);
+ }
+ }
+ }
+
+ list_for_each_safe(p1,p2,&timers_ss)
+ {
+ ss_t=list_entry(p1,struct timer_single_shot_t,entry);
+ twait0=(ss_t->expire_tv.tv_sec-tv->tv_sec)*1000+
+ (ss_t->expire_tv.tv_usec-tv->tv_usec)/1000;
+ if (twait0<=0)
+ {
+ list_del(&ss_t->entry);
+ if (ss_t->arg_cnt)
+ {
+ //args_p=&ss_t->args;
+ //memcpy(pp+ARG_OFFSET,ss_t->args,ss_t->arg_cnt*sizeof(int));
+ //__builtin_apply(ss_t->ss_func,pp,ARG_OFFSET+ss_t->arg_cnt*sizeof(int));
+ dyn_call(ss_t->ss_func,ss_t->arg_cnt,ss_t->args);
+ free(ss_t->args);
+ }else ss_t->ss_func();
+ free(ss_t);
+ }
+ }
+
+ list_for_each_safe(p1,p2,&timers)
+ {
+ t=list_entry(p1,struct timer_t,entry);
+ if (t->del)
+ {
+ list_del(&t->entry);
+ t->timer->active=0;
+ free(t);
+ }
+ }
+ in_timer=0;
+}
+
+static void tv_add(struct timeval *tv,int msec)
+{
+ tv->tv_sec+=msec/1000;
+ tv->tv_usec+=(msec%1000)*1000;
+ if (tv->tv_usec>=1000000)
+ {
+ tv->tv_sec++;
+ tv->tv_usec-=1000000;
+ }
+}
diff --git a/accel-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h
new file mode 100644
index 00000000..b726076e
--- /dev/null
+++ b/accel-pptpd/triton/triton.h
@@ -0,0 +1,78 @@
+#ifndef TRITON_H
+#define TRITON_H
+
+#include <sys/time.h>
+
+struct triton_md_handler_t
+{
+ int fd;
+ int twait;
+ void *pd;
+
+ void (*read)(struct triton_md_handler_t *h);
+ void (*write)(struct triton_md_handler_t *h);
+ void (*timeout)(struct triton_md_handler_t *h);
+};
+
+#define MD_MODE_READ 1
+#define MD_MODE_WRITE 2
+void triton_md_register_handler(struct triton_md_handler_t *h);
+void triton_md_unregister_handler(struct triton_md_handler_t *h);
+void triton_md_enable_handler(struct triton_md_handler_t *h, int mode);
+void triton_md_disable_handler(struct triton_md_handler_t *h,int mode);
+int triton_md_wait(struct triton_md_handler_t *h);
+int triton_md_wait2(int fd,int mode,int timeout);
+
+struct triton_timer_t
+{
+ struct timeval expire_tv;
+ int period;
+ void *pd;
+ int active;
+
+ int (*expire)(struct triton_timer_t*);
+};
+
+void triton_timer_add(struct triton_timer_t*);
+void triton_timer_del(struct triton_timer_t*);
+
+typedef void (*triton_ss_func)(void);
+void triton_timer_single_shot1(int twait,triton_ss_func,int argc,...);
+void triton_timer_single_shot2(struct timeval *shot_tv,triton_ss_func,int argc,...);
+void triton_timer_single_shot3(int tv_sec,int tv_usec,triton_ss_func,int argc,...);
+
+typedef void (*triton_event_func)(void);
+void triton_event_register_handler(int ev_id,triton_event_func,int argc,...);
+void triton_event_unregister_handler(int ev_id,triton_event_func);
+void triton_event_fire(int ev_id,int argc,...);
+
+int triton_get_int_option(const char *str);
+const char* triton_get_str_option(const char *str);
+double triton_get_double_option(const char *str);
+
+void triton_terminate(void);
+void triton_process_events(void);
+
+#ifdef USE_CORO
+#define DEF_COROUTINE_STACK 64*1024
+typedef void (*triton_coroutine_func)(void*);
+long int triton_coroutine_create(int stack_size,triton_coroutine_func func,void *arg,int run);
+void triton_coroutine_delete(long int id);
+void triton_coroutine_wakeup(long int id);
+void triton_coroutine_schedule();
+int triton_coroutine_schedule_timeout(int msec);
+#endif
+
+#define TRITON_OK 0
+#define TRITON_ERR_NOCOMP -1
+#define TRITON_ERR_NOSUPP -2
+#define TRITON_ERR_NOINTF -3
+#define TRITON_ERR_EXISTS -4
+#define TRITON_ERR_NOCHAN -5
+#define TRITON_ERR_NOMSG -6
+#define TRITON_ERR_BUSY -5
+
+int triton_init(const char *conf_file);
+int triton_run(int (*post_init)(void*),void *arg);
+
+#endif
diff --git a/accel-pptpd/triton/triton_p.h b/accel-pptpd/triton/triton_p.h
new file mode 100644
index 00000000..0602bfa0
--- /dev/null
+++ b/accel-pptpd/triton/triton_p.h
@@ -0,0 +1,140 @@
+#ifndef TRITON_P_H
+#define TRITON_P_H
+
+#include "triton.h"
+#include "list.h"
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+#define MAX_ARGS 32
+
+struct option_t
+{
+ struct list_head entry;
+
+ char *name;
+ char *val;
+};
+
+struct md_handler_t
+{
+ struct list_head entry;
+
+ int fd;
+ int del;
+ int timeout;
+ int volatile in_handler;
+
+ struct coroutine_t *coro;
+
+ struct triton_md_handler_t *handler;
+};
+
+struct timer_t
+{
+ struct list_head entry;
+ int del;
+ struct triton_timer_t *timer;
+};
+
+struct timer_single_shot_t
+{
+ struct list_head entry;
+
+ struct timeval expire_tv;
+ int arg_cnt;
+ void *args;
+ triton_ss_func ss_func;
+};
+
+struct event_handler_t
+{
+ struct list_head entry;
+
+ int arg_cnt;
+ void *args;
+ triton_event_func event_func;
+};
+struct event_t
+{
+ struct list_head entry;
+
+ int ev_id;
+ struct list_head handlers;
+};
+
+struct coroutine_t
+{
+ struct list_head entry;
+ ucontext_t uc;
+ struct timeval timeout;
+ struct timeval time;
+};
+
+
+extern struct list_head components;
+extern void md_run();
+extern void md_terminate();
+extern int timer_prepare(struct timeval *tv);
+extern void timer_check(struct timeval *tv);
+extern int coroutine_get_timeout(struct timeval *tv);
+extern void coroutine_check_timeout(struct timeval *tv);
+extern void event_init();
+extern struct coroutine_t *current_coro;
+void schedule(void);
+
+//#define BROKEN_GCC
+
+#ifdef BROKEN_GCC
+#define dyn_call(func,arg_cnt,args)\
+{\
+ switch(arg_cnt)\
+ {\
+ case 0: \
+ {\
+ typedef void (*func0)(void);\
+ ((func0)func)();\
+ break;\
+ }\
+ case 1: \
+ {\
+ typedef void (*func0)(long);\
+ ((func0)func)(*((long*)args+0));\
+ break;\
+ }\
+ case 2: \
+ {\
+ typedef void (*func0)(long,long);\
+ ((func0)func)(*((long*)args+0),*((long*)args+1));\
+ break;\
+ }\
+ case 3: \
+ {\
+ typedef void (*func0)(long,long,long);\
+ ((func0)func)(*((long*)args+0),*((long*)args+1),*((long*)args+2));\
+ break;\
+ }\
+ case 4: \
+ {\
+ typedef void (*func0)(long,long,long,long);\
+ ((func0)func)(*((long*)args+0),*((long*)args+1),*((long*)args+2),*((long*)args+3));\
+ break;\
+ }\
+ }\
+}
+#else
+#define dyn_call(func,arg_cnt,args)\
+{\
+ int aaa=arg_cnt*sizeof(long);\
+ asm("subl %2,%%esp; \n\
+ movl %%esp,%%edi;\n\
+ movl %0,%%esi;\n\
+ cld;\n\
+ rep movsl;\n\
+ call *%1;\n\
+ addl %2,%%esp\n"::"m" (args),"m" (func),"g" (aaa),"c"(arg_cnt):"%edi","%esi","%esp");\
+}
+#endif
+
+#endif