diff options
Diffstat (limited to 'accel-pptpd/ctrl/l2tp/l2tp.c')
-rw-r--r-- | accel-pptpd/ctrl/l2tp/l2tp.c | 1141 |
1 files changed, 0 insertions, 1141 deletions
diff --git a/accel-pptpd/ctrl/l2tp/l2tp.c b/accel-pptpd/ctrl/l2tp/l2tp.c deleted file mode 100644 index ca56051..0000000 --- a/accel-pptpd/ctrl/l2tp/l2tp.c +++ /dev/null @@ -1,1141 +0,0 @@ -#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 <linux/socket.h> -#include <linux/if.h> -#include <linux/if_ether.h> -#include <linux/if_pppox.h> - -#include "triton.h" -#include "mempool.h" -#include "log.h" -#include "ppp.h" -#include "events.h" -#include "utils.h" -#include "iprange.h" -#include "cli.h" - -#include "memdebug.h" - -#include "l2tp.h" -#include "attr_defs.h" - -#ifndef SOL_PPPOL2TP -#define SOL_PPPOL2TP 273 -#endif - -#define STATE_WAIT_SCCCN 1 -#define STATE_WAIT_ICRQ 2 -#define STATE_WAIT_ICCN 3 -#define STATE_WAIT_OCRP 4 -#define STATE_WAIT_OCCN 5 -#define STATE_ESTB 6 -#define STATE_PPP 7 -#define STATE_FIN 8 -#define STATE_CLOSE 0 - -int conf_verbose = 0; -int conf_timeout = 60; -int conf_rtimeout = 5; -int conf_retransmit = 5; -int conf_hello_interval = 60; -char *conf_host_name = NULL; - -static unsigned int stat_active; -static unsigned int stat_starting; - -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_md_handler_t hnd; - struct triton_timer_t timeout_timer; - struct triton_timer_t rtimeout_timer; - struct triton_timer_t hello_timer; - - int tunnel_fd; - - struct sockaddr_in addr; - uint16_t tid; - uint16_t sid; - uint16_t peer_tid; - uint16_t peer_sid; - uint32_t framing_cap; - - int retransmit; - uint16_t Ns, Nr; - struct list_head send_queue; - - int state; - int state1; - int state2; - - 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_rtimeout(struct triton_timer_t *t); -static void l2tp_send_HELLO(struct triton_timer_t *t); -static void l2tp_send_SCCRP(struct l2tp_conn_t *conn); -static int l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack, int log_debug); -static int l2tp_conn_read(struct triton_md_handler_t *); - -static void l2tp_disconnect(struct l2tp_conn_t *conn) -{ - struct l2tp_packet_t *pack; - - triton_md_unregister_handler(&conn->hnd); - close(conn->hnd.fd); - - if (conn->timeout_timer.tpd) - triton_timer_del(&conn->timeout_timer); - - if (conn->rtimeout_timer.tpd) - triton_timer_del(&conn->rtimeout_timer); - - if (conn->hello_timer.tpd) - triton_timer_del(&conn->hello_timer); - - if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); - conn->state = STATE_FIN; - ppp_terminate(&conn->ppp, TERM_USER_REQUEST, 1); - } else if (conn->state != STATE_FIN) - __sync_sub_and_fetch(&stat_starting, 1); - - pthread_mutex_lock(&l2tp_lock); - l2tp_conn[conn->tid] = NULL; - pthread_mutex_unlock(&l2tp_lock); - - if (conn->ppp.fd != -1) - close(conn->ppp.fd); - - if (conn->tunnel_fd != -1) - close(conn->tunnel_fd); - - triton_event_fire(EV_CTRL_FINISHED, &conn->ppp); - - log_ppp_info1("disconnected\n"); - - triton_context_unregister(&conn->ctx); - - while (!list_empty(&conn->send_queue)) { - pack = list_entry(conn->send_queue.next, typeof(*pack), entry); - list_del(&pack->entry); - l2tp_packet_free(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 int l2tp_terminate(struct l2tp_conn_t *conn, int res, int err) -{ - struct l2tp_packet_t *pack; - struct l2tp_avp_result_code rc = {res, err}; - - log_ppp_debug("l2tp: terminate (%i, %i)\n", res, err); - - pack = l2tp_packet_alloc(2, Message_Type_Stop_Ctrl_Conn_Notify, &conn->addr); - if (!pack) - return -1; - - if (l2tp_packet_add_int16(pack, Assigned_Tunnel_ID, conn->tid, 1)) - goto out_err; - if (l2tp_packet_add_octets(pack, Result_Code, (uint8_t *)&rc, sizeof(rc), 0)) - goto out_err; - - l2tp_send(conn, pack, 0); - - conn->state = STATE_FIN; - - return 0; - -out_err: - l2tp_packet_free(pack); - return -1; -} - -static void l2tp_ppp_started(struct ppp_t *ppp) -{ - struct l2tp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - - log_ppp_debug("l2tp: ppp started\n"); - - if (conf_hello_interval) - triton_timer_add(&conn->ctx, &conn->hello_timer, 0); -} - -static void l2tp_ppp_finished(struct ppp_t *ppp) -{ - struct l2tp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - - log_ppp_debug("l2tp: ppp finished\n"); - - if (conn->state != STATE_FIN) { - __sync_sub_and_fetch(&stat_active, 1); - if (l2tp_terminate(conn, 0, 0)) - triton_context_call(&conn->ctx, (triton_event_func)l2tp_disconnect, conn); - } -} - -static void l2tp_conn_close(struct triton_context_t *ctx) -{ - struct l2tp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); - - if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); - conn->state = STATE_FIN; - ppp_terminate(&conn->ppp, TERM_ADMIN_RESET, 1); - } - - if (l2tp_terminate(conn, 0, 0)) - l2tp_disconnect(conn); -} - -static int l2tp_tunnel_alloc(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, struct in_pktinfo *pkt_info, struct l2tp_attr_t *assigned_tid, struct l2tp_attr_t *framing_cap) -{ - struct l2tp_conn_t *conn; - struct sockaddr_in addr; - uint16_t tid; - //char *opt; - int flag = 1; - - conn = mempool_alloc(l2tp_conn_pool); - if (!conn) { - log_emerg("l2tp: out of memory\n"); - return -1; - } - - memset(conn, 0, sizeof(*conn)); - INIT_LIST_HEAD(&conn->send_queue); - - conn->hnd.fd = socket(PF_INET, SOCK_DGRAM, 0); - if (conn->hnd.fd < 0) { - log_error("l2tp: socket: %s\n", strerror(errno)); - mempool_free(conn); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr = pkt_info->ipi_addr; - addr.sin_port = htons(L2TP_PORT); - - setsockopt(conn->hnd.fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); - if (bind(conn->hnd.fd, &addr, sizeof(addr))) { - log_error("l2tp: bind: %s\n", strerror(errno)); - goto out_err; - } - - if (connect(conn->hnd.fd, (struct sockaddr *)&pack->addr, sizeof(addr))) { - log_error("l2tp: connect: %s\n", strerror(errno)); - goto out_err; - } - - if (fcntl(conn->hnd.fd, F_SETFL, O_NONBLOCK)) { - log_emerg("l2tp: failed to set nonblocking mode: %s\n", strerror(errno)); - goto out_err; - } - - 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 -1; - } - - conn->sid = 1; - - memcpy(&conn->addr, &pack->addr, sizeof(pack->addr)); - conn->peer_tid = assigned_tid->val.uint16; - conn->framing_cap = framing_cap->val.uint32; - - conn->ctx.before_switch = log_switch; - conn->ctx.close = l2tp_conn_close; - conn->hnd.read = l2tp_conn_read; - conn->timeout_timer.expire = l2tp_timeout; - conn->timeout_timer.period = conf_timeout * 1000; - conn->rtimeout_timer.expire = l2tp_rtimeout; - conn->rtimeout_timer.period = conf_rtimeout * 1000; - conn->hello_timer.expire = l2tp_send_HELLO; - conn->hello_timer.period = conf_hello_interval * 1000; - conn->ctrl.ctx = &conn->ctx; - conn->ctrl.name = "l2tp"; - conn->ctrl.started = l2tp_ppp_started; - conn->ctrl.finished = l2tp_ppp_finished; - conn->ctrl.max_mtu = 1420; - - 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(addr.sin_addr.s_addr, conn->ctrl.called_station_id); - - ppp_init(&conn->ppp); - conn->ppp.ctrl = &conn->ctrl; - conn->ppp.fd = -1; - conn->tunnel_fd = -1; - - triton_context_register(&conn->ctx, &conn->ppp); - triton_md_register_handler(&conn->ctx, &conn->hnd); - triton_md_enable_handler(&conn->hnd, MD_MODE_READ); - triton_context_wakeup(&conn->ctx); - - if (conf_verbose) { - log_switch(&conn->ctx, &conn->ppp); - log_ppp_info2("recv "); - l2tp_packet_print(pack, log_ppp_info2); - } - - triton_context_call(&conn->ctx, (triton_event_func)l2tp_send_SCCRP, conn); - - __sync_add_and_fetch(&stat_starting, 1); - - return 0; - -out_err: - close(conn->hnd.fd); - mempool_free(conn); - return -1; -} - -static int l2tp_connect(struct l2tp_conn_t *conn) -{ - struct sockaddr_pppol2tp pppox_addr; - int arg = 1; - - memset(&pppox_addr, 0, sizeof(pppox_addr)); - pppox_addr.sa_family = AF_PPPOX; - pppox_addr.sa_protocol = PX_PROTO_OL2TP; - pppox_addr.pppol2tp.fd = conn->hnd.fd; - memcpy(&pppox_addr.pppol2tp.addr, &conn->addr, sizeof(conn->addr)); - pppox_addr.pppol2tp.s_tunnel = conn->tid; - pppox_addr.pppol2tp.d_tunnel = conn->peer_tid; - - conn->tunnel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); - if (!conn->ppp.fd) { - log_ppp_error("l2tp: socket(AF_PPPOX): %s\n", strerror(errno)); - return -1; - } - - conn->ppp.fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); - if (!conn->ppp.fd) { - close(conn->tunnel_fd); - conn->tunnel_fd = -1; - log_ppp_error("l2tp: socket(AF_PPPOX): %s\n", strerror(errno)); - return -1; - } - - if (connect(conn->tunnel_fd, (struct sockaddr *)&pppox_addr, sizeof(pppox_addr)) < 0) { - log_ppp_error("l2tp: connect(tunnel): %s\n", strerror(errno)); - return -1; - } - - pppox_addr.pppol2tp.s_session = conn->sid; - pppox_addr.pppol2tp.d_session = conn->peer_sid; - - if (connect(conn->ppp.fd, (struct sockaddr *)&pppox_addr, sizeof(pppox_addr)) < 0) { - log_ppp_error("l2tp: connect(session): %s\n", strerror(errno)); - return -1; - } - - if (setsockopt(conn->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_LNSMODE, &arg, sizeof(arg))) { - log_ppp_error("l2tp: setsockopt: %s\n", strerror(errno)); - return -1; - } - - conn->ppp.chan_name = _strdup(inet_ntoa(conn->addr.sin_addr)); - - triton_event_fire(EV_CTRL_STARTED, &conn->ppp); - - if (establish_ppp(&conn->ppp)) - return -1; - - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_active, 1); - - conn->state = STATE_PPP; - - return 0; -} - -static void l2tp_rtimeout(struct triton_timer_t *t) -{ - struct l2tp_conn_t *conn = container_of(t, typeof(*conn), rtimeout_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_debug("send "); - l2tp_packet_print(pack, log_ppp_debug); - } - if (l2tp_packet_send(conn->hnd.fd, pack) == 0) - return; - } else - l2tp_disconnect(conn); - } -} - -static void l2tp_timeout(struct triton_timer_t *t) -{ - struct l2tp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer); - log_ppp_debug("l2tp: timeout\n"); - l2tp_disconnect(conn); -} - -static int l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack, int log_debug) -{ - 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 (!list_empty(&pack->attrs)) - conn->Ns++; - - if (conf_verbose) { - if (log_debug) { - log_ppp_debug("send "); - l2tp_packet_print(pack, log_ppp_debug); - } else { - log_ppp_info2("send "); - l2tp_packet_print(pack, log_ppp_info2); - } - } - - if (l2tp_packet_send(conn->hnd.fd, pack)) - goto out_err; - - if (!list_empty(&pack->attrs)) { - list_add_tail(&pack->entry, &conn->send_queue); - if (!conn->rtimeout_timer.tpd) - triton_timer_add(&conn->ctx, &conn->rtimeout_timer, 0); - } else - l2tp_packet_free(pack); - - return 0; - -out_err: - l2tp_packet_free(pack); - return -1; -} - -static int l2tp_send_ZLB(struct l2tp_conn_t *conn) -{ - struct l2tp_packet_t *pack; - - pack = l2tp_packet_alloc(2, 0, &conn->addr); - if (!pack) - return -1; - - if (l2tp_send(conn, pack, 1)) - return -1; - - return 0; -} - -static void l2tp_send_HELLO(struct triton_timer_t *t) -{ - struct l2tp_conn_t *conn = container_of(t, typeof(*conn), hello_timer); - struct l2tp_packet_t *pack; - - pack = l2tp_packet_alloc(2, Message_Type_Hello, &conn->addr); - if (!pack) { - l2tp_disconnect(conn); - return; - } - - if (l2tp_send(conn, pack, 1)) - l2tp_disconnect(conn); -} - -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) - goto out; - - if (l2tp_packet_add_int16(pack, Protocol_Version, L2TP_V2_PROTOCOL_VERSION, 1)) - goto out_err; - if (conf_host_name && l2tp_packet_add_string(pack, Host_Name, conf_host_name, 1)) - goto out_err; - if (l2tp_packet_add_int32(pack, Framing_Capabilities, conn->framing_cap, 1)) - goto out_err; - if (l2tp_packet_add_int16(pack, Assigned_Tunnel_ID, conn->tid, 1)) - goto out_err; - - if (l2tp_send(conn, pack, 0)) - goto out; - - if (!conn->timeout_timer.tpd) - triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); - else - triton_timer_mod(&conn->timeout_timer, 0); - - conn->state = STATE_WAIT_SCCCN; - - return; - -out_err: - l2tp_packet_free(pack); -out: - l2tp_disconnect(conn); -} - -static int l2tp_send_ICRP(struct l2tp_conn_t *conn) -{ - struct l2tp_packet_t *pack; - - pack = l2tp_packet_alloc(2, Message_Type_Incoming_Call_Reply, &conn->addr); - if (!pack) - return -1; - - pack->hdr.sid = htons(conn->peer_sid); - - if (l2tp_packet_add_int16(pack, Assigned_Session_ID, conn->sid, 1)) - goto out_err; - - l2tp_send(conn, pack, 0); - - if (!conn->timeout_timer.tpd) - triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); - else - triton_timer_mod(&conn->timeout_timer, 0); - - conn->state1 = STATE_WAIT_ICCN; - - return 0; - -out_err: - l2tp_packet_free(pack); - return -1; -} - -static int l2tp_send_OCRQ(struct l2tp_conn_t *conn) -{ - struct l2tp_packet_t *pack; - - pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Request, &conn->addr); - if (!pack) - return -1; - - pack->hdr.sid = htons(conn->peer_sid); - - if (l2tp_packet_add_int16(pack, Assigned_Session_ID, conn->sid, 1)) - goto out_err; - if (l2tp_packet_add_int32(pack, Call_Serial_Number, 0, 1)) - goto out_err; - if (l2tp_packet_add_int32(pack, Minimum_BPS, 100, 1)) - goto out_err; - if (l2tp_packet_add_int32(pack, Maximum_BPS, 100000, 1)) - goto out_err; - if (l2tp_packet_add_int32(pack, Bearer_Type, 3, 1)) - goto out_err; - if (l2tp_packet_add_int32(pack, Framing_Type, 3, 1)) - goto out_err; - if (l2tp_packet_add_string(pack, Called_Number, "", 1)) - goto out_err; - - if (l2tp_send(conn, pack, 0)) - return -1; - - if (!conn->timeout_timer.tpd) - triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); - else - triton_timer_mod(&conn->timeout_timer, 0); - - conn->state2 = STATE_WAIT_OCRP; - - return 0; - -out_err: - l2tp_packet_free(pack); - return -1; -} - - -static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, struct in_pktinfo *pkt_info) -{ - 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; - - if (ppp_shutdown) - return 0; - - 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 -1; - 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 -1; - } - } - - if (assigned_tid) { - if (!protocol_version) { - if (conf_verbose) - log_warn("l2tp: SCCRQ: no Protocol-Version present in message\n"); - return -1; - } - 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 -1; - } - if (!framing_cap) { - if (conf_verbose) - log_warn("l2tp: SCCRQ: no Framing-Capabilities present in message\n"); - return -1; - } - - if (l2tp_tunnel_alloc(serv, pack, pkt_info, assigned_tid, framing_cap)) - return -1; - - } else if (assigned_cid) { - // not yet implemented - return 0; - } else { - if (conf_verbose) - log_warn("l2tp: SCCRQ: no Assigned-Tunnel-ID or Assigned-Connection-ID present in message\n"); - return -1; - } - - return 0; -} - -static int l2tp_recv_SCCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - if (conn->state == STATE_WAIT_SCCCN) { - triton_timer_mod(&conn->timeout_timer, 0); - conn->state = STATE_ESTB; - conn->state1 = STATE_WAIT_ICRQ; - } - else - log_ppp_warn("l2tp: unexpected SCCCN\n"); - - return 0; -} - -static int l2tp_recv_StopCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - l2tp_send_ZLB(conn); - return -1; -} - -static int l2tp_recv_HELLO(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - if (l2tp_send_ZLB(conn)) - return -1; - - return 0; -} - -static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - struct l2tp_attr_t *attr; - struct l2tp_attr_t *assigned_sid = NULL; - - if (conn->state1 != STATE_WAIT_ICRQ) { - log_ppp_warn("l2tp: unexpected ICRQ\n"); - return 0; - } - - list_for_each_entry(attr, &pack->attrs, entry) { - switch(attr->attr->id) { - case Assigned_Session_ID: - assigned_sid = attr; - break; - case Message_Type: - case Call_Serial_Number: - case Bearer_Type: - case Calling_Number: - case Called_Number: - case Sub_Address: - case Physical_Channel_ID: - break; - default: - if (attr->M) { - if (conf_verbose) { - log_ppp_warn("l2tp: ICRQ: unknown attribute %i\n", attr->attr->id); - if (l2tp_terminate(conn, 2, 8)) - return -1; - return 0; - } - } - } - } - - if (!assigned_sid) { - if (conf_verbose) - log_ppp_warn("l2tp: ICRQ: no Assigned-Session-ID attribute present in message\n"); - if (l2tp_terminate(conn, 2, 0)) - return -1; - } - - conn->peer_sid = assigned_sid->val.uint16; - - if (l2tp_send_ICRP(conn)) - return -1; - - if (l2tp_send_OCRQ(conn)) - return -1; - - return 0; -} - -static int l2tp_recv_ICCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - if (conn->state1 != STATE_WAIT_ICCN) { - log_ppp_warn("l2tp: unexpected ICCN\n"); - return 0; - } - - conn->state1 = STATE_ESTB; - - if (l2tp_connect(conn)) { - if (l2tp_terminate(conn, 2, 0)) - return -1; - return 0; - } - - if (l2tp_send_ZLB(conn)) - return -1; - - triton_timer_del(&conn->timeout_timer); - - return 0; -} - -static int l2tp_recv_OCRP(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - if (conn->state2 != STATE_WAIT_OCRP) { - log_ppp_warn("l2tp: unexpected OCRP\n"); - return 0; - } - - conn->state2 = STATE_WAIT_OCCN; - - return 0; -} - -static int l2tp_recv_OCCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - if (conn->state2 != STATE_WAIT_OCCN) { - log_ppp_warn("l2tp: unexpected OCCN\n"); - return 0; - } - - conn->state2 = STATE_ESTB; - - return 0; -} - -static int l2tp_recv_CDN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - if (ntohs(pack->hdr.sid) != conn->sid) { - if (conf_verbose) - log_warn("l2tp: sid %i is incorrect\n", ntohs(pack->hdr.sid)); - return 0; - } - - if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); - conn->state = STATE_FIN; - ppp_terminate(&conn->ppp, TERM_USER_REQUEST, 1); - } - - if (l2tp_terminate(conn, 0, 0)) - return -1; - - return 0; -} - -static int l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) -{ - return 0; -} - -static int l2tp_conn_read(struct triton_md_handler_t *h) -{ - struct l2tp_conn_t *conn = container_of(h, typeof(*conn), hnd); - struct l2tp_packet_t *pack, *p; - struct l2tp_attr_t *msg_type; - - while (1) { - if (l2tp_recv(h->fd, &pack, NULL)) - return 0; - - if (!pack) - continue; - - if (ntohs(pack->hdr.tid) != conn->tid) { - if (conf_verbose) - log_warn("l2tp: incorrect tid %i in tunnel %i\n", ntohs(pack->hdr.tid), conn->tid); - l2tp_packet_free(pack); - continue; - } - - if (ntohs(pack->hdr.Ns) == conn->Nr + 1) { - if (!list_empty(&pack->attrs)) - conn->Nr++; - if (!list_empty(&conn->send_queue)) { - p = list_entry(conn->send_queue.next, typeof(*pack), entry); - list_del(&p->entry); - l2tp_packet_free(p); - conn->retransmit = 0; - } - if (!list_empty(&conn->send_queue)) - triton_timer_mod(&conn->rtimeout_timer, 0); - else { - if (conn->rtimeout_timer.tpd) - triton_timer_del(&conn->rtimeout_timer); - if (conn->state == STATE_FIN) - goto drop; - } - } else { - if (ntohs(pack->hdr.Ns) < conn->Nr + 1 || (ntohs(pack->hdr.Ns > 32767 && conn->Nr + 1 < 32767))) { - log_ppp_debug("duplicate packet\n"); - if (l2tp_send_ZLB(conn)) - goto drop; - } else - log_ppp_debug("reordered packet\n"); - l2tp_packet_free(pack); - continue; - } - - if (list_empty(&pack->attrs)) { - l2tp_packet_free(pack); - continue; - } - - 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; - } - - if (conf_verbose) { - if (msg_type->val.uint16 == Message_Type_Hello) { - log_ppp_debug("recv "); - l2tp_packet_print(pack, log_ppp_debug); - } else { - log_ppp_info2("recv "); - l2tp_packet_print(pack, log_ppp_info2); - } - } - - switch (msg_type->val.uint16) { - case Message_Type_Start_Ctrl_Conn_Connected: - if (l2tp_recv_SCCCN(conn, pack)) - goto drop; - break; - case Message_Type_Stop_Ctrl_Conn_Notify: - if (l2tp_recv_StopCCN(conn, pack)) - goto drop; - break; - case Message_Type_Hello: - if (l2tp_recv_HELLO(conn, pack)) - goto drop; - break; - case Message_Type_Incoming_Call_Request: - if (l2tp_recv_ICRQ(conn, pack)) - goto drop; - break; - case Message_Type_Incoming_Call_Connected: - if (l2tp_recv_ICCN(conn, pack)) - goto drop; - break; - case Message_Type_Outgoing_Call_Reply: - if (l2tp_recv_OCRP(conn, pack)) - goto drop; - break; - case Message_Type_Outgoing_Call_Connected: - if (l2tp_recv_OCCN(conn, pack)) - goto drop; - break; - case Message_Type_Call_Disconnect_Notify: - if (l2tp_recv_CDN(conn, pack)) - goto drop; - break; - case Message_Type_Set_Link_Info: - if (l2tp_recv_SLI(conn, pack)) - goto drop; - break; - case Message_Type_Start_Ctrl_Conn_Request: - case Message_Type_Start_Ctrl_Conn_Reply: - case Message_Type_Outgoing_Call_Request: - case Message_Type_Incoming_Call_Reply: - 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) { - if (l2tp_terminate(conn, 2, 8)) - goto drop; - } - } - - l2tp_packet_free(pack); - } - -drop: - l2tp_packet_free(pack); - l2tp_disconnect(conn); - return -1; -} - -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 in_pktinfo pkt_info; - - while (1) { - if (l2tp_recv(h->fd, &pack, &pkt_info)) - break; - - if (!pack) - continue; - - if (iprange_client_check(pack->addr.sin_addr.s_addr)) { - log_warn("l2tp: IP is out of client-ip-range, droping connection...\n"); - goto skip; - } - - if (pack->hdr.tid) - goto skip; - - 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, &pkt_info); - else { - if (conf_verbose) { - log_warn("recv (unexpected) "); - l2tp_packet_print(pack, log_ppp_warn); - } - } -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); - triton_md_unregister_handler(&serv->hnd); - close(serv->hnd.fd); - triton_context_unregister(&serv->ctx); -} - -static struct l2tp_serv_t udp_serv = -{ - .hnd.read = l2tp_udp_read, - .ctx.close = l2tp_udp_close, - .ctx.before_switch = log_switch, -}; - -/*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; - int flag = 1; - - 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; - } - - memset(&addr, 0, sizeof(addr)); - 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, sizeof(udp_serv.hnd.fd)); - setsockopt(udp_serv.hnd.fd, SOL_SOCKET, SO_NO_CHECK, &udp_serv.hnd.fd, sizeof(udp_serv.hnd.fd)); - - if (bind (udp_serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { - log_emerg("l2tp: bind: %s\n", strerror(errno)); - close(udp_serv.hnd.fd); - return; - } - - if (fcntl(udp_serv.hnd.fd, F_SETFL, O_NONBLOCK)) { - log_emerg("l2tp: failed to set nonblocking mode: %s\n", strerror(errno)); - close(udp_serv.hnd.fd); - return; - } - - if (setsockopt(udp_serv.hnd.fd, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag))) { - log_emerg("l2tp: setsockopt(IP_PKTINFO): %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 int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) -{ - cli_send(client, "l2tp:\r\n"); - cli_sendv(client, " starting: %u\r\n", stat_starting); - cli_sendv(client, " active: %u\r\n", stat_active); - - return CLI_CMD_OK; -} - -static void load_config(void) -{ - char *opt; - - opt = conf_get_opt("l2tp", "verbose"); - if (opt && atoi(opt) > 0) - conf_verbose = 1; - - opt = conf_get_opt("l2tp", "hello-interval"); - if (opt && atoi(opt) > 0) - conf_hello_interval = atoi(opt); - - opt = conf_get_opt("l2tp", "timeout"); - if (opt && atoi(opt) > 0) - conf_timeout = atoi(opt); - - opt = conf_get_opt("l2tp", "rtimeout"); - if (opt && atoi(opt) > 0) - conf_rtimeout = atoi(opt); - - opt = conf_get_opt("l2tp", "retransmit"); - if (opt && atoi(opt) > 0) - conf_retransmit = atoi(opt); - - if (conf_host_name) - _free(conf_host_name); - opt = conf_get_opt("l2tp", "host-name"); - if (opt) - conf_host_name = _strdup(opt); - else - conf_host_name = NULL; -} - -static void __init l2tp_init(void) -{ - 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)); - - load_config(); - - start_udp_server(); - - cli_register_simple_cmd2(&show_stat_exec, NULL, 2, "show", "stat"); - - triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); -} - |