From 1dbf2a2820c428b8ba8b04d6ec30c78f642cbfb3 Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Fri, 20 Aug 2010 17:50:13 +0400 Subject: using dynamic ppp layers instead of hard coded, but signal transition/handling (up,down,open,close) not fully elaborated --- accel-pptpd/CMakeLists.txt | 2 +- accel-pptpd/auth_pap.c | 10 +- accel-pptpd/ctrl.c | 380 ------------------------------------------ accel-pptpd/ppp.c | 368 +++++++++++++++++++++++++++++++---------- accel-pptpd/ppp.h | 79 +++++---- accel-pptpd/ppp_auth.c | 131 +++++++++------ accel-pptpd/ppp_fsm.c | 6 +- accel-pptpd/ppp_lcp.c | 71 +++++--- accel-pptpd/ppp_lcp.h | 1 + accel-pptpd/pptp.c | 399 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 871 insertions(+), 576 deletions(-) delete mode 100644 accel-pptpd/ctrl.c create mode 100644 accel-pptpd/pptp.c (limited to 'accel-pptpd') diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt index 3279141..2a038f1 100644 --- a/accel-pptpd/CMakeLists.txt +++ b/accel-pptpd/CMakeLists.txt @@ -7,7 +7,7 @@ ADD_SUBDIRECTORY(triton) ADD_EXECUTABLE(pptpd pptpd.c - ctrl.c + pptp.c log.c ppp.c ppp_fsm.c diff --git a/accel-pptpd/auth_pap.c b/accel-pptpd/auth_pap.c index 95d5b1e..e92f253 100644 --- a/accel-pptpd/auth_pap.c +++ b/accel-pptpd/auth_pap.c @@ -84,7 +84,7 @@ static int pap_start(struct ppp_t *ppp, struct auth_data_t *auth) d->h.proto=PPP_PAP; d->h.recv=pap_recv; - ppp_register_handler(ppp,&d->h); + ppp_register_chan_handler(ppp,&d->h); return 0; } @@ -120,7 +120,7 @@ static void pap_send_ack(struct pap_auth_data_t *p, int id) log_debug("send [PAP AuthAck id=%x \"%s\"]\n",id,MSG_SUCCESSED); - ppp_send(p->ppp,msg,ntohs(msg->hdr.len)+2); + ppp_chan_send(p->ppp,msg,ntohs(msg->hdr.len)+2); } static void pap_send_nak(struct pap_auth_data_t *p,int id) @@ -136,7 +136,7 @@ static void pap_send_nak(struct pap_auth_data_t *p,int id) log_debug("send [PAP AuthNak id=%x \"%s\"]\n",id,MSG_FAILED); - ppp_send(p->ppp,msg,ntohs(msg->hdr.len)+2); + ppp_chan_send(p->ppp,msg,ntohs(msg->hdr.len)+2); } static int pap_recv_req(struct pap_auth_data_t *p,struct pap_hdr_t *hdr) @@ -190,9 +190,9 @@ static int pap_recv_req(struct pap_auth_data_t *p,struct pap_hdr_t *hdr) static void pap_recv(struct ppp_handler_t *h) { struct pap_auth_data_t *d=container_of(h,typeof(*d),h); - struct pap_hdr_t *hdr=(struct pap_hdr_t *)d->ppp->in_buf; + struct pap_hdr_t *hdr=(struct pap_hdr_t *)d->ppp->chan_buf; - if (d->ppp->in_buf_sizelen)len)ppp->in_buf_size-2) + if (d->ppp->chan_buf_sizelen)len)ppp->chan_buf_size-2) { log_warn("PAP: short packet received\n"); return; diff --git a/accel-pptpd/ctrl.c b/accel-pptpd/ctrl.c deleted file mode 100644 index 3fbc6e8..0000000 --- a/accel-pptpd/ctrl.c +++ /dev/null @@ -1,380 +0,0 @@ -/* -* C Implementation: ctrl -* -* Description: -* -* -* Author: , (C) 2009 -* -* Copyright: See COPYING file that comes with this distribution -* -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#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 (nout_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/ppp.c b/accel-pptpd/ppp.c index b032b06..58f99dc 100644 --- a/accel-pptpd/ppp.c +++ b/accel-pptpd/ppp.c @@ -17,21 +17,33 @@ #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*); +static LIST_HEAD(layers); -struct ppp_t *alloc_ppp(void) +struct layer_node_t +{ + struct list_head entry; + int order; + struct list_head items; +}; + +static void ppp_chan_read(struct triton_md_handler_t*); +static void ppp_unit_read(struct triton_md_handler_t*); +static void init_layers(struct ppp_t *); +static void start_first_layer(struct ppp_t *); + +struct ppp_t *init_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; } +static void free_ppp(struct ppp_t *ppp) +{ + free(ppp->chan_buf); + free(ppp->unit_buf); +} + int establish_ppp(struct ppp_t *ppp) { /* Open an instance of /dev/ppp and connect the channel to it */ @@ -65,42 +77,75 @@ int establish_ppp(struct ppp_t *ppp) if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx)<0) { log_error("Couldn't create new ppp unit\n"); - goto exit_clodse_unit; + goto exit_close_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; + goto exit_close_unit; } log_info("connect: ppp%i <--> pptp(%s)\n",ppp->unit_idx,ppp->chan_name); + + ppp->chan_buf=malloc(PPP_MRU); + ppp->unit_buf=malloc(PPP_MRU); - 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->handlers); - - ppp->cur_layer=PPP_LAYER_LCP; + INIT_LIST_HEAD(&ppp->chan_handlers); + INIT_LIST_HEAD(&ppp->unit_handlers); - lcp_start(ppp); + init_layers(ppp); + + if (list_empty(&ppp->layers)) + { + log_error("no layers to start\n"); + goto exit_close_unit; + } + + ppp->chan_hnd.fd=ppp->chan_fd; + ppp->chan_hnd.read=ppp_chan_read; + ppp->chan_hnd.twait=-1; + ppp->unit_hnd.fd=ppp->unit_fd; + ppp->unit_hnd.read=ppp_unit_read; + ppp->unit_hnd.twait=-1; + triton_md_register_handler(&ppp->chan_hnd); + triton_md_register_handler(&ppp->unit_hnd); + + triton_md_enable_handler(&ppp->chan_hnd,MD_MODE_READ); + triton_md_enable_handler(&ppp->unit_hnd,MD_MODE_READ); + + log_debug("ppp established\n"); + + start_first_layer(ppp); return 0; -exit_clodse_unit: +exit_close_unit: close(ppp->unit_fd); exit_close_chan: close(ppp->chan_fd); + + free_ppp(ppp); + return -1; } +void destablish_ppp(struct ppp_t *ppp) +{ + triton_md_unregister_handler(&ppp->chan_hnd); + triton_md_unregister_handler(&ppp->unit_hnd); + + close(ppp->unit_fd); + close(ppp->chan_fd); + + free(ppp->unit_buf); + free(ppp->chan_buf); + + log_debug("ppp destablished\n"); + + if (ppp->events.finished) ppp->events.finished(ppp); +} + void print_buf(uint8_t *buf,int size) { int i; @@ -109,41 +154,51 @@ void print_buf(uint8_t *buf,int size) printf("\n"); } -int ppp_send(struct ppp_t *ppp, void *data, int size) +int ppp_chan_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; + printf("ppp_chan_send: "); + print_buf((uint8_t*)data,size); + + n=write(ppp->chan_fd,data,size); + if (nunit_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); - } - }*/ + if (npd; - struct ppp_handler_t *ppp_h=NULL; + struct ppp_t *ppp=container_of(h,typeof(*ppp),chan_hnd); + struct ppp_handler_t *ppp_h; uint16_t proto; - ppp->in_buf_size=read(h->fd,ppp->in_buf,PPP_MRU+PPP_HDRLEN); + ppp->chan_buf_size=read(h->fd,ppp->chan_buf,PPP_MRU); + + printf("ppp_chan_read: "); + print_buf(ppp->chan_buf,ppp->chan_buf_size); - printf("ppp: recv: "); - print_buf(ppp->in_buf,ppp->in_buf_size); + if (ppp->chan_buf_size<2) + { + log_error("ppp_chan_read: short read %i\n",ppp->chan_buf_size); + return; + } - proto=ntohs(*(uint16_t*)ppp->in_buf); - list_for_each_entry(ppp_h,&ppp->handlers,entry) + proto=ntohs(*(uint16_t*)ppp->chan_buf); + list_for_each_entry(ppp_h,&ppp->chan_handlers,entry) { if (ppp_h->proto==proto) { @@ -152,75 +207,212 @@ static void ppp_read(struct triton_md_handler_t*h) } } - log_warn("discarding unknown packet %x\n",proto); + log_warn("ppp_chan_read: discarding unknown packet %x\n",proto); } -static void ppp_write(struct triton_md_handler_t*h) + +static void ppp_unit_read(struct triton_md_handler_t*h) { - struct ppp_t *ppp=(struct ppp_t *)h->pd; + struct ppp_t *ppp=container_of(h,typeof(*ppp),unit_hnd); + struct ppp_handler_t *ppp_h; + uint16_t proto; - 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->unit_buf_size=read(h->fd,ppp->unit_buf,PPP_MRU); + + printf("ppp_unit_read: "); + print_buf(ppp->unit_buf,ppp->unit_buf_size); + + if (ppp->unit_buf_size<2) { - ppp->out_buf_pos+=n; - if (ppp->out_buf_pos==ppp->out_buf_size) + log_error("ppp_chan_read: short read %i\n",ppp->unit_buf_size); + return; + } + + proto=ntohs(*(uint16_t*)ppp->unit_buf); + list_for_each_entry(ppp_h,&ppp->unit_handlers,entry) + { + if (ppp_h->proto==proto) { - triton_md_disable_handler(ppp->h,MD_MODE_WRITE); - ppp->out_buf_pos=0; - ppp->out_buf_size=0; + ppp_h->recv(ppp_h); + return; } } + + log_warn("ppp_chan_read: discarding unknown packet %x\n",proto); } -static void ppp_timeout(struct triton_md_handler_t*h) + +void ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d) { + struct layer_node_t *n=d->node; + + d->started=1; + + list_for_each_entry(d,&n->items,entry) + if (!d->started) return; + if (n->entry.next==&ppp->layers) + { + if (ppp->events.started) ppp->events.started(ppp); + }else + { + n=list_entry(n->entry.next,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + d->layer->start(d); + } } -void ppp_layer_started(struct ppp_t *ppp) +void ppp_layer_finished(struct ppp_t *ppp, struct ppp_layer_data_t *d) { - switch(ppp->cur_layer) + struct layer_node_t *n=d->node; + + d->started=0; + + list_for_each_entry(d,&n->items,entry) + if (d->started) return; + + if (n->entry.prev==&ppp->layers) destablish_ppp(ppp); + else { - case PPP_LAYER_LCP: - ppp->cur_layer++; - if (auth_start(ppp)) - break; - case PPP_LAYER_AUTH: - ppp->cur_layer++; - if (ccp_start(ppp)) - break; - case PPP_LAYER_CCP: - ppp->cur_layer++; - if (ipcp_start(ppp)) - break; - case PPP_LAYER_IPCP: - break; + n=list_entry(n->entry.prev,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + if (d->started) d->layer->finish(d); } } + void ppp_terminate(struct ppp_t *ppp) { - switch(ppp->cur_layer) + struct layer_node_t *n; + struct list_head *p; + struct ppp_layer_data_t *d; + int s=0; + + log_debug("ppp_terminate\n"); + + list_for_each_prev(p,&ppp->layers) { - case PPP_LAYER_IPCP: - ppp->cur_layer--; - ipcp_finish(ppp); - case PPP_LAYER_CCP: - ppp->cur_layer--; - ccp_finish(ppp); - case PPP_LAYER_AUTH: - ppp->cur_layer--; - auth_finish(ppp); - case PPP_LAYER_LCP: - ppp->cur_layer--; - lcp_finish(ppp); + list_for_each_entry(d,&n->items,entry) + { + if (d->started) + { + s=1; + d->layer->finish(d); + } + } + if (s) return; } + destablish_ppp(ppp); } - -void ppp_register_handler(struct ppp_t *ppp,struct ppp_handler_t *h) +void ppp_register_chan_handler(struct ppp_t *ppp,struct ppp_handler_t *h) +{ + list_add_tail(&h->entry,&ppp->chan_handlers); +} +void ppp_register_unit_handler(struct ppp_t *ppp,struct ppp_handler_t *h) { - list_add_tail(&h->entry,&ppp->handlers); + list_add_tail(&h->entry,&ppp->unit_handlers); } void ppp_unregister_handler(struct ppp_t *ppp,struct ppp_handler_t *h) { list_del(&h->entry); } +static int get_layer_order(const char *name) +{ + if (!strcmp(name,"lcp")) return 0; + if (!strcmp(name,"auth")) return 1; + if (!strcmp(name,"ipcp")) return 2; + if (!strcmp(name,"ccp")) return 2; + return -1; +} + +int ppp_register_layer(const char *name, struct ppp_layer_t *layer) +{ + int order; + struct layer_node_t *n,*n1; + + order=get_layer_order(name); + + if (order<0) + return order; + + list_for_each_entry(n,&layers,entry) + { + if (order>n->order) + continue; + if (orderorder) + { + n1=malloc(sizeof(*n1)); + memset(n1,0,sizeof(*n1)); + n1->order=order; + INIT_LIST_HEAD(&n1->items); + list_add_tail(&n1->entry,&n->entry); + n=n1; + } + goto insert; + } + n1=malloc(sizeof(*n1)); + memset(n1,0,sizeof(*n1)); + n1->order=order; + INIT_LIST_HEAD(&n1->items); + list_add_tail(&n1->entry,&layers); + n=n1; +insert: + list_add_tail(&layer->entry,&n->items); + + return 0; +} +void ppp_unregister_layer(struct ppp_layer_t *layer) +{ + list_del(&layer->entry); +} + +static void init_layers(struct ppp_t *ppp) +{ + struct layer_node_t *n,*n1; + struct ppp_layer_t *l; + struct ppp_layer_data_t *d; + + INIT_LIST_HEAD(&ppp->layers); + + list_for_each_entry(n,&layers,entry) + { + n1=(struct layer_node_t*)malloc(sizeof(*n1)); + memset(n1,0,sizeof(*n1)); + INIT_LIST_HEAD(&n1->items); + list_add_tail(&n1->entry,&ppp->layers); + list_for_each_entry(l,&n->items,entry) + { + d=l->init(ppp); + d->layer=l; + d->started=0; + d->node=n1; + list_add_tail(&d->entry,&n1->items); + } + } +} + +static void start_first_layer(struct ppp_t *ppp) +{ + struct layer_node_t *n; + struct ppp_layer_data_t *d; + + n=list_entry(ppp->layers.next,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + d->layer->start(d); +} + +struct ppp_layer_data_t *ppp_find_layer_data(struct ppp_t *ppp, struct ppp_layer_t *layer) +{ + struct layer_node_t *n; + struct ppp_layer_data_t *d; + + list_for_each_entry(n,&ppp->layers,entry) + { + list_for_each_entry(d,&n->items,entry) + { + if (d->layer==layer) + return d; + } + } + + return NULL; +} diff --git a/accel-pptpd/ppp.h b/accel-pptpd/ppp.h index 83ad8ed..9d8cdf1 100644 --- a/accel-pptpd/ppp.h +++ b/accel-pptpd/ppp.h @@ -2,6 +2,8 @@ #define PPP_H #include + +#include "triton/triton.h" #include "list.h" /* @@ -48,11 +50,18 @@ #define AUTH_MAX 3 -struct ppp_lcp_t; +struct ppp_t; + +struct ppp_events_t +{ + void (*started)(struct ppp_t*); + void (*finished)(struct ppp_t*); +}; struct ppp_t { - struct triton_md_handler_t *h; + struct triton_md_handler_t chan_hnd; + struct triton_md_handler_t unit_hnd; int fd; int chan_fd; int unit_fd; @@ -62,28 +71,42 @@ struct ppp_t char *chan_name; - //options - int mtu,mru; - int accomp; // 0 - disabled, 1 - enable, 2 - allow, disabled, 3 - allow,enabled - int pcomp; // 0 - disabled, 1 - enable, 2 - allow, disabled, 3 - allow,enabled - int auth[AUTH_MAX]; - // - + struct ppp_events_t events; + int log:1; - void *out_buf; - int out_buf_size; - int out_buf_pos; + void *chan_buf; + int chan_buf_size; + void *unit_buf; + int unit_buf_size; - void *in_buf; - int in_buf_size; + struct list_head chan_handlers; + struct list_head unit_handlers; - struct list_head handlers; + struct list_head layers; - int cur_layer; struct ppp_lcp_t *lcp; }; +struct ppp_layer_t; +struct layer_node_t; +struct ppp_layer_data_t +{ + struct list_head entry; + struct ppp_layer_t *layer; + struct layer_node_t *node; + int started:1; +}; + +struct ppp_layer_t +{ + struct list_head entry; + struct ppp_layer_data_t *(*init)(struct ppp_t *); + void (*start)(struct ppp_layer_data_t*); + void (*finish)(struct ppp_layer_data_t*); + void (*free)(struct ppp_layer_data_t *); +}; + struct ppp_handler_t { struct list_head entry; @@ -93,25 +116,23 @@ struct ppp_handler_t struct ppp_t *alloc_ppp(void); int establish_ppp(struct ppp_t *ppp); -int ppp_send(struct ppp_t *ppp, void *data, int size); +int ppp_chan_send(struct ppp_t *ppp, void *data, int size); +int ppp_unit_send(struct ppp_t *ppp, void *data, int size); void ppp_init(void); struct ppp_fsm_t* ppp_lcp_init(struct ppp_t *ppp); -void ppp_layer_started(struct ppp_t *ppp); +void ppp_layer_started(struct ppp_t *ppp,struct ppp_layer_data_t*); +void ppp_layer_finished(struct ppp_t *ppp,struct ppp_layer_data_t*); void ppp_terminate(struct ppp_t *ppp); -void ppp_register_handler(struct ppp_t*,struct ppp_handler_t*); -void ppp_unregister_handler(struct ppp_t*,struct ppp_handler_t*); - -void lcp_start(struct ppp_t*); -void lcp_finish(struct ppp_t*); -int auth_start(struct ppp_t*); -void auth_finish(struct ppp_t*); -int ccp_start(struct ppp_t*); -void ccp_finish(struct ppp_t*); -int ipcp_start(struct ppp_t*); -void ipcp_finish(struct ppp_t*); +void ppp_register_chan_handler(struct ppp_t *, struct ppp_handler_t *); +void ppp_register_unit_handler(struct ppp_t * ,struct ppp_handler_t *); +void ppp_unregister_handler(struct ppp_t *, struct ppp_handler_t *); + +int ppp_register_layer(const char *name, struct ppp_layer_t *); +void ppp_unregister_layer(struct ppp_layer_t *); +struct ppp_layer_data_t *ppp_find_layer_data(struct ppp_t *, struct ppp_layer_t *); #define __init __attribute__((constructor)) diff --git a/accel-pptpd/ppp_auth.c b/accel-pptpd/ppp_auth.c index 6fc4801..ee173a7 100644 --- a/accel-pptpd/ppp_auth.c +++ b/accel-pptpd/ppp_auth.c @@ -21,6 +21,11 @@ static int auth_recv_conf_rej(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, u static int auth_recv_conf_ack(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); static void auth_print(void (*print)(const char *fmt,...),struct lcp_option_t*, uint8_t *ptr); +static struct ppp_layer_data_t *auth_layer_init(struct ppp_t*); +static void auth_layer_start(struct ppp_layer_data_t *); +static void auth_layer_finish(struct ppp_layer_data_t *); +static void auth_layer_free(struct ppp_layer_data_t *); + struct auth_option_t { struct lcp_option_t opt; @@ -29,6 +34,13 @@ struct auth_option_t struct auth_data_t *peer_auth; }; +struct auth_layer_data_t +{ + struct ppp_layer_data_t ld; + struct auth_option_t auth_opt; + struct ppp_t *ppp; +}; + static struct lcp_option_handler_t auth_opt_hnd= { .init=auth_init, @@ -42,25 +54,35 @@ static struct lcp_option_handler_t auth_opt_hnd= .print=auth_print, }; +static struct ppp_layer_t auth_layer= +{ + .init=auth_layer_init, + .start=auth_layer_start, + .finish=auth_layer_finish, + .free=auth_layer_free, +}; + static struct lcp_option_t *auth_init(struct ppp_lcp_t *lcp) { struct ppp_auth_handler_t *h; struct auth_data_t *d; - struct auth_option_t *auth_opt=malloc(sizeof(*auth_opt)); - memset(auth_opt,0,sizeof(*auth_opt)); - auth_opt->opt.id=CI_AUTH; - auth_opt->opt.len=4+extra_opt_len; + struct auth_layer_data_t *ad; - INIT_LIST_HEAD(&auth_opt->auth_list); + ad=container_of(ppp_find_layer_data(lcp->ppp,&auth_layer),typeof(*ad),ld); + + ad->auth_opt.opt.id=CI_AUTH; + ad->auth_opt.opt.len=4+extra_opt_len; + + INIT_LIST_HEAD(&ad->auth_opt.auth_list); list_for_each_entry(h,&auth_handlers,entry) { d=h->init(lcp->ppp); d->h=h; - list_add_tail(&d->entry,&auth_opt->auth_list); + list_add_tail(&d->entry,&ad->auth_opt.auth_list); } - return &auth_opt->opt; + return &ad->auth_opt.opt; } static void auth_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) @@ -74,8 +96,6 @@ static void auth_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) list_del(&d->entry); d->h->free(lcp->ppp,d); } - - free(auth_opt); } static int auth_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) @@ -206,66 +226,61 @@ print_d: print("",d->h->name); } -int ppp_auth_register_handler(struct ppp_auth_handler_t *h) +static struct ppp_layer_data_t *auth_layer_init(struct ppp_t *ppp) { - list_add_tail(&h->entry,&auth_handlers); - return 0; -} - -static void __init auth_opt_init() -{ - lcp_option_register(&auth_opt_hnd); -} - - - - + struct auth_layer_data_t *ad=(struct auth_layer_data_t*)malloc(sizeof(*ad)); + log_debug("auth_layer_init\n"); + + memset(ad,0,sizeof(*ad)); + ad->ppp=ppp; + return &ad->ld; +} -int auth_start(struct ppp_t *ppp) +static void auth_layer_start(struct ppp_layer_data_t *ld) { - struct lcp_option_t *opt; - struct auth_option_t *auth_opt; - - list_for_each_entry(opt,&ppp->lcp->options,entry) + struct auth_layer_data_t *ad=container_of(ld,typeof(*ad),ld); + + log_debug("auth_layer_start\n"); + + if (ad->auth_opt.auth) + ad->auth_opt.auth->h->start(ad->ppp,ad->auth_opt.auth); + else { - if (opt->id==CI_AUTH) - { - auth_opt=container_of(opt,typeof(*auth_opt),opt); - if (auth_opt->auth) - { - auth_opt->auth->h->start(ppp,auth_opt->auth); - return 1; - } - break; - } + log_debug("auth_layer_started\n"); + ppp_layer_started(ad->ppp,ld); } +} - return 0; +static void auth_layer_finish(struct ppp_layer_data_t *ld) +{ + struct auth_layer_data_t *ad=container_of(ld,typeof(*ad),ld); + + log_debug("auth_layer_finish\n"); + + if (ad->auth_opt.auth) + ad->auth_opt.auth->h->finish(ad->ppp,ad->auth_opt.auth); + + log_debug("auth_layer_finished\n"); + ppp_layer_finished(ad->ppp,ld); } -void auth_finish(struct ppp_t *ppp) +static void auth_layer_free(struct ppp_layer_data_t *ld) { - struct lcp_option_t *opt; - struct auth_option_t *auth_opt; + struct auth_layer_data_t *ad=container_of(ld,typeof(*ad),ld); - list_for_each_entry(opt,&ppp->lcp->options,entry) - { - if (opt->id==CI_AUTH) - { - auth_opt=container_of(opt,typeof(*auth_opt),opt); - if (auth_opt->auth) - auth_opt->auth->h->finish(ppp,auth_opt->auth); - break; - } - } + log_debug("auth_layer_free\n"); + + free(ad); } void auth_successed(struct ppp_t *ppp) { - ppp_layer_started(ppp); + struct auth_layer_data_t *ad=container_of(ppp_find_layer_data(ppp,&auth_layer),typeof(*ad),ld); + log_debug("auth_layer_started\n"); + ppp_layer_started(ppp,&ad->ld); } void auth_failed(struct ppp_t *ppp) @@ -273,3 +288,15 @@ void auth_failed(struct ppp_t *ppp) ppp_terminate(ppp); } +int ppp_auth_register_handler(struct ppp_auth_handler_t *h) +{ + list_add_tail(&h->entry,&auth_handlers); + return 0; +} + +static void __init ppp_auth_init() +{ + ppp_register_layer("auth",&auth_layer); + lcp_option_register(&auth_opt_hnd); +} + diff --git a/accel-pptpd/ppp_fsm.c b/accel-pptpd/ppp_fsm.c index b68b63f..41436eb 100644 --- a/accel-pptpd/ppp_fsm.c +++ b/accel-pptpd/ppp_fsm.c @@ -10,6 +10,8 @@ * */ +#include + #include "triton/triton.h" #include "ppp.h" #include "ppp_fsm.h" @@ -441,7 +443,7 @@ void send_term_req(struct ppp_fsm_t *layer) log_debug("send [LCP TermReq id=%i \"\"]\n",hdr.id); - ppp_send(layer->ppp,&hdr,6); + ppp_chan_send(layer->ppp,&hdr,6); } void send_term_ack(struct ppp_fsm_t *layer) { @@ -454,7 +456,7 @@ void send_term_ack(struct ppp_fsm_t *layer) log_debug("send [LCP TermAck id=%i \"\"]\n",hdr.id); - ppp_send(layer->ppp,&hdr,6); + ppp_chan_send(layer->ppp,&hdr,6); } static void init_req_counter(struct ppp_fsm_t *layer,int timeout) diff --git a/accel-pptpd/ppp_lcp.c b/accel-pptpd/ppp_lcp.c index 21b7fb2..bfc9917 100644 --- a/accel-pptpd/ppp_lcp.c +++ b/accel-pptpd/ppp_lcp.c @@ -62,10 +62,12 @@ static void lcp_options_free(struct ppp_lcp_t *lcp) } } -void lcp_start(struct ppp_t *ppp) +static struct ppp_layer_data_t *lcp_layer_init(struct ppp_t *ppp) { struct ppp_lcp_t *lcp=malloc(sizeof(*lcp)); memset(lcp,0,sizeof(*lcp)); + + log_debug("lcp_layer_init\n"); lcp->ppp=ppp; lcp->fsm.ppp=ppp; @@ -73,46 +75,65 @@ void lcp_start(struct ppp_t *ppp) lcp->hnd.proto=PPP_LCP; lcp->hnd.recv=lcp_recv; - ppp_register_handler(ppp,&lcp->hnd); + ppp_register_chan_handler(ppp,&lcp->hnd); ppp_fsm_init(&lcp->fsm); lcp->fsm.layer_up=lcp_layer_up; - lcp->fsm.layer_down=lcp_layer_down; + lcp->fsm.layer_finished=lcp_layer_down; lcp->fsm.send_conf_req=send_conf_req; lcp->fsm.send_conf_ack=send_conf_ack; lcp->fsm.send_conf_nak=send_conf_nak; lcp->fsm.send_conf_rej=send_conf_rej; - lcp_options_init(lcp); INIT_LIST_HEAD(&lcp->ropt_list); + return &lcp->ld; +} + +void lcp_layer_start(struct ppp_layer_data_t *ld) +{ + struct ppp_lcp_t *lcp=container_of(ld,typeof(*lcp),ld); + + log_debug("lcp_layer_start\n"); + + lcp_options_init(lcp); ppp_fsm_lower_up(&lcp->fsm); ppp_fsm_open(&lcp->fsm); - - ppp->lcp=lcp; } -void lcp_finish(struct ppp_t *ppp) +void lcp_layer_finish(struct ppp_layer_data_t *ld) { - struct ppp_lcp_t *lcp=ppp->lcp; + struct ppp_lcp_t *lcp=container_of(ld,typeof(*lcp),ld); + + log_debug("lcp_layer_finish\n"); - ppp_unregister_handler(ppp,&lcp->hnd); + ppp_unregister_handler(lcp->ppp,&lcp->hnd); lcp_options_free(lcp); +} + +void lcp_layer_free(struct ppp_layer_data_t *ld) +{ + struct ppp_lcp_t *lcp=container_of(ld,typeof(*lcp),ld); + + log_debug("lcp_layer_free\n"); + free(lcp); } static void lcp_layer_up(struct ppp_fsm_t *fsm) { struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); - ppp_layer_started(lcp->ppp); + log_debug("lcp_layer_started\n"); + ppp_layer_started(lcp->ppp,&lcp->ld); } static void lcp_layer_down(struct ppp_fsm_t *fsm) { struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); - ppp_terminate(lcp->ppp); + log_debug("lcp_layer_finished\n"); + ppp_layer_finished(lcp->ppp,&lcp->ld); } static void print_ropt(struct recv_opt_t *ropt) @@ -159,18 +180,18 @@ static void send_conf_req(struct ppp_fsm_t *fsm) log_debug("]\n"); lcp_hdr->len=htons((ptr-buf)-2); - ppp_send(lcp->ppp,lcp_hdr,ptr-buf); + ppp_chan_send(lcp->ppp,lcp_hdr,ptr-buf); } static void send_conf_ack(struct ppp_fsm_t *fsm) { struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); - struct lcp_hdr_t *hdr=(struct lcp_hdr_t*)lcp->ppp->in_buf; + struct lcp_hdr_t *hdr=(struct lcp_hdr_t*)lcp->ppp->chan_buf; hdr->code=CONFACK; log_debug("send [LCP ConfAck id=%x ]\n",lcp->fsm.recv_id); - ppp_send(lcp->ppp,hdr,ntohs(hdr->len)+2); + ppp_chan_send(lcp->ppp,hdr,ntohs(hdr->len)+2); } static void send_conf_nak(struct ppp_fsm_t *fsm) @@ -202,7 +223,7 @@ static void send_conf_nak(struct ppp_fsm_t *fsm) log_debug("]\n"); lcp_hdr->len=htons((ptr-buf)-2); - ppp_send(lcp->ppp,lcp_hdr,ptr-buf); + ppp_chan_send(lcp->ppp,lcp_hdr,ptr-buf); } static void send_conf_rej(struct ppp_fsm_t *fsm) @@ -236,7 +257,7 @@ static void send_conf_rej(struct ppp_fsm_t *fsm) log_debug("]\n"); lcp_hdr->len=htons((ptr-buf)-2); - ppp_send(lcp->ppp,lcp_hdr,ptr-buf); + ppp_chan_send(lcp->ppp,lcp_hdr,ptr-buf); } static int lcp_recv_conf_req(struct ppp_lcp_t *lcp,uint8_t *data,int size) @@ -438,7 +459,7 @@ void send_echo_reply(struct ppp_lcp_t *lcp) .magic.val=0, }; - ppp_send(lcp->ppp,&msg,ntohs(msg.hdr.len)+2); + ppp_chan_send(lcp->ppp,&msg,ntohs(msg.hdr.len)+2); } static void lcp_recv(struct ppp_handler_t*h) @@ -448,13 +469,13 @@ static void lcp_recv(struct ppp_handler_t*h) int r; char *term_msg; - if (lcp->ppp->in_buf_sizeppp->chan_buf_sizeppp->in_buf; + hdr=(struct lcp_hdr_t *)lcp->ppp->chan_buf; if (ntohs(hdr->len), (C) 2009 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_PPP 2 +#define STATE_FIN 10 + +struct pptp_conn_t +{ + struct triton_md_handler_t hnd; + 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 ppp_started(struct ppp_t *); +static void ppp_finished(struct ppp_t *); + +static void ctrl_read(struct triton_md_handler_t *h) +{ + 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); + conn->hnd.fd=fd; + conn->hnd.twait=TIMEOUT; + conn->hnd.read=pptp_read; + conn->hnd.write=pptp_write; + conn->hnd.timeout=pptp_timeout; + + triton_md_register_handler(&conn->hnd); + triton_md_enable_handler(&conn->hnd,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->hnd.fd); + triton_md_unregister_handler(&conn->hnd); + 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->hnd.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 (nout_buf,buf+n,size-n); + triton_md_enable_handler(&conn->hnd,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); + + if (conn->state==STATE_PPP) + ppp_terminate(&conn->ppp); + + conn->state=STATE_FIN; + conn->hnd.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->hnd.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->hnd.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)); + conn->ppp.events.started=ppp_started; + conn->ppp.events.finished=ppp_finished; + if (establish_ppp(&conn->ppp)) + { + close(pptp_sock); + send_pptp_stop_ctrl_conn_rqst(conn,0,0); + conn->state=STATE_FIN; + conn->hnd.twait=1000; + }else conn->state=STATE_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=container_of(h,typeof(*conn),hnd); + 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==EAGAIN) 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=container_of(h,typeof(*conn),hnd); + 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) +{ +} + +static void ppp_started(struct ppp_t *ppp) +{ + log_msg("ppp_started\n"); +} +static void ppp_finished(struct ppp_t *ppp) +{ + struct pptp_conn_t *conn=container_of(ppp,typeof(*conn),ppp); + + log_msg("ppp_finished\n"); + close(conn->ppp.fd); + send_pptp_stop_ctrl_conn_rqst(conn,0,0); + conn->state=STATE_FIN; + conn->hnd.twait=1000; +} -- cgit v1.2.3