summaryrefslogtreecommitdiff
path: root/accel-pptpd/ctrl
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pptpd/ctrl')
-rw-r--r--accel-pptpd/ctrl/CMakeLists.txt12
-rw-r--r--accel-pptpd/ctrl/l2tp/CMakeLists.txt11
-rw-r--r--accel-pptpd/ctrl/l2tp/attr_defs.h73
-rw-r--r--accel-pptpd/ctrl/l2tp/dict.c271
-rw-r--r--accel-pptpd/ctrl/l2tp/dict/dictionary2
-rw-r--r--accel-pptpd/ctrl/l2tp/dict/dictionary.rfc266155
-rw-r--r--accel-pptpd/ctrl/l2tp/dict/dictionary.rfc393115
-rw-r--r--accel-pptpd/ctrl/l2tp/dict2c.py20
-rw-r--r--accel-pptpd/ctrl/l2tp/l2tp.c732
-rw-r--r--accel-pptpd/ctrl/l2tp/l2tp.h84
-rw-r--r--accel-pptpd/ctrl/l2tp/l2tp_prot.h55
-rw-r--r--accel-pptpd/ctrl/l2tp/packet.c457
-rw-r--r--accel-pptpd/ctrl/pppoe/CMakeLists.txt5
-rw-r--r--accel-pptpd/ctrl/pppoe/pppoe.c (renamed from accel-pptpd/ctrl/pppoe.c)104
-rw-r--r--accel-pptpd/ctrl/pppoe/pppoe.h (renamed from accel-pptpd/ctrl/pppoe.h)0
-rw-r--r--accel-pptpd/ctrl/pptp/CMakeLists.txt5
-rw-r--r--accel-pptpd/ctrl/pptp/pptp.c (renamed from accel-pptpd/ctrl/pptp.c)0
-rw-r--r--accel-pptpd/ctrl/pptp/pptp_prot.h (renamed from accel-pptpd/ctrl/pptp_prot.h)0
18 files changed, 1844 insertions, 57 deletions
diff --git a/accel-pptpd/ctrl/CMakeLists.txt b/accel-pptpd/ctrl/CMakeLists.txt
index d63a825..fa7acdc 100644
--- a/accel-pptpd/ctrl/CMakeLists.txt
+++ b/accel-pptpd/ctrl/CMakeLists.txt
@@ -1,9 +1,3 @@
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
-
-ADD_LIBRARY(pptp SHARED pptp.c)
-ADD_LIBRARY(pppoe SHARED pppoe.c)
-
-INSTALL(TARGETS pptp pppoe
- LIBRARY DESTINATION usr/lib/accel-pptp
-)
-
+ADD_SUBDIRECTORY(pptp)
+ADD_SUBDIRECTORY(pppoe)
+#ADD_SUBDIRECTORY(l2tp)
diff --git a/accel-pptpd/ctrl/l2tp/CMakeLists.txt b/accel-pptpd/ctrl/l2tp/CMakeLists.txt
new file mode 100644
index 0000000..8a64d5f
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/CMakeLists.txt
@@ -0,0 +1,11 @@
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/usr/share/accel-pptp/l2tp/dictionary")
+
+ADD_LIBRARY(l2tp SHARED
+ l2tp.c
+ dict.c
+ packet.c
+)
+
+INSTALL(TARGETS l2tp LIBRARY DESTINATION usr/lib/accel-pptp)
diff --git a/accel-pptpd/ctrl/l2tp/attr_defs.h b/accel-pptpd/ctrl/l2tp/attr_defs.h
new file mode 100644
index 0000000..e799157
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/attr_defs.h
@@ -0,0 +1,73 @@
+#ifndef __ATTR_DEFS_H
+#define __ATTR_DEFS_H
+
+#define Message_Type 0
+#define Random_Vector 36
+#define Result_Code 1
+#define Protocol_Version 2
+#define Framing_Capabilities 3
+#define Bearer_Capabilities 4
+#define Tie_Breaker 5
+#define Firmware_Revision 6
+#define Host_Name 7
+#define Vendor_Name 8
+#define Assigned_Tunnel_ID 9
+#define Recv_Window_Size 10
+#define Challenge 11
+#define Challenge_Response 13
+#define Cause_Code 12
+#define Assigned_Session_ID 14
+#define Call_Serial_Number 15
+#define Minimum_BPS 16
+#define Maximum_BPS 17
+#define Bearer_Type 18
+#define Framing_Type 19
+#define Called_Number 21
+#define Calling_Number 22
+#define Sub_Address 23
+#define TX_Speed 24
+#define RX_Speed 38
+#define Physical_Channel_ID 25
+#define Private_Group_ID 37
+#define Sequencing_Required 39
+#define Init_Recv_LCP 26
+#define Last_Sent_LCP 27
+#define Last_Recv_LCP 28
+#define Proxy_Authen_Type 29
+#define Proxy_Authen_Name 30
+#define Proxy_Authen_Challenge 31
+#define Proxy_Authen_ID 32
+#define Proxy_Authen_Response 33
+#define Call_Errors 34
+#define ACCM 35
+#define Message_Type_Start_Ctrl_Conn_Request 1
+#define Message_Type_Start_Ctrl_Conn_Reply 2
+#define Message_Type_Start_Ctrl_Conn_Connected 3
+#define Message_Type_Stop_Ctrl_Conn_Notify 4
+#define Message_Type_Hello 6
+#define Message_Type_Outgoing_Call_Request 7
+#define Message_Type_Outgoing_Call_Reply 8
+#define Message_Type_Outgoing_Call_Connected 9
+#define Message_Type_Incoming_Call_Request 10
+#define Message_Type_Incoming_Call_Reply 11
+#define Message_Type_Incoming_Call_Connected 12
+#define Message_Type_Call_Disconnect_Notify 14
+#define Message_Type_WAN_Error_Notify 15
+#define Message_Type_Set_Link_Info 16
+#define Message_Digest 59
+#define Router_ID 60
+#define Assigned_Connection_ID 61
+#define Pseudowire_Capabilities 62
+#define Prefered_Language 72
+#define Local_Session_ID 63
+#define Remote_Session_ID 64
+#define Assigned_Cookie 65
+#define Remote_End_ID 66
+#define Pseudowire_Type 68
+#define L2_Specific_Sublayer 69
+#define Data_Sequencing 70
+#define TX_Connect_Speeed 74
+#define RX_Connect_Speeed 75
+#define Circuit_Status 71
+
+#endif
diff --git a/accel-pptpd/ctrl/l2tp/dict.c b/accel-pptpd/ctrl/l2tp/dict.c
new file mode 100644
index 0000000..a0ca999
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/dict.c
@@ -0,0 +1,271 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "list.h"
+#include "l2tp.h"
+#include "log.h"
+#include "triton.h"
+
+#include "memdebug.h"
+
+struct l2tp_dict_t
+{
+ struct list_head items;
+};
+
+static struct l2tp_dict_t *dict;
+
+#define BUF_SIZE 1024
+static char *path, *fname1, *buf;
+
+struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_name(const char *name)
+{
+ struct l2tp_dict_attr_t *attr;
+
+ list_for_each_entry(attr, &dict->items, entry) {
+ if (!strcmp(attr->name, name))
+ return attr;
+ }
+
+ return NULL;
+}
+
+struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_id(int id)
+{
+ struct l2tp_dict_attr_t *attr;
+
+ list_for_each_entry(attr, &dict->items, entry) {
+ if (attr->id == id)
+ return attr;
+ }
+
+ return NULL;
+}
+
+struct l2tp_dict_value_t *l2tp_dict_find_value(struct l2tp_dict_attr_t *attr, l2tp_value_t val)
+{
+ struct l2tp_dict_value_t *v;
+
+ list_for_each_entry(v, &attr->values, entry) {
+ switch (attr->type) {
+ case ATTR_TYPE_INT16:
+ if (v->val.int16 == val.int16)
+ return v;
+ break;
+ case ATTR_TYPE_INT32:
+ if (v->val.int32 == val.int32)
+ return v;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static char *skip_word(char *ptr)
+{
+ for(; *ptr; ptr++)
+ if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
+ break;
+ return ptr;
+}
+
+static char *skip_space(char *ptr)
+{
+ for(; *ptr; ptr++)
+ if (*ptr != ' ' && *ptr != '\t')
+ break;
+ return ptr;
+}
+
+static int split(char *buf, char **ptr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ buf = skip_word(buf);
+ if (!*buf)
+ return i;
+
+ *buf = 0;
+
+ buf = skip_space(buf + 1);
+ if (!*buf)
+ return i;
+
+ ptr[i] = buf;
+ }
+
+ buf = skip_word(buf);
+ //if (*buf == '\n')
+ *buf = 0;
+ //else if (*buf)
+ // return -1;
+
+ return i;
+}
+
+
+static int dict_load(const char *fname)
+{
+ FILE *f;
+ char *ptr[6], *endptr;
+ struct l2tp_dict_attr_t *attr;
+ struct l2tp_dict_value_t *value;
+ struct list_head *items;
+ int r, n, i;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ log_emerg("l2tp: open '%s': %s\n", fname, strerror(errno));
+ return -1;
+ }
+
+ items = &dict->items;
+ while (fgets(buf, BUF_SIZE, f)) {
+ n++;
+ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == 0)
+ continue;
+
+ r = split(buf, ptr);
+
+ if (!strcmp(buf, "$INCLUDE")) {
+ if (r != 1)
+ goto out_syntax;
+
+ for (i = strlen(path) - 1; i; i--) {
+ if (path[i] == '/') {
+ path[i + 1] = 0;
+ break;
+ }
+ }
+
+ strcpy(fname1, path);
+ strcat(fname1, ptr[0]);
+
+ if (dict_load(fname1))
+ goto out_err;
+ } else if (!strcmp(buf, "ATTRIBUTE")) {
+ if (r < 3)
+ goto out_syntax;
+
+ attr = malloc(sizeof(*attr));
+ memset(attr, 0, sizeof(*attr));
+ list_add_tail(&attr->entry, items);
+ INIT_LIST_HEAD(&attr->values);
+
+ attr->name = strdup(ptr[0]);
+ attr->id = strtol(ptr[1], &endptr, 10);
+ if (*endptr != 0)
+ goto out_syntax;
+
+ if (!strcmp(ptr[2], "none"))
+ attr->type = ATTR_TYPE_NONE;
+ else if (!strcmp(ptr[2], "int16"))
+ attr->type = ATTR_TYPE_INT16;
+ else if (!strcmp(ptr[2], "int32"))
+ attr->type = ATTR_TYPE_INT32;
+ else if (!strcmp(ptr[2], "int64"))
+ attr->type = ATTR_TYPE_INT64;
+ else if (!strcmp(ptr[2], "octets"))
+ attr->type = ATTR_TYPE_OCTETS;
+ else if (!strcmp(ptr[2], "string"))
+ attr->type = ATTR_TYPE_STRING;
+ else
+ goto out_syntax;
+
+ attr->M = -1;
+ attr->H = -1;
+
+ for (i = 3; i < r; i++) {
+ if (!strcmp(ptr[i], "M=0"))
+ attr->M = 0;
+ else if (!strcmp(ptr[i], "M=1"))
+ attr->M = 1;
+ else if (!strcmp(ptr[i], "H=0"))
+ attr->H = 0;
+ else if (!strcmp(ptr[i], "H=1"))
+ attr->H = 1;
+ else
+ goto out_syntax;
+ }
+ } else if (!strcmp(buf, "VALUE")) {
+ if (r != 3)
+ goto out_syntax;
+
+ attr = l2tp_dict_find_attr_by_name(ptr[0]);
+ if (!attr) {
+ log_emerg("l2tp:%s:%i: attribute not found\n", fname, n);
+ goto out_err;
+ }
+
+ value = malloc(sizeof(*value));
+ memset(value, 0, sizeof(*value));
+ list_add_tail(&value->entry, &attr->values);
+
+ value->name = strdup(ptr[1]);
+ switch (attr->type) {
+ case ATTR_TYPE_INT16:
+ case ATTR_TYPE_INT32:
+ value->val.int16 = strtol(ptr[2], &endptr, 10);
+ if (*endptr != 0)
+ goto out_syntax;
+ break;
+ case ATTR_TYPE_STRING:
+ value->val.string = strdup(ptr[2]);
+ break;
+ }
+ } else
+ goto out_syntax;
+ }
+
+ fclose(f);
+
+ return 0;
+
+out_syntax:
+ log_emerg("l2tp:%s:%i: syntaxis error\n", fname, n);
+out_err:
+ fclose(f);
+ return -1;
+}
+
+static int l2tp_dict_load(const char *fname)
+{
+ int r;
+
+ dict = _malloc(sizeof(*dict));
+ memset(dict, 0, sizeof(*dict));
+ INIT_LIST_HEAD(&dict->items);
+
+ path = _malloc(PATH_MAX);
+ fname1 = _malloc(PATH_MAX);
+ buf = _malloc(BUF_SIZE);
+
+ strcpy(path, fname);
+
+ r = dict_load(fname);
+
+ _free(buf);
+ _free(fname1);
+ _free(path);
+
+ return r;
+}
+
+static void __init dict_init(void)
+{
+ char *opt;
+
+ opt = conf_get_opt("l2tp", "dictionary");
+ if (!opt)
+ opt = DICTIONARY;
+
+ if (l2tp_dict_load(opt))
+ _exit(EXIT_FAILURE);
+}
+
diff --git a/accel-pptpd/ctrl/l2tp/dict/dictionary b/accel-pptpd/ctrl/l2tp/dict/dictionary
new file mode 100644
index 0000000..f5d7c42
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/dict/dictionary
@@ -0,0 +1,2 @@
+$INCLUDE dictionary.rfc2661
+$INCLUDE dictionary.rfc3931
diff --git a/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661 b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661
new file mode 100644
index 0000000..434b55d
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc2661
@@ -0,0 +1,55 @@
+ATTRIBUTE Message-Type 0 int16 H=0
+ATTRIBUTE Random-Vector 36 octets M=1 H=0
+ATTRIBUTE Result-Code 1 octets M=1 H=0
+ATTRIBUTE Protocol-Version 2 int16 M=1 H=0
+ATTRIBUTE Framing-Capabilities 3 int32 M=1
+ATTRIBUTE Bearer-Capabilities 4 int32 M=1
+ATTRIBUTE Tie-Breaker 5 int64 M=1
+ATTRIBUTE Firmware-Revision 6 int16 M=0
+ATTRIBUTE Host-Name 7 string M=1
+ATTRIBUTE Vendor-Name 8 string M=0
+ATTRIBUTE Assigned-Tunnel-ID 9 int16 M=1
+ATTRIBUTE Recv-Window-Size 10 int16 M=1
+ATTRIBUTE Challenge 11 octets M=1
+ATTRIBUTE Challenge-Response 13 octets M=1
+ATTRIBUTE Cause-Code 12 int32 M=1 H=0
+ATTRIBUTE Assigned-Session-ID 14 int16 M=1
+ATTRIBUTE Call-Serial-Number 15 int32 M=1
+ATTRIBUTE Minimum-BPS 16 int32 M=1
+ATTRIBUTE Maximum-BPS 17 int32 M=1
+ATTRIBUTE Bearer-Type 18 int32 M=1
+ATTRIBUTE Framing-Type 19 int32 M=1
+ATTRIBUTE Called-Number 21 string M=1
+ATTRIBUTE Calling-Number 22 string M=1
+ATTRIBUTE Sub-Address 23 string M=1
+ATTRIBUTE TX-Speed 24 int32 M=1
+ATTRIBUTE RX-Speed 38 int32 M=1
+ATTRIBUTE Physical-Channel-ID 25 int32 M=0
+ATTRIBUTE Private-Group-ID 37 int32 M=0
+ATTRIBUTE Sequencing-Required 39 none M=1 H=0
+ATTRIBUTE Init-Recv-LCP 26 octets M=0
+ATTRIBUTE Last-Sent-LCP 27 octets M=0
+ATTRIBUTE Last-Recv-LCP 28 octets M=0
+ATTRIBUTE Proxy-Authen-Type 29 int16 M=0
+ATTRIBUTE Proxy-Authen-Name 30 string M=0
+ATTRIBUTE Proxy-Authen-Challenge 31 octets M=0
+ATTRIBUTE Proxy-Authen-ID 32 int16 M=0
+ATTRIBUTE Proxy-Authen-Response 33 octets M=0
+ATTRIBUTE Call-Errors 34 octets M=1
+ATTRIBUTE ACCM 35 octets M=1
+
+VALUE Message-Type Start-Ctrl-Conn-Request 1
+VALUE Message-Type Start-Ctrl-Conn-Reply 2
+VALUE Message-Type Start-Ctrl-Conn-Connected 3
+VALUE Message-Type Stop-Ctrl-Conn-Notify 4
+VALUE Message-Type Hello 6
+VALUE Message-Type Outgoing-Call-Request 7
+VALUE Message-Type Outgoing-Call-Reply 8
+VALUE Message-Type Outgoing-Call-Connected 9
+VALUE Message-Type Incoming-Call-Request 10
+VALUE Message-Type Incoming-Call-Reply 11
+VALUE Message-Type Incoming-Call-Connected 12
+VALUE Message-Type Call-Disconnect-Notify 14
+VALUE Message-Type WAN-Error-Notify 15
+VALUE Message-Type Set-Link-Info 16
+
diff --git a/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931 b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931
new file mode 100644
index 0000000..d6ad410
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/dict/dictionary.rfc3931
@@ -0,0 +1,15 @@
+ATTRIBUTE Message-Digest 59 octets M=1 H=0
+ATTRIBUTE Router-ID 60 int32 H=0
+ATTRIBUTE Assigned-Connection-ID 61 int32
+ATTRIBUTE Pseudowire-Capabilities 62 octets
+ATTRIBUTE Prefered-Language 72 octets
+ATTRIBUTE Local-Session-ID 63 int32
+ATTRIBUTE Remote-Session-ID 64 int32
+ATTRIBUTE Assigned-Cookie 65 octets
+ATTRIBUTE Remote-End-ID 66 octets
+ATTRIBUTE Pseudowire-Type 68 int16
+ATTRIBUTE L2-Specific-Sublayer 69 int16
+ATTRIBUTE Data-Sequencing 70 int16
+ATTRIBUTE TX-Connect-Speeed 74 int64
+ATTRIBUTE RX-Connect-Speeed 75 int64
+ATTRIBUTE Circuit-Status 71 int16
diff --git a/accel-pptpd/ctrl/l2tp/dict2c.py b/accel-pptpd/ctrl/l2tp/dict2c.py
new file mode 100644
index 0000000..ff0961e
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/dict2c.py
@@ -0,0 +1,20 @@
+import sys,re
+
+hdr = file(sys.argv[2],'w')
+
+def process(fname, hdr):
+ for line in file(fname):
+ if line[:-1].strip() == '':
+ continue
+ if line[0] == '#':
+ continue
+ f = re.compile('[$.a-zA-Z0-9\-]+').findall(line)
+ if f[0] == 'ATTRIBUTE' or f[0] == 'VENDOR':
+ hdr.write('#define {0} {1}\n'.format(f[1].replace('-','_').replace('.','_'), f[2]))
+ elif f[0] == 'VALUE':
+ hdr.write('#define {0}_{1} {2}\n'.format(f[1].replace('-','_').replace('.','_'), f[2].replace('-','_'),f[3]))
+ elif f[0] == '$INCLUDE':
+ process(f[1], hdr)
+
+if __name__ == '__main__':
+ process(sys.argv[1], hdr)
diff --git a/accel-pptpd/ctrl/l2tp/l2tp.c b/accel-pptpd/ctrl/l2tp/l2tp.c
new file mode 100644
index 0000000..7548411
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/l2tp.c
@@ -0,0 +1,732 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "triton.h"
+#include "mempool.h"
+#include "log.h"
+#include "ppp.h"
+#include "events.h"
+#include "utils.h"
+
+#include "memdebug.h"
+
+#include "l2tp.h"
+#include "attr_defs.h"
+
+#define STATE_WAIT_SCCCN 1
+#define STATE_WAIT_OCRQ 2
+#define STATE_WAIT_OCCN 3
+#define STATE_PPP 4
+#define STATE_CLOSE 0
+
+int conf_verbose = 0;
+int conf_timeout = 5;
+int conf_retransmit = 5;
+const char *conf_host_name = "accel-pptp";
+
+struct l2tp_serv_t
+{
+ struct triton_context_t ctx;
+ struct triton_md_handler_t hnd;
+ struct sockaddr_in addr;
+};
+
+struct l2tp_conn_t
+{
+ struct triton_context_t ctx;
+ struct triton_timer_t timeout_timer;
+ struct triton_timer_t echo_timer;
+
+ pthread_mutex_t lock;
+
+ int sock;
+ struct sockaddr_in addr;
+ uint16_t tid;
+ uint16_t sid;
+ uint16_t peer_tid;
+ uint16_t peer_sid;
+ uint32_t framing_cap;
+
+ struct l2tp_packet_t *last_pack;
+ int retransmit;
+ uint16_t Ns, Nr;
+ struct list_head recv_queue;
+ struct list_head send_queue;
+
+ int state;
+
+ struct ppp_ctrl_t ctrl;
+ struct ppp_t ppp;
+};
+
+static pthread_mutex_t l2tp_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct l2tp_conn_t **l2tp_conn;
+static uint16_t l2tp_tid;
+
+static mempool_t l2tp_conn_pool;
+
+static void l2tp_timeout(struct triton_timer_t *t);
+static void l2tp_send_SCCRP(struct l2tp_conn_t *conn);
+static void l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack);
+
+static struct l2tp_conn_t *l2tp_conn_lookup(uint16_t tid)
+{
+ struct l2tp_conn_t *conn;
+ pthread_mutex_lock(&conn->lock);
+ conn = l2tp_conn[tid];
+ if (conn)
+ pthread_mutex_lock(&conn->lock);
+ pthread_mutex_unlock(&conn->lock);
+
+ return conn;
+}
+
+static void l2tp_disconnect(struct l2tp_conn_t *conn)
+{
+ close(conn->sock);
+
+ if (conn->timeout_timer.tpd)
+ triton_timer_del(&conn->timeout_timer);
+
+ if (conn->echo_timer.tpd)
+ triton_timer_del(&conn->echo_timer);
+
+ if (conn->state == STATE_PPP) {
+ conn->state = STATE_CLOSE;
+ ppp_terminate(&conn->ppp, 1);
+ }
+
+ pthread_mutex_lock(&l2tp_lock);
+ pthread_mutex_lock(&conn->lock);
+ l2tp_conn[conn->tid] = NULL;
+ pthread_mutex_unlock(&l2tp_lock);
+ pthread_mutex_unlock(&conn->lock);
+
+ triton_event_fire(EV_CTRL_FINISHED, &conn->ppp);
+
+ if (conf_verbose)
+ log_ppp_info("disconnected\n");
+
+ triton_context_unregister(&conn->ctx);
+
+ if (conn->last_pack)
+ l2tp_packet_free(conn->last_pack);
+
+ if (conn->ppp.chan_name)
+ _free(conn->ppp.chan_name);
+
+ _free(conn->ctrl.calling_station_id);
+ _free(conn->ctrl.called_station_id);
+
+ mempool_free(conn);
+}
+
+static void l2tp_terminate(struct l2tp_conn_t *conn, int res, int err)
+{
+ struct l2tp_packet_t *pack;
+ struct l2tp_avp_result_code rc = {res, err};
+
+ pack = l2tp_packet_alloc(2, Message_Type_Stop_Ctrl_Conn_Notify, &conn->addr);
+ if (!pack) {
+ l2tp_disconnect(conn);
+ return;
+ }
+
+ if (l2tp_packet_add_int16(pack, Assigned_Tunnel_ID, conn->tid))
+ goto out_err;
+ if (l2tp_packet_add_octets(pack, Result_Code, (uint8_t *)&rc, sizeof(rc)))
+ goto out_err;
+
+ l2tp_send(conn, pack);
+
+ return;
+
+out_err:
+ l2tp_packet_free(pack);
+ l2tp_disconnect(conn);
+}
+
+static void l2tp_alloc(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, struct l2tp_attr_t *assigned_tid, struct l2tp_attr_t *framing_cap)
+{
+ struct l2tp_conn_t *conn;
+ uint16_t tid;
+
+ conn = mempool_alloc(l2tp_conn_pool);
+ if (!conn) {
+ log_emerg("l2tp: out of memory\n");
+ return;
+ }
+
+ memset(conn, 0, sizeof(*conn));
+
+ pthread_mutex_lock(&l2tp_lock);
+ for (tid = l2tp_tid + 1; tid != l2tp_tid; tid++) {
+ if (tid == L2TP_MAX_TID)
+ tid = 1;
+ if (!l2tp_conn[tid]) {
+ l2tp_conn[tid] = conn;
+ conn->tid = tid;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&l2tp_lock);
+
+ if (!conn->tid) {
+ if (conf_verbose)
+ log_warn("l2tp: no free tid available\n");
+ mempool_free(conn);
+ return;
+ }
+
+ INIT_LIST_HEAD(&conn->recv_queue);
+ INIT_LIST_HEAD(&conn->send_queue);
+
+ conn->sock = dup(serv->hnd.fd);
+ memcpy(&conn->addr, &pack->addr, sizeof(pack->addr));
+ conn->peer_tid = assigned_tid->val.uint16;
+ conn->framing_cap = framing_cap->val.uint32;
+
+ conn->timeout_timer.expire = l2tp_timeout;
+ conn->timeout_timer.period = conf_timeout * 1000;
+ conn->ctrl.ctx = &conn->ctx;
+ conn->ctrl.name = "l2tp";
+
+ conn->ctrl.calling_station_id = _malloc(17);
+ conn->ctrl.called_station_id = _malloc(17);
+ u_inet_ntoa(conn->addr.sin_addr.s_addr, conn->ctrl.calling_station_id);
+ u_inet_ntoa(serv->addr.sin_addr.s_addr, conn->ctrl.called_station_id);
+
+ ppp_init(&conn->ppp);
+ conn->ppp.ctrl = &conn->ctrl;
+
+ triton_context_register(&conn->ctx, &conn->ppp);
+ triton_context_wakeup(&conn->ctx);
+
+ if (conf_verbose) {
+ log_switch(&conn->ctx, &conn->ppp);
+ log_ppp_info("recv ");
+ l2tp_packet_print(pack);
+ }
+
+ triton_context_call(&conn->ctx, (triton_event_func)l2tp_send_SCCRP, conn);
+}
+
+static int l2tp_connect(struct l2tp_conn_t *conn)
+{
+
+ return 0;
+}
+
+static void l2tp_timeout(struct triton_timer_t *t)
+{
+ struct l2tp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer);
+ struct l2tp_packet_t *pack;
+
+ if (!list_empty(&conn->send_queue)) {
+ log_ppp_debug("l2tp: retransmit (%i)\n", conn->retransmit);
+ if (++conn->retransmit <= conf_retransmit) {
+ pack = list_entry(conn->send_queue.next, typeof(*pack), entry);
+ pack->hdr.Nr = htons(conn->Nr + 1);
+ if (conf_verbose) {
+ log_ppp_info("send ");
+ l2tp_packet_print(conn->last_pack);
+ }
+ if (l2tp_packet_send(conn->sock, conn->last_pack) == 0)
+ return;
+ }
+ }
+
+ l2tp_disconnect(conn);
+}
+
+static void l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+ conn->retransmit = 0;
+
+ pack->hdr.tid = htons(conn->peer_tid);
+ pack->hdr.sid = htons(conn->peer_sid);
+ pack->hdr.Nr = htons(conn->Nr + 1);
+ pack->hdr.Ns = htons(conn->Ns++);
+
+ if (conf_verbose) {
+ log_ppp_info("send ");
+ l2tp_packet_print(conn->last_pack);
+ }
+
+ if (l2tp_packet_send(conn->sock, pack))
+ goto out_err;
+
+ if (!conn->timeout_timer.tpd)
+ triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
+
+ if (!list_empty(&pack->attrs))
+ list_add_tail(&pack->entry, &conn->send_queue);
+
+ return;
+
+out_err:
+ l2tp_packet_free(pack);
+ l2tp_disconnect(conn);
+}
+
+static void l2tp_send_ZLB(struct l2tp_conn_t *conn)
+{
+ struct l2tp_packet_t *pack;
+
+ pack = l2tp_packet_alloc(2, 0, &conn->addr);
+ if (!pack) {
+ l2tp_disconnect(conn);
+ return;
+ }
+
+ l2tp_send(conn, pack);
+
+ return;
+}
+
+static void l2tp_send_SCCRP(struct l2tp_conn_t *conn)
+{
+ struct l2tp_packet_t *pack;
+
+ pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Reply, &conn->addr);
+ if (!pack) {
+ l2tp_disconnect(conn);
+ return;
+ }
+
+ if (l2tp_packet_add_int16(pack, Protocol_Version, L2TP_V2_PROTOCOL_VERSION))
+ goto out_err;
+ if (l2tp_packet_add_string(pack, Host_Name, conf_host_name))
+ goto out_err;
+ if (l2tp_packet_add_int32(pack, Framing_Capabilities, conn->framing_cap))
+ goto out_err;
+ if (l2tp_packet_add_int16(pack, Assigned_Tunnel_ID, conn->tid))
+ goto out_err;
+
+
+ l2tp_send(conn, pack);
+
+ conn->state = STATE_WAIT_SCCCN;
+
+ return;
+
+out_err:
+ l2tp_packet_free(pack);
+ l2tp_disconnect(conn);
+}
+
+static void l2tp_send_OCRP(struct l2tp_conn_t *conn)
+{
+ struct l2tp_packet_t *pack;
+
+ pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Reply, &conn->addr);
+ if (!pack) {
+ l2tp_disconnect(conn);
+ return;
+ }
+
+ conn->sid = 1;
+
+ if (l2tp_packet_add_int16(pack, Assigned_Session_ID, conn->sid))
+ goto out_err;
+
+ l2tp_send(conn, pack);
+
+ return;
+
+out_err:
+ l2tp_packet_free(pack);
+ l2tp_disconnect(conn);
+}
+
+static void l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack)
+{
+ struct l2tp_attr_t *attr;
+ struct l2tp_attr_t *protocol_version = NULL;
+ struct l2tp_attr_t *assigned_tid = NULL;
+ struct l2tp_attr_t *assigned_cid = NULL;
+ struct l2tp_attr_t *framing_cap = NULL;
+ struct l2tp_attr_t *router_id = NULL;
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ switch (attr->attr->id) {
+ case Protocol_Version:
+ protocol_version = attr;
+ break;
+ case Framing_Capabilities:
+ framing_cap = attr;
+ break;
+ case Assigned_Tunnel_ID:
+ assigned_tid = attr;
+ break;
+ case Challenge:
+ if (conf_verbose)
+ log_warn("l2tp: Challenge in SCCRQ is not supported\n");
+ return;
+ case Assigned_Connection_ID:
+ assigned_cid = attr;
+ break;
+ case Router_ID:
+ router_id = attr;
+ break;
+ case Message_Digest:
+ if (conf_verbose)
+ log_warn("l2tp: Message-Digest is not supported\n");
+ return;
+ }
+ }
+
+ if (assigned_tid) {
+ if (!protocol_version) {
+ if (conf_verbose)
+ log_warn("l2tp: SCCRQ: no Protocol-Version present in message\n");
+ return;
+ }
+ if (protocol_version->val.uint16 != L2TP_V2_PROTOCOL_VERSION) {
+ if (conf_verbose)
+ log_warn("l2tp: protocol version %02x is not supported\n", protocol_version->val.uint16);
+ return;
+ }
+ if (!framing_cap) {
+ if (conf_verbose)
+ log_warn("l2tp: SCCRQ: no Framing-Capabilities present in message\n");
+ return;
+ }
+
+ l2tp_alloc(serv, pack, assigned_tid, framing_cap);
+
+ } else if (assigned_cid) {
+ // not yet implemented
+ return;
+ } else {
+ if (conf_verbose)
+ log_warn("l2tp: SCCRQ: no Assigned-Tunnel-ID or Assigned-Connection-ID present in message\n");
+ return;
+ }
+}
+
+static void l2tp_recv_SCCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+ if (conn->state == STATE_WAIT_SCCCN) {
+ l2tp_send_ZLB(conn);
+ conn->state = STATE_WAIT_OCRQ;
+ }
+ else
+ log_ppp_warn("l2tp: unexpected SCCCN\n");
+}
+
+static void l2tp_recv_StopCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+
+}
+
+static void l2tp_recv_HELLO(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+
+}
+
+static void l2tp_recv_OCRQ(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+ struct l2tp_attr_t *attr;
+ struct l2tp_attr_t *assigned_sid = NULL;
+
+ if (conn->state != STATE_WAIT_OCRQ) {
+ log_ppp_warn("l2tp: unexpected OCRQ\n");
+ return;
+ }
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ switch(attr->attr->id) {
+ case Assigned_Session_ID:
+ assigned_sid = attr;
+ break;
+ case Call_Serial_Number:
+ case Minimum_BPS:
+ case Maximum_BPS:
+ case Bearer_Type:
+ case Framing_Type:
+ case Called_Number:
+ case Sub_Address:
+ break;
+ default:
+ if (attr->M) {
+ if (conf_verbose) {
+ log_ppp_warn("l2tp: OCRQ: unknown attribute %i\n", attr->attr->id);
+ l2tp_terminate(conn, 2, 8);
+ return;
+ }
+ }
+ }
+ }
+
+ if (!assigned_sid) {
+ if (conf_verbose)
+ log_ppp_warn("l2tp: OCRQ: no Assigned-Session-ID attribute present in message\n");
+ l2tp_terminate(conn, 2, 0);
+ return;
+ }
+
+ l2tp_send_OCRP(conn);
+
+ conn->peer_sid = assigned_sid->val.uint16;
+
+ l2tp_connect(conn);
+}
+
+static void l2tp_recv_OCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+
+}
+
+static void l2tp_recv_CDN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+
+}
+
+static void l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
+{
+
+}
+
+static void l2tp_ctx_recv(struct l2tp_conn_t *conn)
+{
+ struct l2tp_packet_t *pack;
+ struct l2tp_attr_t *msg_type;
+
+ pthread_mutex_lock(&conn->lock);
+ if (list_empty(&conn->recv_queue)) {
+ pthread_mutex_unlock(&conn->lock);
+ return;
+ }
+ pack = list_entry(conn->recv_queue.next, typeof(*pack), entry);
+ list_del(&pack->entry);
+ pthread_mutex_unlock(&conn->lock);
+
+ if (conf_verbose) {
+ log_ppp_info("recv ");
+ l2tp_packet_print(pack);
+ }
+
+ if (ntohs(pack->hdr.Ns) == conn->Nr + 1) {
+ conn->Nr++;
+ if (!list_empty(&conn->send_queue)) {
+ pack = list_entry(conn->send_queue.next, typeof(*pack), entry);
+ list_del(&pack->entry);
+ l2tp_packet_free(pack);
+ conn->retransmit = 0;
+ }
+ if (!list_empty(&conn->send_queue))
+ triton_timer_mod(&conn->timeout_timer, 0);
+ else if (conn->timeout_timer.tpd)
+ triton_timer_del(&conn->timeout_timer);
+ } else {
+ if (ntohs(pack->hdr.Ns) < conn->Nr + 1 || (ntohs(pack->hdr.Ns > 32767 && conn->Nr + 1 < 32767))) {
+ log_ppp_debug("duplicate packet\n");
+ l2tp_send_ZLB(conn);
+ } else
+ log_ppp_debug("reordered packet\n");
+ l2tp_packet_free(pack);
+ return;
+ }
+
+ if (list_empty(&pack->attrs)) {
+ l2tp_packet_free(pack);
+ return;
+ }
+
+ msg_type = list_entry(pack->attrs.next, typeof(*msg_type), entry);
+
+ if (msg_type->attr->id != Message_Type) {
+ if (conf_verbose)
+ log_ppp_error("l2tp: first attribute is not Message-Type, dropping connection...\n");
+ goto drop;
+ }
+
+ switch (msg_type->val.uint16) {
+ case Message_Type_Start_Ctrl_Conn_Connected:
+ l2tp_recv_SCCCN(conn, pack);
+ break;
+ case Message_Type_Stop_Ctrl_Conn_Notify:
+ l2tp_recv_StopCCN(conn, pack);
+ break;
+ case Message_Type_Hello:
+ l2tp_recv_HELLO(conn, pack);
+ break;
+ case Message_Type_Outgoing_Call_Request:
+ l2tp_recv_OCRQ(conn, pack);
+ break;
+ case Message_Type_Outgoing_Call_Connected:
+ l2tp_recv_OCCN(conn, pack);
+ break;
+ case Message_Type_Call_Disconnect_Notify:
+ l2tp_recv_CDN(conn, pack);
+ break;
+ case Message_Type_Set_Link_Info:
+ l2tp_recv_SLI(conn, pack);
+ break;
+ case Message_Type_Start_Ctrl_Conn_Reply:
+ case Message_Type_Outgoing_Call_Reply:
+ case Message_Type_Incoming_Call_Request:
+ case Message_Type_Incoming_Call_Reply:
+ case Message_Type_Incoming_Call_Connected:
+ case Message_Type_WAN_Error_Notify:
+ if (conf_verbose)
+ log_warn("l2tp: unexpected Message-Type %i\n", msg_type->val.uint16);
+ break;
+ default:
+ if (conf_verbose)
+ log_warn("l2tp: unknown Message-Type %i\n", msg_type->val.uint16);
+ if (msg_type->M)
+ l2tp_terminate(conn, 2, 8);
+ }
+
+ l2tp_packet_free(pack);
+
+ return;
+
+drop:
+ l2tp_packet_free(pack);
+ l2tp_disconnect(conn);
+}
+
+static int l2tp_udp_read(struct triton_md_handler_t *h)
+{
+ struct l2tp_serv_t *serv = container_of(h, typeof(*serv), hnd);
+ struct l2tp_packet_t *pack;
+ struct l2tp_attr_t *msg_type;
+ struct l2tp_conn_t *conn = NULL;
+
+ while (1) {
+ pack = NULL;
+
+ if (l2tp_recv(h->fd, &pack))
+ break;
+
+ if (!pack)
+ continue;
+
+ if (pack->hdr.ver == 2 && pack->hdr.tid) {
+ conn = l2tp_conn_lookup(ntohs(pack->hdr.tid));
+ if (!conn) {
+ if (conf_verbose)
+ log_warn("l2tp: tunnel %i not found\n", ntohs(pack->hdr.tid));
+ goto skip;
+ }
+
+ list_add_tail(&pack->entry, &conn->recv_queue);
+ triton_context_call(&conn->ctx, (triton_event_func)l2tp_ctx_recv, conn);
+ pthread_mutex_unlock(&conn->lock);
+ continue;
+ }
+
+ if (list_empty(&pack->attrs)) {
+ if (conf_verbose)
+ log_warn("l2tp: to Message-Type attribute present\n");
+ goto skip;
+ }
+
+ msg_type = list_entry(pack->attrs.next, typeof(*msg_type), entry);
+ if (msg_type->attr->id != Message_Type) {
+ if (conf_verbose)
+ log_warn("l2tp: first attribute is not Message-Type\n");
+ goto skip;
+ }
+
+ if (msg_type->val.uint16 == Message_Type_Start_Ctrl_Conn_Request)
+ l2tp_recv_SCCRQ(serv, pack);
+ else {
+ if (conf_verbose) {
+ log_warn("recv (unexpected) ");
+ l2tp_packet_print(pack);
+ }
+ }
+skip:
+ l2tp_packet_free(pack);
+ }
+
+ return 0;
+}
+
+static void l2tp_udp_close(struct triton_context_t *ctx)
+{
+ struct l2tp_serv_t *serv = container_of(ctx, typeof(*serv), ctx);
+}
+
+static struct l2tp_serv_t udp_serv =
+{
+ .hnd.read=l2tp_udp_read,
+ .ctx.close=l2tp_udp_close,
+};
+
+/*static struct l2tp_serv_t ip_serv =
+{
+ .hnd.read=l2t_ip_read,
+ .ctx.close=l2tp_ip_close,
+};*/
+
+static void start_udp_server(void)
+{
+ struct sockaddr_in addr;
+ char *opt;
+
+ udp_serv.hnd.fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (udp_serv.hnd.fd < 0) {
+ log_emerg("l2tp: socket: %s\n", strerror(errno));
+ return;
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(L2TP_PORT);
+
+ opt = conf_get_opt("l2tp", "bind");
+ if (opt)
+ addr.sin_addr.s_addr = inet_addr(opt);
+ else
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ setsockopt(udp_serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &udp_serv.hnd.fd, 4);
+ if (bind (udp_serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
+ log_emerg("l2tp: failed to bind socket: %s\n", strerror(errno));
+ close(udp_serv.hnd.fd);
+ return;
+ }
+
+ if (fcntl(udp_serv.hnd.fd, F_SETFL, O_NONBLOCK)) {
+ log_emerg("pptp: failed to set nonblocking mode: %s\n", strerror(errno));
+ close(udp_serv.hnd.fd);
+ return;
+ }
+
+ memcpy(&udp_serv.addr, &addr, sizeof(addr));
+
+ triton_context_register(&udp_serv.ctx, NULL);
+ triton_md_register_handler(&udp_serv.ctx, &udp_serv.hnd);
+ triton_md_enable_handler(&udp_serv.hnd, MD_MODE_READ);
+ triton_context_wakeup(&udp_serv.ctx);
+}
+
+static void __init l2tp_init(void)
+{
+ char *opt;
+
+ l2tp_conn = malloc(L2TP_MAX_TID * sizeof(void *));
+ memset(l2tp_conn, 0, L2TP_MAX_TID * sizeof(void *));
+
+ l2tp_conn_pool = mempool_create(sizeof(struct l2tp_conn_t));
+
+ opt = conf_get_opt("l2tp", "verbose");
+ if (opt && atoi(opt) > 0)
+ conf_verbose = 1;
+
+ start_udp_server();
+}
+
diff --git a/accel-pptpd/ctrl/l2tp/l2tp.h b/accel-pptpd/ctrl/l2tp/l2tp.h
new file mode 100644
index 0000000..a99bdc3
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/l2tp.h
@@ -0,0 +1,84 @@
+#ifndef __L2TP_H
+#define __L2TP_H
+
+#include <netinet/in.h>
+
+#include "list.h"
+#include "l2tp_prot.h"
+
+#define ATTR_TYPE_NONE 0
+#define ATTR_TYPE_INT16 1
+#define ATTR_TYPE_INT32 2
+#define ATTR_TYPE_INT64 3
+#define ATTR_TYPE_OCTETS 4
+#define ATTR_TYPE_STRING 5
+
+#define L2TP_MAX_PACKET_SIZE 65536
+#define L2TP_MAX_TID 65534
+
+#define L2TP_V2_PROTOCOL_VERSION ( 1 << 8 | 0 )
+
+typedef union
+{
+ uint32_t uint32;
+ int32_t int32;
+ uint16_t uint16;
+ int16_t int16;
+ uint64_t uint64;
+ uint8_t *octets;
+ char *string;
+} l2tp_value_t;
+
+struct l2tp_dict_attr_t
+{
+ struct list_head entry;
+ const char *name;
+ int id;
+ int type;
+ int M;
+ int H;
+ struct list_head values;
+};
+
+struct l2tp_dict_value_t
+{
+ struct list_head entry;
+ const char *name;
+ l2tp_value_t val;
+};
+
+struct l2tp_attr_t
+{
+ struct list_head entry;
+ struct l2tp_dict_attr_t *attr;
+ int M:1;
+ int H:1;
+ int length;
+ l2tp_value_t val;
+};
+
+struct l2tp_packet_t
+{
+ struct list_head entry;
+ struct sockaddr_in addr;
+ struct l2tp_hdr_t hdr;
+ struct list_head attrs;
+};
+
+extern int conf_verbose;
+
+struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_name(const char *name);
+struct l2tp_dict_attr_t *l2tp_dict_find_attr_by_id(int id);
+struct l2tp_dict_value_t *l2tp_dict_find_value(struct l2tp_dict_attr_t *attr, l2tp_value_t val);
+
+int l2tp_recv(int fd, struct l2tp_packet_t **);
+void l2tp_packet_free(struct l2tp_packet_t *);
+void l2tp_packet_print(struct l2tp_packet_t *);
+struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type, struct sockaddr_in *addr);
+int l2tp_packet_send(int sock, struct l2tp_packet_t *);
+int l2tp_packet_add_int16(struct l2tp_packet_t *pack, int id, int16_t val);
+int l2tp_packet_add_int32(struct l2tp_packet_t *pack, int id, int32_t val);
+int l2tp_packet_add_string(struct l2tp_packet_t *pack, int id, const char *val);
+int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *val, int size);
+
+#endif
diff --git a/accel-pptpd/ctrl/l2tp/l2tp_prot.h b/accel-pptpd/ctrl/l2tp/l2tp_prot.h
new file mode 100644
index 0000000..1c1d9da
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/l2tp_prot.h
@@ -0,0 +1,55 @@
+#ifndef __L2TP_PROT_H
+#define __L2TP_PROT_H
+
+#include <stdint.h>
+
+#define L2TP_PORT 1701
+
+struct l2tp_hdr_t
+{
+ uint8_t P:1;
+ uint8_t O:1;
+ uint8_t reserved2:1;
+ uint8_t S:1;
+ uint8_t reserved1:2;
+ uint8_t L:1;
+ uint8_t T:1;
+ uint8_t ver:4;
+ uint8_t reserved3:4;
+ uint16_t length;
+ union {
+ struct {
+ uint16_t tid;
+ uint16_t sid;
+ };
+ uint32_t cid;
+ };
+ uint16_t Ns;
+ uint16_t Nr;
+} __attribute__((packed));
+
+/*#define L2TP_T(hdr) (hdr->flags >> 15)
+#define L2TP_L(hdr) ((hdr->flags >> 14) & 1)
+#define L2TP_S(hdr) ((hdr->flags >> 10) & 1)
+#define L2TP_O(hdr) ((hdr->flags >> 8) & 1)
+#define L2TP_VER(hdr) (hdr->flags & 0xf)*/
+
+struct l2tp_avp_t
+{
+ uint16_t length:10;
+ uint16_t reserved:4;
+ uint16_t H:1;
+ uint16_t M:1;
+ uint16_t vendor;
+ uint16_t type;
+ uint8_t val[0];
+} __attribute__((packed));
+
+struct l2tp_avp_result_code
+{
+ uint16_t result_code;
+ uint16_t error_code;
+} __attribute__((packed));
+
+#endif
+
diff --git a/accel-pptpd/ctrl/l2tp/packet.c b/accel-pptpd/ctrl/l2tp/packet.c
new file mode 100644
index 0000000..e0ff65a
--- /dev/null
+++ b/accel-pptpd/ctrl/l2tp/packet.c
@@ -0,0 +1,457 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+
+#include "triton.h"
+#include "log.h"
+#include "mempool.h"
+#include "memdebug.h"
+
+#include "l2tp.h"
+#include "attr_defs.h"
+
+static mempool_t attr_pool;
+static mempool_t pack_pool;
+static mempool_t buf_pool;
+
+void l2tp_packet_print(struct l2tp_packet_t *pack)
+{
+ struct l2tp_attr_t *attr;
+ struct l2tp_dict_value_t *val;
+
+ if (pack->hdr.ver == 2)
+ log_ppp_info("[L2TP tid=%i sid=%i Ns=%i Nr=%i",
+ pack->hdr.tid, pack->hdr.sid, pack->hdr.Ns, pack->hdr.Nr);
+ else
+ log_ppp_info("[L2TP cid=%u Ns=%i Nr=%i",
+ pack->hdr.cid, pack->hdr.Ns, pack->hdr.Nr);
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ log_ppp_info(" <%s", attr->attr->name);
+ val = l2tp_dict_find_value(attr->attr, attr->val);
+ if (val)
+ log_ppp_info(" %s", val->name);
+ else {
+ switch (attr->attr->type) {
+ case ATTR_TYPE_INT16:
+ log_ppp_info(" %i", attr->val.int16);
+ break;
+ case ATTR_TYPE_INT32:
+ log_ppp_info(" %i", attr->val.int32);
+ break;
+ case ATTR_TYPE_STRING:
+ log_ppp_info(" %s", attr->val.string);
+ break;
+ }
+ }
+ log_ppp_info(">");
+ }
+
+ log_ppp_info("]\n");
+}
+
+struct l2tp_packet_t *l2tp_packet_alloc(int ver, int msg_type, struct sockaddr_in *addr)
+{
+ struct l2tp_packet_t *pack = mempool_alloc(pack_pool);
+ if (!pack)
+ return NULL;
+
+ memset(pack, 0, sizeof(*pack));
+ INIT_LIST_HEAD(&pack->attrs);
+ pack->hdr.ver = ver;
+ pack->hdr.T = 1;
+ pack->hdr.L = 1;
+ pack->hdr.S = 1;
+ memcpy(&pack->addr, addr, sizeof(*addr));
+
+ if (msg_type) {
+ if (l2tp_packet_add_int16(pack, Message_Type, msg_type)) {
+ mempool_free(pack);
+ return NULL;
+ }
+ }
+
+ return pack;
+}
+
+void l2tp_packet_free(struct l2tp_packet_t *pack)
+{
+ struct l2tp_attr_t *attr;
+
+ while (!list_empty(&pack->attrs)) {
+ attr = list_entry(pack->attrs.next, typeof(*attr), entry);
+ if (attr->attr->type == ATTR_TYPE_OCTETS || attr->attr->type == ATTR_TYPE_STRING)
+ _free(attr->val.octets);
+ list_del(&attr->entry);
+ mempool_free(attr);
+ }
+
+ mempool_free(pack);
+}
+
+int l2tp_recv(int fd, struct l2tp_packet_t **p)
+{
+ int n, length;
+ uint8_t *buf = mempool_alloc(buf_pool);
+ struct l2tp_hdr_t *hdr = (struct l2tp_hdr_t *)buf;
+ struct l2tp_avp_t *avp;
+ struct l2tp_dict_attr_t *da;
+ struct l2tp_attr_t *attr, *RV = NULL;
+ uint8_t *ptr = (uint8_t *)(hdr + 1);
+ struct l2tp_packet_t *pack;
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+
+ if (!buf) {
+ log_emerg("l2tp: out of memory\n");
+ return 0;
+ }
+
+ n = recvfrom(fd, buf, L2TP_MAX_PACKET_SIZE, 0, &addr, &len);
+
+ if (n < 0) {
+ if (errno == EAGAIN)
+ return -1;
+ log_error("l2tp: recv: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if (n < sizeof(*hdr)) {
+ if (conf_verbose)
+ log_warn("l2tp: short packet received (%i/%i)\n", n, sizeof(*hdr));
+ goto out_err;
+ }
+
+ if (n < ntohs(hdr->length)) {
+ if (conf_verbose)
+ log_warn("l2tp: short packet received (%i/%i)\n", n, ntohs(hdr->length));
+ goto out_err;
+ }
+
+ if (hdr->T == 0)
+ goto out_err_hdr;
+
+ if (hdr->ver == 2) {
+ if (hdr->L == 0) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect message received (L=0)\n");
+ goto out_err_hdr;
+ }
+
+ if (hdr->S == 0) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect message received (S=0)\n");
+ goto out_err_hdr;
+ }
+
+ if (hdr->O == 1) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect message received (O=1)\n");
+ goto out_err_hdr;
+ }
+ } else if (hdr->ver != 3) {
+ if (conf_verbose)
+ log_warn("l2tp: protocol version %i is not supported\n", hdr->ver);
+ goto out_err_hdr;
+ }
+
+ pack = mempool_alloc(pack_pool);
+ if (!pack) {
+ log_emerg("l2tp: out of memory\n");
+ mempool_free(buf);
+ return -1;
+ }
+
+ memset(pack, 0, sizeof(*pack));
+ INIT_LIST_HEAD(&pack->attrs);
+
+ memcpy(&pack->addr, &addr, sizeof(addr));
+ memcpy(&pack->hdr, hdr, sizeof(*hdr));
+ length = ntohs(hdr->length) - sizeof(*hdr);
+
+ while (length) {
+ *(uint16_t *)ptr = ntohs(*(uint16_t *)ptr);
+ avp = (struct l2tp_avp_t *)ptr;
+
+ if (avp->length > length) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect avp received (exceeds message length)\n");
+ goto out_err;
+ }
+
+ da = l2tp_dict_find_attr_by_id(ntohs(avp->type));
+ if (!da) {
+ if (conf_verbose)
+ log_warn("l2tp: unknown avp received (type=%i, M=%u)\n", ntohs(avp->type), avp->M);
+ if (avp->M)
+ goto out_err;
+ } else {
+ if (da->M != -1 && da->M != avp->M) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect avp received (type=%i, M=%i, must be %i)\n", ntohs(avp->type), avp->M, da->M);
+ goto out_err;
+ }
+
+ if (da->H != -1 && da->H != avp->H) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect avp received (type=%i, H=%i, must be %i)\n", ntohs(avp->type), avp->H, da->H);
+ goto out_err;
+ }
+
+ if (avp->H) {
+ if (!RV) {
+ if (conf_verbose)
+ log_warn("l2tp: incorrect avp received (type=%i, H=1, but Random-Vector is not received)\n", ntohs(avp->type));
+ goto out_err;
+ } else {
+ if (conf_verbose)
+ log_warn("l2tp: hidden avp received (type=%i)\n", ntohs(avp->type));
+ }
+ }
+
+ attr = mempool_alloc(attr_pool);
+ memset(attr, 0, sizeof(*attr));
+ list_add_tail(&attr->entry, &pack->attrs);
+
+ attr->attr = da;
+ attr->M = avp->M;
+ attr->H = avp->H;
+ attr->length = avp->length - sizeof(*avp);
+
+ if (attr->attr->id == Random_Vector)
+ RV = attr;
+
+ switch (da->type) {
+ case ATTR_TYPE_INT16:
+ if (avp->length != sizeof(*avp) + 2)
+ goto out_err_len;
+ attr->val.uint16 = ntohs(*(uint16_t *)avp->val);
+ break;
+ case ATTR_TYPE_INT32:
+ if (avp->length != sizeof(*avp) + 4)
+ goto out_err_len;
+ attr->val.uint32 = ntohl(*(uint32_t *)avp->val);
+ break;
+ case ATTR_TYPE_INT64:
+ if (avp->length != sizeof(*avp) + 8)
+ goto out_err_len;
+ attr->val.uint64 = *(uint64_t *)avp->val;
+ break;
+ case ATTR_TYPE_OCTETS:
+ attr->val.octets = _malloc(attr->length);
+ if (!attr->val.octets)
+ goto out_err_mem;
+ memcpy(attr->val.octets, avp->val, attr->length);
+ break;
+ case ATTR_TYPE_STRING:
+ attr->val.string = _malloc(attr->length + 1);
+ if (!attr->val.string)
+ goto out_err_mem;
+ memcpy(attr->val.string, avp->val, attr->length);
+ attr->val.string[attr->length] = 0;
+ break;
+ }
+ }
+
+ ptr += avp->length;
+ length -= avp->length;
+ }
+
+ *p = pack;
+
+ mempool_free(buf);
+
+ return 0;
+
+out_err:
+ l2tp_packet_free(pack);
+out_err_hdr:
+ mempool_free(buf);
+ return 0;
+out_err_len:
+ if (conf_verbose)
+ log_warn("l2tp: incorrect avp received (type=%i, incorrect length %i)\n", ntohs(avp->type), avp->length);
+ goto out_err;
+out_err_mem:
+ log_emerg("l2tp: out of memory\n");
+ goto out_err;
+}
+
+int l2tp_packet_send(int sock, struct l2tp_packet_t *pack)
+{
+ uint8_t *buf = mempool_alloc(buf_pool);
+ struct l2tp_avp_t *avp;
+ struct l2tp_attr_t *attr;
+ uint8_t *ptr;
+ int n;
+ int len = sizeof(pack->hdr);
+
+ if (!buf) {
+ log_emerg("l2tp: out of memory\n");
+ return -1;
+ }
+
+ memset(buf, 0, L2TP_MAX_PACKET_SIZE);
+
+ ptr = buf + sizeof(pack->hdr);
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ if (len + sizeof(*avp) + attr->length >= L2TP_MAX_PACKET_SIZE) {
+ log_error("l2tp: cann't send packet (exceeds maximum size)\n");
+ mempool_free(buf);
+ return -1;
+ }
+ avp = (struct l2tp_avp_t *)ptr;
+ avp->type = htons(attr->attr->id);
+ avp->M = attr->M;
+ avp->H = attr->H;
+ avp->length = sizeof(*avp) + attr->length;
+ *(uint16_t *)ptr = htons(*(uint16_t *)ptr);
+ switch (attr->attr->type) {
+ case ATTR_TYPE_INT16:
+ *(int16_t *)avp->val = htons(attr->val.int16);
+ break;
+ case ATTR_TYPE_INT32:
+ *(int32_t *)avp->val = htonl(attr->val.int32);
+ break;
+ case ATTR_TYPE_STRING:
+ case ATTR_TYPE_OCTETS:
+ memcpy(avp->val, attr->val.string, attr->length);
+ break;
+ }
+
+ ptr += sizeof(*avp) + attr->length;
+ len += sizeof(*avp) + attr->length;
+ }
+
+ pack->hdr.length = htons(len);
+ memcpy(buf, &pack->hdr, sizeof(pack->hdr));
+
+ n = sendto(sock, buf, ntohs(pack->hdr.length), 0, &pack->addr, sizeof(pack->addr));
+
+ mempool_free(buf);
+
+ if (n < 0) {
+ if (errno == EAGAIN) {
+ if (conf_verbose)
+ log_warn("l2tp: buffer overflow (packet lost)\n");
+ } else {
+ if (conf_verbose)
+ log_warn("l2tp: sendto: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (n != ntohs(pack->hdr.length)) {
+ if (conf_verbose)
+ log_warn("l2tp: short write (%i/%i)\n", n, ntohs(pack->hdr.length));
+ }
+
+ return 0;
+}
+
+static struct l2tp_attr_t *attr_alloc(int id)
+{
+ struct l2tp_attr_t *attr;
+ struct l2tp_dict_attr_t *da;
+
+ da = l2tp_dict_find_attr_by_id(id);
+ if (!da)
+ return NULL;
+
+ attr = mempool_alloc(attr_pool);
+ if (!attr) {
+ log_emerg("l2tp: out of memory\n");
+ return NULL;
+ }
+
+ memset(attr, 0, sizeof(*attr));
+
+ attr->attr = da;
+
+ if (da->M != -1)
+ attr->M = da->M;
+ if (da->H != -1)
+ attr->H = da->H;
+
+ return attr;
+}
+
+int l2tp_packet_add_int16(struct l2tp_packet_t *pack, int id, int16_t val)
+{
+ struct l2tp_attr_t *attr = attr_alloc(id);
+
+ if (!attr)
+ return -1;
+
+ attr->length = 2;
+ attr->val.int16 = val;
+ list_add_tail(&attr->entry, &pack->attrs);
+
+ return 0;
+}
+int l2tp_packet_add_int32(struct l2tp_packet_t *pack, int id, int32_t val)
+{
+ struct l2tp_attr_t *attr = attr_alloc(id);
+
+ if (!attr)
+ return -1;
+
+ attr->length = 4;
+ attr->val.int32 = val;
+ list_add_tail(&attr->entry, &pack->attrs);
+
+ return 0;
+}
+int l2tp_packet_add_string(struct l2tp_packet_t *pack, int id, const char *val)
+{
+ struct l2tp_attr_t *attr = attr_alloc(id);
+
+ if (!attr)
+ return -1;
+
+ attr->length = strlen(val);
+ attr->val.string = _strdup(val);
+ if (!attr->val.string) {
+ log_emerg("l2tp: out of memory\n");
+ mempool_free(attr);
+ return -1;
+ }
+ memcpy(attr->val.string, val, attr->length);
+ list_add_tail(&attr->entry, &pack->attrs);
+
+ return 0;
+}
+
+int l2tp_packet_add_octets(struct l2tp_packet_t *pack, int id, const uint8_t *val, int size)
+{
+ struct l2tp_attr_t *attr = attr_alloc(id);
+
+ if (!attr)
+ return -1;
+
+ attr->length = size;
+ attr->val.octets = _malloc(size);
+ if (!attr->val.string) {
+ log_emerg("l2tp: out of memory\n");
+ mempool_free(attr);
+ return -1;
+ }
+ memcpy(attr->val.octets, val, attr->length);
+ list_add_tail(&attr->entry, &pack->attrs);
+
+ return 0;
+}
+
+static void __init init(void)
+{
+ attr_pool = mempool_create(sizeof(struct l2tp_attr_t));
+ pack_pool = mempool_create(sizeof(struct l2tp_packet_t));
+ buf_pool = mempool_create(L2TP_MAX_PACKET_SIZE);
+}
+
diff --git a/accel-pptpd/ctrl/pppoe/CMakeLists.txt b/accel-pptpd/ctrl/pppoe/CMakeLists.txt
new file mode 100644
index 0000000..dd0f9cd
--- /dev/null
+++ b/accel-pptpd/ctrl/pppoe/CMakeLists.txt
@@ -0,0 +1,5 @@
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_LIBRARY(pppoe SHARED pppoe.c)
+
+INSTALL(TARGETS pppoe LIBRARY DESTINATION usr/lib/accel-pptp)
diff --git a/accel-pptpd/ctrl/pppoe.c b/accel-pptpd/ctrl/pppoe/pppoe.c
index d59a317..30769b5 100644
--- a/accel-pptpd/ctrl/pppoe.c
+++ b/accel-pptpd/ctrl/pppoe/pppoe.c
@@ -678,62 +678,65 @@ static int pppoe_serv_read(struct triton_md_handler_t *h)
struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
int n;
- n = read(h->fd, pack, sizeof(pack));
- if (n < 0) {
- log_error("pppoe: read: %s\n", strerror(errno));
- return 0;
- }
+ while (1) {
+ n = read(h->fd, pack, sizeof(pack));
+ if (n < 0) {
+ if (errno == EAGAIN)
+ break;
+ log_error("pppoe: read: %s\n", strerror(errno));
+ return 0;
+ }
- if (n < ETH_HLEN + sizeof(*hdr)) {
- if (conf_verbose)
- log_warn("pppoe: short packet received (%i)\n", n);
- return 0;
- }
+ if (n < ETH_HLEN + sizeof(*hdr)) {
+ if (conf_verbose)
+ log_warn("pppoe: short packet received (%i)\n", n);
+ return 0;
+ }
- if (memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN) && memcmp(ethhdr->h_dest, serv->hwaddr, ETH_ALEN))
- return 0;
+ if (memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN) && memcmp(ethhdr->h_dest, serv->hwaddr, ETH_ALEN))
+ return 0;
- if (!memcmp(ethhdr->h_source, bc_addr, ETH_ALEN)) {
- if (conf_verbose)
- log_warn("pppoe: discarding packet (host address is broadcast)\n");
- return 0;
- }
+ if (!memcmp(ethhdr->h_source, bc_addr, ETH_ALEN)) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (host address is broadcast)\n");
+ return 0;
+ }
- if ((ethhdr->h_source[0] & 1) != 0) {
- if (conf_verbose)
- log_warn("pppoe: discarding packet (host address is not unicast)\n");
- return 0;
- }
+ if ((ethhdr->h_source[0] & 1) != 0) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (host address is not unicast)\n");
+ return 0;
+ }
- if (n < ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)) {
- if (conf_verbose)
- log_warn("pppoe: short packet received\n");
- return 0;
- }
+ if (n < ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)) {
+ if (conf_verbose)
+ log_warn("pppoe: short packet received\n");
+ return 0;
+ }
- if (hdr->ver != 1) {
- if (conf_verbose)
- log_warn("pppoe: discarding packet (unsupported version %i)\n", hdr->ver);
- return 0;
- }
-
- if (hdr->type != 1) {
- if (conf_verbose)
- log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type);
- }
+ if (hdr->ver != 1) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (unsupported version %i)\n", hdr->ver);
+ return 0;
+ }
+
+ if (hdr->type != 1) {
+ if (conf_verbose)
+ log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type);
+ }
- switch (hdr->code) {
- case CODE_PADI:
- pppoe_recv_PADI(serv, pack, n);
- break;
- case CODE_PADR:
- pppoe_recv_PADR(serv, pack, n);
- break;
- case CODE_PADT:
- pppoe_recv_PADT(serv, pack);
- break;
+ switch (hdr->code) {
+ case CODE_PADI:
+ pppoe_recv_PADI(serv, pack, n);
+ break;
+ case CODE_PADR:
+ pppoe_recv_PADR(serv, pack, n);
+ break;
+ case CODE_PADT:
+ pppoe_recv_PADT(serv, pack);
+ break;
+ }
}
-
return 0;
}
@@ -811,6 +814,11 @@ static void pppoe_start_server(const char *ifname)
goto out_err;
}
+ if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
+ log_emerg("pppoe: failed to set nonblocking mode: %s\n", strerror(errno));
+ goto out_err;
+ }
+
serv->ctx.close = pppoe_serv_close;
serv->hnd.fd = sock;
serv->hnd.read = pppoe_serv_read;
diff --git a/accel-pptpd/ctrl/pppoe.h b/accel-pptpd/ctrl/pppoe/pppoe.h
index 0506108..0506108 100644
--- a/accel-pptpd/ctrl/pppoe.h
+++ b/accel-pptpd/ctrl/pppoe/pppoe.h
diff --git a/accel-pptpd/ctrl/pptp/CMakeLists.txt b/accel-pptpd/ctrl/pptp/CMakeLists.txt
new file mode 100644
index 0000000..19e53b2
--- /dev/null
+++ b/accel-pptpd/ctrl/pptp/CMakeLists.txt
@@ -0,0 +1,5 @@
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_LIBRARY(pptp SHARED pptp.c)
+
+INSTALL(TARGETS pptp LIBRARY DESTINATION usr/lib/accel-pptp )
diff --git a/accel-pptpd/ctrl/pptp.c b/accel-pptpd/ctrl/pptp/pptp.c
index 1151dab..1151dab 100644
--- a/accel-pptpd/ctrl/pptp.c
+++ b/accel-pptpd/ctrl/pptp/pptp.c
diff --git a/accel-pptpd/ctrl/pptp_prot.h b/accel-pptpd/ctrl/pptp/pptp_prot.h
index ee8cb34..ee8cb34 100644
--- a/accel-pptpd/ctrl/pptp_prot.h
+++ b/accel-pptpd/ctrl/pptp/pptp_prot.h