diff options
Diffstat (limited to 'accel-pptpd/ppp')
-rw-r--r-- | accel-pptpd/ppp/CMakeLists.txt | 19 | ||||
-rw-r--r-- | accel-pptpd/ppp/ipcp_opt_dns.c | 146 | ||||
-rw-r--r-- | accel-pptpd/ppp/ipcp_opt_ipaddr.c | 147 | ||||
-rw-r--r-- | accel-pptpd/ppp/lcp_opt_accomp.c | 92 | ||||
-rw-r--r-- | accel-pptpd/ppp/lcp_opt_magic.c | 83 | ||||
-rw-r--r-- | accel-pptpd/ppp/lcp_opt_mru.c | 123 | ||||
-rw-r--r-- | accel-pptpd/ppp/lcp_opt_pcomp.c | 92 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp.c | 492 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp.h | 138 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_auth.c | 320 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_auth.h | 34 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_ccp.c | 577 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_ccp.h | 94 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_fsm.c | 534 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_fsm.h | 65 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_ipcp.c | 568 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_ipcp.h | 94 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_lcp.c | 659 | ||||
-rw-r--r-- | accel-pptpd/ppp/ppp_lcp.h | 134 |
19 files changed, 4411 insertions, 0 deletions
diff --git a/accel-pptpd/ppp/CMakeLists.txt b/accel-pptpd/ppp/CMakeLists.txt new file mode 100644 index 00000000..f4c0f04a --- /dev/null +++ b/accel-pptpd/ppp/CMakeLists.txt @@ -0,0 +1,19 @@ +SET(target ppp) +SET(sources_c + ppp.c + ppp_fsm.c + ppp_lcp.c + lcp_opt_mru.c + lcp_opt_magic.c + lcp_opt_pcomp.c + lcp_opt_accomp.c + ppp_auth.c + ppp_ipcp.c + ipcp_opt_ipaddr.c + ipcp_opt_dns.c + ppp_ccp.c +) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_LIBRARY(${target} SHARED ${sources_c}) + diff --git a/accel-pptpd/ppp/ipcp_opt_dns.c b/accel-pptpd/ppp/ipcp_opt_dns.c new file mode 100644 index 00000000..b7417989 --- /dev/null +++ b/accel-pptpd/ppp/ipcp_opt_dns.c @@ -0,0 +1,146 @@ +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include "ppp.h" +#include "ppp_ipcp.h" +#include "log.h" +#include "ipdb.h" + +static struct ipcp_option_t *dns1_init(struct ppp_ipcp_t *ipcp); +static struct ipcp_option_t *dns2_init(struct ppp_ipcp_t *ipcp); +static void dns_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt); +static int dns_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +static int dns_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +static int dns_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +static void dns1_print(void (*print)(const char *fmt,...),struct ipcp_option_t*, uint8_t *ptr); +static void dns2_print(void (*print)(const char *fmt,...),struct ipcp_option_t*, uint8_t *ptr); + +struct dns_option_t +{ + struct ipcp_option_t opt; + in_addr_t addr; +}; + +static struct ipcp_option_handler_t dns1_opt_hnd= +{ + .init=dns1_init, + .send_conf_req=dns_send_conf_req, + .send_conf_nak=dns_send_conf_nak, + .recv_conf_req=dns_recv_conf_req, + .free=dns_free, + .print=dns1_print, +}; +static struct ipcp_option_handler_t dns2_opt_hnd= +{ + .init=dns2_init, + .send_conf_req=dns_send_conf_req, + .send_conf_nak=dns_send_conf_nak, + .recv_conf_req=dns_recv_conf_req, + .free=dns_free, + .print=dns2_print, +}; + +static struct ipcp_option_t *dns1_init(struct ppp_ipcp_t *ipcp) +{ + struct dns_option_t *dns_opt=malloc(sizeof(*dns_opt)); + memset(dns_opt,0,sizeof(*dns_opt)); + dns_opt->opt.id=CI_DNS1; + dns_opt->opt.len=6; + + return &dns_opt->opt; +} + +static struct ipcp_option_t *dns2_init(struct ppp_ipcp_t *ipcp) +{ + struct dns_option_t *dns_opt=malloc(sizeof(*dns_opt)); + memset(dns_opt,0,sizeof(*dns_opt)); + dns_opt->opt.id=CI_DNS2; + dns_opt->opt.len=6; + + return &dns_opt->opt; +} + +static void dns_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt) +{ + struct dns_option_t *dns_opt=container_of(opt,typeof(*dns_opt),opt); + + free(dns_opt); +} + +static int dns_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct dns_option_t *dns_opt=container_of(opt,typeof(*dns_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + + if (!dns_opt->addr) + return 0; + opt32->hdr.id=dns_opt->opt.id; + opt32->hdr.len=6; + opt32->val=dns_opt->addr; + return 6; +} + +static int dns_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct dns_option_t *dns_opt=container_of(opt,typeof(*dns_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + opt32->hdr.id=dns_opt->opt.id; + opt32->hdr.len=6; + opt32->val=dns_opt->addr; + return 6; +} + +static int dns_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct dns_option_t *dns_opt=container_of(opt,typeof(*dns_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + + if (!dns_opt->addr) + { + if (dns_opt->opt.id==CI_DNS1) dns_opt->addr=inet_addr("10.0.0.1"); + else dns_opt->addr=inet_addr("10.0.0.2"); + + if (!dns_opt->addr) + { + dns_opt->addr=opt32->val; + return IPCP_OPT_ACK; + } + } + + if (dns_opt->addr==opt32->val) + return IPCP_OPT_ACK; + + return IPCP_OPT_NAK; +} + +static void dns1_print(void (*print)(const char *fmt,...),struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct dns_option_t *dns_opt=container_of(opt,typeof(*dns_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + struct in_addr in; + + if (ptr) in.s_addr=opt32->val; + else in.s_addr=dns_opt->addr; + + print("<dns1 %s>",inet_ntoa(in)); +} + +static void dns2_print(void (*print)(const char *fmt,...),struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct dns_option_t *dns_opt=container_of(opt,typeof(*dns_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + struct in_addr in; + + if (ptr) in.s_addr=opt32->val; + else in.s_addr=dns_opt->addr; + + print("<dns2 %s>",inet_ntoa(in)); +} + +static void __init dns_opt_init() +{ + ipcp_option_register(&dns1_opt_hnd); + ipcp_option_register(&dns2_opt_hnd); +} + diff --git a/accel-pptpd/ppp/ipcp_opt_ipaddr.c b/accel-pptpd/ppp/ipcp_opt_ipaddr.c new file mode 100644 index 00000000..2fa92519 --- /dev/null +++ b/accel-pptpd/ppp/ipcp_opt_ipaddr.c @@ -0,0 +1,147 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <linux/if_ppp.h> + +#include "ppp.h" +#include "ppp_ipcp.h" +#include "log.h" +#include "ipdb.h" + +static struct ipcp_option_t *ipaddr_init(struct ppp_ipcp_t *ipcp); +static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt); +static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +static int ipaddr_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +//static int ipaddr_recv_conf_ack(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr); +static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t*, uint8_t *ptr); + +struct ipaddr_option_t +{ + struct ipcp_option_t opt; + in_addr_t addr; + in_addr_t peer_addr; +}; + +static struct ipcp_option_handler_t ipaddr_opt_hnd= +{ + .init=ipaddr_init, + .send_conf_req=ipaddr_send_conf_req, + .send_conf_nak=ipaddr_send_conf_nak, + .recv_conf_req=ipaddr_recv_conf_req, + .free=ipaddr_free, + .print=ipaddr_print, +}; + +static struct ipcp_option_t *ipaddr_init(struct ppp_ipcp_t *ipcp) +{ + struct ipaddr_option_t *ipaddr_opt=malloc(sizeof(*ipaddr_opt)); + memset(ipaddr_opt,0,sizeof(*ipaddr_opt)); + ipdb_get(&ipaddr_opt->addr,&ipaddr_opt->peer_addr); + ipaddr_opt->opt.id=CI_ADDR; + ipaddr_opt->opt.len=6; + + return &ipaddr_opt->opt; +} + +static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt) +{ + struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); + + free(ipaddr_opt); +} + +static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + opt32->hdr.id=CI_ADDR; + opt32->hdr.len=6; + opt32->val=ipaddr_opt->addr; + return 6; +} + +static int ipaddr_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + opt32->hdr.id=CI_ADDR; + opt32->hdr.len=6; + opt32->val=ipaddr_opt->peer_addr; + return 6; +} + +static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct ipaddr_option_t *ipaddr_opt = container_of(opt,typeof(*ipaddr_opt), opt); + struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t*)ptr; + struct ifreq ifr; + struct sockaddr_in addr; + struct npioctl np; + + if (ipaddr_opt->peer_addr == opt32->val) + goto ack; + + if (!ipaddr_opt->peer_addr) { + ipaddr_opt->peer_addr = opt32->val; + goto ack; + } + + return IPCP_OPT_NAK; + +ack: + memset(&ifr, 0, sizeof(ifr)); + memset(&addr, 0, sizeof(addr)); + + sprintf(ifr.ifr_name,"ppp%i",ipcp->ppp->unit_idx); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ipaddr_opt->addr; + memcpy(&ifr.ifr_addr,&addr,sizeof(addr)); + + if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) + log_error("\nipcp: failed to set PA address: %s\n", strerror(errno)); + + addr.sin_addr.s_addr = ipaddr_opt->peer_addr; + memcpy(&ifr.ifr_dstaddr,&addr,sizeof(addr)); + + if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) + log_error("\nipcp: failed to set remote PA address: %s\n", strerror(errno)); + + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr)) + log_error("\nipcp: failed to get interface flags: %s\n", strerror(errno)); + + ifr.ifr_flags |= IFF_UP | IFF_POINTOPOINT; + + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) + log_error("\nipcp: failed to set interface flags: %s\n", strerror(errno)); + + np.protocol = PPP_IP; + np.mode = NPMODE_PASS; + + if (ioctl(ipcp->ppp->unit_fd, PPPIOCSNPMODE, &np)) + log_error("\nipcp: failed to set NP mode: %s\n", strerror(errno)); + + return IPCP_OPT_ACK; +} + +static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t *opt, uint8_t *ptr) +{ + struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); + struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + struct in_addr in; + + if (ptr) in.s_addr=opt32->val; + else in.s_addr=ipaddr_opt->addr; + + print("<addr %s>",inet_ntoa(in)); +} + +static void __init ipaddr_opt_init() +{ + ipcp_option_register(&ipaddr_opt_hnd); +} + diff --git a/accel-pptpd/ppp/lcp_opt_accomp.c b/accel-pptpd/ppp/lcp_opt_accomp.c new file mode 100644 index 00000000..c4c221ce --- /dev/null +++ b/accel-pptpd/ppp/lcp_opt_accomp.c @@ -0,0 +1,92 @@ +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include "ppp.h" +#include "ppp_lcp.h" +#include "log.h" + +static struct lcp_option_t *accomp_init(struct ppp_lcp_t *lcp); +static void accomp_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt); +static int accomp_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int accomp_send_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int accomp_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static void accomp_print(void (*print)(const char *fmt,...),struct lcp_option_t*, uint8_t *ptr); + +struct accomp_option_t +{ + struct lcp_option_t opt; + int accomp; // 0 - disabled, 1 - enabled, 2 - allow,disabled, 3 - allow,enabled +}; + +static struct lcp_option_handler_t accomp_opt_hnd= +{ + .init=accomp_init, + .send_conf_req=accomp_send_conf_req, + .send_conf_nak=accomp_send_conf_nak, + .recv_conf_req=accomp_recv_conf_req, + .free=accomp_free, + .print=accomp_print, +}; + +static struct lcp_option_t *accomp_init(struct ppp_lcp_t *lcp) +{ + struct accomp_option_t *accomp_opt=malloc(sizeof(*accomp_opt)); + memset(accomp_opt,0,sizeof(*accomp_opt)); + accomp_opt->accomp=0; + accomp_opt->opt.id=CI_ACCOMP; + accomp_opt->opt.len=2; + + return &accomp_opt->opt; +} + +static void accomp_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) +{ + struct accomp_option_t *accomp_opt=container_of(opt,typeof(*accomp_opt),opt); + + free(accomp_opt); +} + +static int accomp_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct accomp_option_t *accomp_opt=container_of(opt,typeof(*accomp_opt),opt); + struct lcp_opt_hdr_t *opt0=(struct lcp_opt_hdr_t*)ptr; + if (accomp_opt->accomp==1 || accomp_opt->accomp==3) + { + opt0->id=CI_ACCOMP; + opt0->len=2; + return 2; + } + return 0; +} + +static int accomp_send_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct accomp_option_t *accomp_opt=container_of(opt,typeof(*accomp_opt),opt); + struct lcp_opt_hdr_t *opt0=(struct lcp_opt_hdr_t*)ptr; + opt0->id=CI_ACCOMP; + opt0->len=2; + return 2; +} + +static int accomp_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct accomp_option_t *accomp_opt=container_of(opt,typeof(*accomp_opt),opt); + + if (accomp_opt->accomp>0) + { + accomp_opt->accomp=1; + return LCP_OPT_ACK; + }else return LCP_OPT_REJ; +} + +static void accomp_print(void (*print)(const char *fmt,...),struct lcp_option_t *opt, uint8_t *ptr) +{ + print("<accomp>"); +} + +static void __init accomp_opt_init() +{ + lcp_option_register(&accomp_opt_hnd); +} + diff --git a/accel-pptpd/ppp/lcp_opt_magic.c b/accel-pptpd/ppp/lcp_opt_magic.c new file mode 100644 index 00000000..dc94ac62 --- /dev/null +++ b/accel-pptpd/ppp/lcp_opt_magic.c @@ -0,0 +1,83 @@ +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include "ppp.h" +#include "ppp_lcp.h" +#include "log.h" + +static struct lcp_option_t *magic_init(struct ppp_lcp_t *lcp); +static void magic_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt); +static int magic_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int magic_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static void magic_print(void (*print)(const char *fmt,...),struct lcp_option_t*, uint8_t *ptr); + +struct magic_option_t +{ + struct lcp_option_t opt; + int magic; +}; + +static struct lcp_option_handler_t magic_opt_hnd= +{ + .init=magic_init, + .send_conf_req=magic_send_conf_req, + .recv_conf_req=magic_recv_conf_req, + .free=magic_free, + .print=magic_print, +}; + +static struct lcp_option_t *magic_init(struct ppp_lcp_t *lcp) +{ + struct magic_option_t *magic_opt=malloc(sizeof(*magic_opt)); + memset(magic_opt,0,sizeof(*magic_opt)); + magic_opt->magic=random(); + magic_opt->opt.id=CI_MAGIC; + magic_opt->opt.len=6; + + lcp->magic = magic_opt->magic; + + return &magic_opt->opt; +} + +static void magic_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) +{ + struct magic_option_t *magic_opt=container_of(opt,typeof(*magic_opt),opt); + + free(magic_opt); +} + +static int magic_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct magic_option_t *magic_opt=container_of(opt,typeof(*magic_opt),opt); + struct lcp_opt32_t *opt32=(struct lcp_opt32_t*)ptr; + opt32->hdr.id=CI_MAGIC; + opt32->hdr.len=6; + opt32->val=htonl(magic_opt->magic); + return 6; +} + +static int magic_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct magic_option_t *magic_opt=container_of(opt,typeof(*magic_opt),opt); + struct lcp_opt32_t *opt32=(struct lcp_opt32_t*)ptr; + + if (magic_opt->magic==ntohl(opt32->val)) + { + log_error("loop detected"); + return -1; + } + return LCP_OPT_ACK; +} + +static void magic_print(void (*print)(const char *fmt,...),struct lcp_option_t *opt, uint8_t *ptr) +{ + struct magic_option_t *magic_opt=container_of(opt,typeof(*magic_opt),opt); + + print("<magic %04x>",magic_opt->magic); +} + +static void __init magic_opt_init() +{ + lcp_option_register(&magic_opt_hnd); +} diff --git a/accel-pptpd/ppp/lcp_opt_mru.c b/accel-pptpd/ppp/lcp_opt_mru.c new file mode 100644 index 00000000..e1c13b47 --- /dev/null +++ b/accel-pptpd/ppp/lcp_opt_mru.c @@ -0,0 +1,123 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <linux/if_ppp.h> +#include <sys/ioctl.h> + +#include "ppp.h" +#include "ppp_lcp.h" +#include "log.h" + +#define MAX_MTU 1436 + +static struct lcp_option_t *mru_init(struct ppp_lcp_t *lcp); +static void mru_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt); +static int mru_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int mru_send_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int mru_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int mru_recv_conf_ack(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static void mru_print(void (*print)(const char *fmt,...),struct lcp_option_t*, uint8_t *ptr); + +struct mru_option_t +{ + struct lcp_option_t opt; + int mru; + int mtu; +}; + +static struct lcp_option_handler_t mru_opt_hnd= +{ + .init=mru_init, + .send_conf_req=mru_send_conf_req, + .send_conf_nak=mru_send_conf_nak, + .recv_conf_req=mru_recv_conf_req, + .recv_conf_ack=mru_recv_conf_ack, + .free=mru_free, + .print=mru_print, +}; + +static struct lcp_option_t *mru_init(struct ppp_lcp_t *lcp) +{ + struct mru_option_t *mru_opt=malloc(sizeof(*mru_opt)); + memset(mru_opt,0,sizeof(*mru_opt)); + mru_opt->mtu=0; + mru_opt->mru=MAX_MTU; + mru_opt->opt.id=CI_MRU; + mru_opt->opt.len=4; + + return &mru_opt->opt; +} + +static void mru_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) +{ + struct mru_option_t *mru_opt=container_of(opt,typeof(*mru_opt),opt); + + free(mru_opt); +} + +static int mru_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct mru_option_t *mru_opt=container_of(opt,typeof(*mru_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + opt16->hdr.id=CI_MRU; + opt16->hdr.len=4; + opt16->val=htons(mru_opt->mru); + return 4; +} + +static int mru_send_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct mru_option_t *mru_opt=container_of(opt,typeof(*mru_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + opt16->hdr.id=CI_MRU; + opt16->hdr.len=4; + opt16->val=htons(mru_opt->mtu); + return 4; +} + +static int mru_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct mru_option_t *mru_opt=container_of(opt,typeof(*mru_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + + if (!mru_opt->mtu || mru_opt->mtu==ntohs(opt16->val)) + { + mru_opt->mtu=ntohs(opt16->val); + return LCP_OPT_ACK; + }else return LCP_OPT_NAK; +} + +static int mru_recv_conf_ack(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct mru_option_t *mru_opt = container_of(opt,typeof(*mru_opt), opt); + struct ifreq ifr = { + .ifr_mtu = mru_opt->mtu, + }; + + sprintf(ifr.ifr_name,"ppp%i",lcp->ppp->unit_idx); + + if (ioctl(lcp->ppp->unit_fd, PPPIOCSMRU, &mru_opt->mru)) + log_error("\nlcp:mru: failed to set MRU: %s\n", strerror(errno)); + + if (ioctl(sock_fd, SIOCSIFMTU, &ifr)) + log_error("\nlcp:mru: failed to set MTU: %s\n", strerror(errno)); + + return 0; +} + +static void mru_print(void (*print)(const char *fmt,...),struct lcp_option_t *opt, uint8_t *ptr) +{ + struct mru_option_t *mru_opt=container_of(opt,typeof(*mru_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + + if (ptr) print("<mru %i>",ntohs(opt16->val)); + else print("<mru %i>",mru_opt->mru); +} + +static void __init mru_opt_init() +{ + lcp_option_register(&mru_opt_hnd); +} + diff --git a/accel-pptpd/ppp/lcp_opt_pcomp.c b/accel-pptpd/ppp/lcp_opt_pcomp.c new file mode 100644 index 00000000..8700bf49 --- /dev/null +++ b/accel-pptpd/ppp/lcp_opt_pcomp.c @@ -0,0 +1,92 @@ +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include "ppp.h" +#include "ppp_lcp.h" +#include "log.h" + +static struct lcp_option_t *pcomp_init(struct ppp_lcp_t *lcp); +static void pcomp_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt); +static int pcomp_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int pcomp_send_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int pcomp_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static void pcomp_print(void (*print)(const char *fmt,...),struct lcp_option_t*, uint8_t *ptr); + +struct pcomp_option_t +{ + struct lcp_option_t opt; + int pcomp; // 0 - disabled, 1 - enabled, 2 - allow,disabled, 3 - allow,enabled +}; + +static struct lcp_option_handler_t pcomp_opt_hnd= +{ + .init=pcomp_init, + .send_conf_req=pcomp_send_conf_req, + .send_conf_nak=pcomp_send_conf_nak, + .recv_conf_req=pcomp_recv_conf_req, + .free=pcomp_free, + .print=pcomp_print, +}; + +static struct lcp_option_t *pcomp_init(struct ppp_lcp_t *lcp) +{ + struct pcomp_option_t *pcomp_opt=malloc(sizeof(*pcomp_opt)); + memset(pcomp_opt,0,sizeof(*pcomp_opt)); + pcomp_opt->pcomp=0; + pcomp_opt->opt.id=CI_PCOMP; + pcomp_opt->opt.len=2; + + return &pcomp_opt->opt; +} + +static void pcomp_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) +{ + struct pcomp_option_t *pcomp_opt=container_of(opt,typeof(*pcomp_opt),opt); + + free(pcomp_opt); +} + +static int pcomp_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct pcomp_option_t *pcomp_opt=container_of(opt,typeof(*pcomp_opt),opt); + struct lcp_opt_hdr_t *opt0=(struct lcp_opt_hdr_t*)ptr; + if (pcomp_opt->pcomp==1 || pcomp_opt->pcomp==3) + { + opt0->id=CI_PCOMP; + opt0->len=2; + return 2; + } + return 0; +} + +static int pcomp_send_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct pcomp_option_t *pcomp_opt=container_of(opt,typeof(*pcomp_opt),opt); + struct lcp_opt_hdr_t *opt0=(struct lcp_opt_hdr_t*)ptr; + opt0->id=CI_PCOMP; + opt0->len=2; + return 2; +} + +static int pcomp_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct pcomp_option_t *pcomp_opt=container_of(opt,typeof(*pcomp_opt),opt); + + if (pcomp_opt->pcomp>0) + { + pcomp_opt->pcomp=1; + return LCP_OPT_ACK; + }else return LCP_OPT_REJ; +} + +static void pcomp_print(void (*print)(const char *fmt,...),struct lcp_option_t *opt, uint8_t *ptr) +{ + print("<pcomp>"); +} + +static void __init pcomp_opt_init() +{ + lcp_option_register(&pcomp_opt_hnd); +} + diff --git a/accel-pptpd/ppp/ppp.c b/accel-pptpd/ppp/ppp.c new file mode 100644 index 00000000..5c2eb910 --- /dev/null +++ b/accel-pptpd/ppp/ppp.c @@ -0,0 +1,492 @@ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> + +#include "triton.h" + +#include "ppp.h" +#include "ppp_fsm.h" +#include "log.h" + +static LIST_HEAD(layers); + +struct layer_node_t +{ + struct list_head entry; + int order; + struct list_head items; +}; + +static int ppp_chan_read(struct triton_md_handler_t*); +static int ppp_unit_read(struct triton_md_handler_t*); +static void init_layers(struct ppp_t *); +static void free_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)); + return ppp; +} + +static void free_ppp(struct ppp_t *ppp) +{ + free(ppp->chan_buf); + free(ppp->unit_buf); +} + +int __export establish_ppp(struct ppp_t *ppp) +{ + /* Open an instance of /dev/ppp and connect the channel to it */ + if (ioctl(ppp->fd, PPPIOCGCHAN, &ppp->chan_idx)==-1) + { + log_error("Couldn't get channel number\n"); + return -1; + } + + ppp->chan_fd=open("/dev/ppp", O_RDWR); + if (ppp->chan_fd<0) + { + log_error("Couldn't reopen /dev/ppp\n"); + return -1; + } + + if (ioctl(ppp->chan_fd, PPPIOCATTCHAN, &ppp->chan_idx)<0) + { + log_error("Couldn't attach to channel %d\n", ppp->chan_idx); + goto exit_close_chan; + } + + ppp->unit_fd=open("/dev/ppp", O_RDWR); + if (ppp->unit_fd<0) + { + log_error("Couldn't reopen /dev/ppp\n"); + goto exit_close_chan; + } + + ppp->unit_idx=-1; + if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx)<0) + { + log_error("Couldn't create new ppp unit\n"); + goto exit_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_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); + + INIT_LIST_HEAD(&ppp->chan_handlers); + INIT_LIST_HEAD(&ppp->unit_handlers); + + init_layers(ppp); + + if (list_empty(&ppp->layers)) + { + log_error("no layers to start\n"); + goto exit_close_unit; + } + + if (fcntl(ppp->chan_fd, F_SETFL, O_NONBLOCK)) { + log_error("ppp: cann't to set nonblocking mode: %s\n", strerror(errno)); + goto exit_close_unit; + } + + if (fcntl(ppp->unit_fd, F_SETFL, O_NONBLOCK)) { + log_error("ppp: cann't to set nonblocking mode: %s\n", strerror(errno)); + 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->ctrl->ctx, &ppp->chan_hnd); + triton_md_register_handler(ppp->ctrl->ctx, &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_close_unit: + close(ppp->unit_fd); +exit_close_chan: + close(ppp->chan_fd); + + free_ppp(ppp); + + return -1; +} + +static 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); + + ppp->unit_fd = -1; + ppp->chan_fd = -1; + + free(ppp->unit_buf); + free(ppp->chan_buf); + + free_layers(ppp); + + log_debug("ppp destablished\n"); + + ppp->ctrl->finished(ppp); +} + +void print_buf(uint8_t *buf,int size) +{ + int i; + for(i=0;i<size;i++) + printf("%x ",buf[i]); + printf("\n"); +} + +int __export ppp_chan_send(struct ppp_t *ppp, void *data, int size) +{ + int n; + + //printf("ppp_chan_send: "); + //print_buf((uint8_t*)data,size); + + n=write(ppp->chan_fd,data,size); + if (n<size) + log_error("ppp_chan_send: short write %i, excpected %i\n",n,size); + return n; +} + +int __export ppp_unit_send(struct ppp_t *ppp, void *data, int size) +{ + int n; + + //printf("ppp_unit_send: "); + //print_buf((uint8_t*)data,size); + + n=write(ppp->unit_fd,data,size); + if (n<size) + log_error("ppp_unit_send: short write %i, excpected %i\n",n,size); + return n; +} + +static int ppp_chan_read(struct triton_md_handler_t *h) +{ + struct ppp_t *ppp = container_of(h, typeof(*ppp), chan_hnd); + struct ppp_handler_t *ppp_h; + uint16_t proto; + + while(1) { +cont: + ppp->chan_buf_size = read(h->fd, ppp->chan_buf, PPP_MRU); + if (ppp->chan_buf_size < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return 0; + log_error("ppp_chan_read: %s\n",strerror(errno)); + return 0; + } + + //printf("ppp_chan_read: "); + //print_buf(ppp->chan_buf,ppp->chan_buf_size); + + if (ppp->chan_buf_size < 2) { + log_error("ppp_chan_read: short read %i\n", ppp->chan_buf_size); + continue; + } + + proto = ntohs(*(uint16_t*)ppp->chan_buf); + list_for_each_entry(ppp_h, &ppp->chan_handlers, entry) { + if (ppp_h->proto == proto) { + ppp_h->recv(ppp_h); + if (ppp->chan_fd == -1) { + ppp->ctrl->finished(ppp); + return 1; + } + goto cont; + } + } + + log_warn("ppp_chan_read: discarding unknown packet %x\n", proto); + } +} + +static int ppp_unit_read(struct triton_md_handler_t *h) +{ + struct ppp_t *ppp = container_of(h, typeof(*ppp), unit_hnd); + struct ppp_handler_t *ppp_h; + uint16_t proto; + + while (1) { +cont: + ppp->unit_buf_size = read(h->fd, ppp->unit_buf, PPP_MRU); + if (ppp->unit_buf_size < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return 0; + log_error("ppp_chan_read: %s\n",strerror(errno)); + return 0; + } + + //printf("ppp_unit_read: "); + //print_buf(ppp->unit_buf,ppp->unit_buf_size); + + if (ppp->unit_buf_size < 2) { + log_error("ppp_chan_read: short read %i\n", ppp->unit_buf_size); + continue; + } + + proto=ntohs(*(uint16_t*)ppp->unit_buf); + list_for_each_entry(ppp_h, &ppp->unit_handlers, entry) { + if (ppp_h->proto == proto) { + ppp_h->recv(ppp_h); + if (ppp->unit_fd == -1) { + ppp->ctrl->finished(ppp); + return 1; + } + goto cont; + } + } + + log_warn("ppp_unit_read: discarding unknown packet %x\n",proto); + } +} + +void __export 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) + { + ppp->ctrl->started(ppp); + }else + { + n=list_entry(n->entry.next,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + { + d->starting=1; + d->layer->start(d); + } + } +} + +void __export ppp_layer_finished(struct ppp_t *ppp, struct ppp_layer_data_t *d) +{ + struct layer_node_t *n=d->node; + + d->starting=0; + d->started=0; + + list_for_each_entry(n,&ppp->layers,entry) + { + list_for_each_entry(d,&n->items,entry) + { + if (d->starting) + return; + } + } + + destablish_ppp(ppp); +} + +void __export ppp_terminate(struct ppp_t *ppp, int hard) +{ + struct layer_node_t *n; + struct ppp_layer_data_t *d; + int s = 0; + + log_debug("ppp_terminate\n"); + + if (hard) { + destablish_ppp(ppp); + return; + } + + list_for_each_entry(n,&ppp->layers,entry) { + list_for_each_entry(d,&n->items,entry) { + if (d->starting) { + s = 1; + d->layer->finish(d); + } + } + } + if (s) + return; + destablish_ppp(ppp); +} + +void __export ppp_register_chan_handler(struct ppp_t *ppp,struct ppp_handler_t *h) +{ + list_add_tail(&h->entry,&ppp->chan_handlers); +} +void __export ppp_register_unit_handler(struct ppp_t *ppp,struct ppp_handler_t *h) +{ + list_add_tail(&h->entry,&ppp->unit_handlers); +} +void __export 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 __export 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 (order<n->order) + { + 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 __export 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 free_layers(struct ppp_t *ppp) +{ + struct layer_node_t *n; + struct ppp_layer_data_t *d; + + while (!list_empty(&ppp->layers)) { + n = list_entry(ppp->layers.next, typeof(*n), entry); + while (!list_empty(&n->items)) { + d = list_entry(n->items.next, typeof(*d), entry); + list_del(&d->entry); + d->layer->free(d); + } + list_del(&n->entry); + free(n); + } +} + +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->starting=1; + 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; +} + +int sock_fd; +static void __init ppp_init(void) +{ + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd < 0) { + perror("socket"); + _exit(EXIT_FAILURE); + } +} diff --git a/accel-pptpd/ppp/ppp.h b/accel-pptpd/ppp/ppp.h new file mode 100644 index 00000000..d880fc2a --- /dev/null +++ b/accel-pptpd/ppp/ppp.h @@ -0,0 +1,138 @@ +#ifndef PPP_H +#define PPP_H + +#include <sys/types.h> + +#include "triton.h" +#include "list.h" + +/* + * Packet header = Code, id, length. + */ +#define PPP_HEADERLEN 4 +#define PPP_MTU 1500 + +/* + * Timeouts. + */ +#define DEFTIMEOUT 3 /* Timeout time in seconds */ +#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ + +#define PPP_LAYER_LCP 1 +#define PPP_LAYER_AUTH 2 +#define PPP_LAYER_CCP 3 +#define PPP_LAYER_IPCP 4 + +#define AUTH_MAX 3 + +struct ppp_t; + +struct ppp_ctrl_t +{ + struct triton_ctx_t *ctx; + void (*started)(struct ppp_t*); + void (*finished)(struct ppp_t*); +}; + +struct ppp_t +{ + struct triton_md_handler_t chan_hnd; + struct triton_md_handler_t unit_hnd; + int fd; + int chan_fd; + int unit_fd; + + int chan_idx; + int unit_idx; + + char *chan_name; + + struct ppp_ctrl_t *ctrl; + + int log:1; + + void *chan_buf; + int chan_buf_size; + void *unit_buf; + int unit_buf_size; + + struct list_head chan_handlers; + struct list_head unit_handlers; + + struct list_head layers; + + 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 starting:1; + 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; + int proto; + void (*recv)(struct ppp_handler_t*); +}; + +struct ppp_t *alloc_ppp(void); +int establish_ppp(struct ppp_t *ppp); +int ppp_chan_send(struct ppp_t *ppp, void *data, int size); +int ppp_unit_send(struct ppp_t *ppp, void *data, int size); + +struct ppp_fsm_t* ppp_lcp_init(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, int hard); + +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 *); + +extern int sock_fd; // internet socket for ioctls +#endif diff --git a/accel-pptpd/ppp/ppp_auth.c b/accel-pptpd/ppp/ppp_auth.c new file mode 100644 index 00000000..32f63d5b --- /dev/null +++ b/accel-pptpd/ppp/ppp_auth.c @@ -0,0 +1,320 @@ +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include "ppp.h" +#include "ppp_lcp.h" +#include "log.h" + +#include "ppp_auth.h" + + +static LIST_HEAD(auth_handlers); +static int extra_opt_len=0; + +static struct lcp_option_t *auth_init(struct ppp_lcp_t *lcp); +static void auth_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt); +static int auth_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int auth_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int auth_recv_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +static int auth_recv_conf_rej(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); +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; + struct list_head auth_list; + struct auth_data_t *auth; + 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, + .send_conf_req=auth_send_conf_req, + .send_conf_nak=auth_send_conf_req, + .recv_conf_req=auth_recv_conf_req, + .recv_conf_nak=auth_recv_conf_nak, + .recv_conf_rej=auth_recv_conf_rej, + .recv_conf_ack=auth_recv_conf_ack, + .free=auth_free, + .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_layer_data_t *ad; + + 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,&ad->auth_opt.auth_list); + } + + return &ad->auth_opt.opt; +} + +static void auth_free(struct ppp_lcp_t *lcp, struct lcp_option_t *opt) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + struct auth_data_t *d; + + while(!list_empty(&auth_opt->auth_list)) + { + d=list_entry(auth_opt->auth_list.next,typeof(*d),entry); + list_del(&d->entry); + d->h->free(lcp->ppp,d); + } +} + +static int auth_send_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + struct auth_data_t *d; + int n; + + if (list_empty(&auth_opt->auth_list)) return 0; + + if (!auth_opt->auth || auth_opt->auth->state==LCP_OPT_NAK) + { + list_for_each_entry(d,&auth_opt->auth_list,entry) + { + if (d->state==LCP_OPT_NAK || d->state==LCP_OPT_REJ) + continue; + auth_opt->auth=d; + break; + } + } + + opt16->hdr.id=CI_AUTH; + opt16->val=htons(auth_opt->auth->proto); + n=auth_opt->auth->h->send_conf_req(lcp->ppp,auth_opt->auth,(uint8_t*)(opt16+1)); + opt16->hdr.len=4+n; + + return 4+n; +} + +static int auth_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + struct auth_data_t *d; + int r; + + if (list_empty(&auth_opt->auth_list)) + return LCP_OPT_REJ; + + list_for_each_entry(d,&auth_opt->auth_list,entry) + { + if (d->proto==ntohs(opt16->val)) + { + r=d->h->recv_conf_req(lcp->ppp,d,(uint8_t*)(opt16+1)); + if (r==LCP_OPT_FAIL) + return LCP_OPT_FAIL; + if (r==LCP_OPT_REJ) + break; + auth_opt->peer_auth=d; + return r; + } + } + + list_for_each_entry(d,&auth_opt->auth_list,entry) + { + if (d->state!=LCP_OPT_NAK) + { + auth_opt->peer_auth=d; + return LCP_OPT_NAK; + } + } + + log_msg("cann't negotiate authentication type\n"); + return LCP_OPT_FAIL; +} + +static int auth_recv_conf_ack(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + + auth_opt->peer_auth=NULL; + + return 0; +} + +static int auth_recv_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + struct auth_data_t *d; + + if (!auth_opt->auth) + { + log_error("auth: unexcepcted configure-nak\n"); + return -1; + } + auth_opt->auth->state=LCP_OPT_NAK; + if (auth_opt->peer_auth) + auth_opt->auth=auth_opt->peer_auth; + + list_for_each_entry(d,&auth_opt->auth_list,entry) + { + if (d->state!=LCP_OPT_NAK) + return 0; + } + + log_msg("cann't negotiate authentication type\n"); + return -1; +} + +static int auth_recv_conf_rej(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + struct auth_data_t *d; + + if (!auth_opt->auth) + { + log_error("auth: unexcepcted configure-reject\n"); + return -1; + } + auth_opt->auth->state=LCP_OPT_NAK; + if (auth_opt->peer_auth) + auth_opt->auth=auth_opt->peer_auth; + + list_for_each_entry(d,&auth_opt->auth_list,entry) + { + if (d->state!=LCP_OPT_NAK) + return 0; + } + + log_msg("cann't negotiate authentication type\n"); + return -1; +} + +static void auth_print(void (*print)(const char *fmt,...),struct lcp_option_t *opt, uint8_t *ptr) +{ + struct auth_option_t *auth_opt=container_of(opt,typeof(*auth_opt),opt); + struct lcp_opt16_t *opt16=(struct lcp_opt16_t*)ptr; + struct auth_data_t *d; + + if (ptr) + { + list_for_each_entry(d,&auth_opt->auth_list,entry) + { + if (d->proto==ntohs(opt16->val)) + goto print_d; + } + + print("<auth %02x>",ntohs(opt16->val)); + return; + } + else if (auth_opt->auth) d=auth_opt->auth; + else return; + +print_d: + print("<auth %s>",d->h->name); +} + +static struct ppp_layer_data_t *auth_layer_init(struct ppp_t *ppp) +{ + 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; +} + +static void auth_layer_start(struct ppp_layer_data_t *ld) +{ + 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 + { + log_debug("auth_layer_started\n"); + ppp_layer_started(ad->ppp,ld); + } +} + +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); +} + +static void auth_layer_free(struct ppp_layer_data_t *ld) +{ + struct auth_layer_data_t *ad=container_of(ld,typeof(*ad),ld); + + log_debug("auth_layer_free\n"); + + free(ad); +} + +void __export auth_successed(struct ppp_t *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 __export auth_failed(struct ppp_t *ppp) +{ + ppp_terminate(ppp, 0); +} + +int __export 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/ppp_auth.h b/accel-pptpd/ppp/ppp_auth.h new file mode 100644 index 00000000..f1880d5d --- /dev/null +++ b/accel-pptpd/ppp/ppp_auth.h @@ -0,0 +1,34 @@ +#ifndef PPP_AUTH_H +#define PPP_AUTH_H + +#include "list.h" + +struct ppp_auth_handler_t; + +struct auth_data_t +{ + struct list_head entry; + int proto; + int state; + struct ppp_auth_handler_t *h; +}; + +struct ppp_auth_handler_t +{ + struct list_head entry; + const char *name; + struct auth_data_t* (*init)(struct ppp_t*); + int (*send_conf_req)(struct ppp_t*, struct auth_data_t*, uint8_t*); + int (*recv_conf_req)(struct ppp_t*, struct auth_data_t*, uint8_t*); + int (*start)(struct ppp_t*, struct auth_data_t*); + int (*finish)(struct ppp_t*, struct auth_data_t*); + void (*free)(struct ppp_t*,struct auth_data_t*); +}; + +int ppp_auth_register_handler(struct ppp_auth_handler_t*); + +void auth_successed(struct ppp_t *ppp); +void auth_failed(struct ppp_t *ppp); + +#endif + diff --git a/accel-pptpd/ppp/ppp_ccp.c b/accel-pptpd/ppp/ppp_ccp.c new file mode 100644 index 00000000..fe10886e --- /dev/null +++ b/accel-pptpd/ppp/ppp_ccp.c @@ -0,0 +1,577 @@ +#include <stdlib.h> +#include <string.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <arpa/inet.h> + +#include "triton.h" + +#include "log.h" + +#include "ppp.h" +#include "ppp_ccp.h" + +struct recv_opt_t +{ + struct list_head entry; + struct ccp_opt_hdr_t *hdr; + int len; + int state; + struct ccp_option_t *lopt; +}; + +static LIST_HEAD(option_handlers); + +static void ccp_layer_up(struct ppp_fsm_t*); +static void ccp_layer_down(struct ppp_fsm_t*); +static void send_conf_req(struct ppp_fsm_t*); +static void send_conf_ack(struct ppp_fsm_t*); +static void send_conf_nak(struct ppp_fsm_t*); +static void send_conf_rej(struct ppp_fsm_t*); +static void ccp_recv(struct ppp_handler_t*); + +static void ccp_options_init(struct ppp_ccp_t *ccp) +{ + struct ccp_option_t *lopt; + struct ccp_option_handler_t *h; + + INIT_LIST_HEAD(&ccp->options); + + list_for_each_entry(h,&option_handlers,entry) + { + lopt=h->init(ccp); + if (lopt) + { + lopt->h=h; + list_add_tail(&lopt->entry,&ccp->options); + ccp->conf_req_len+=lopt->len; + } + } +} + +static void ccp_options_free(struct ppp_ccp_t *ccp) +{ + struct ccp_option_t *lopt; + + while(!list_empty(&ccp->options)) + { + lopt=list_entry(ccp->options.next,typeof(*lopt),entry); + list_del(&lopt->entry); + lopt->h->free(ccp,lopt); + } +} + +static struct ppp_layer_data_t *ccp_layer_init(struct ppp_t *ppp) +{ + struct ppp_ccp_t *ccp=malloc(sizeof(*ccp)); + memset(ccp,0,sizeof(*ccp)); + + log_debug("ccp_layer_init\n"); + + ccp->ppp=ppp; + ccp->fsm.ppp=ppp; + + ccp->hnd.proto=PPP_CCP; + ccp->hnd.recv=ccp_recv; + + ppp_register_unit_handler(ppp,&ccp->hnd); + + ppp_fsm_init(&ccp->fsm); + + ccp->fsm.layer_up=ccp_layer_up; + ccp->fsm.layer_finished=ccp_layer_down; + ccp->fsm.send_conf_req=send_conf_req; + ccp->fsm.send_conf_ack=send_conf_ack; + ccp->fsm.send_conf_nak=send_conf_nak; + ccp->fsm.send_conf_rej=send_conf_rej; + + INIT_LIST_HEAD(&ccp->ropt_list); + + return &ccp->ld; +} + +void ccp_layer_start(struct ppp_layer_data_t *ld) +{ + struct ppp_ccp_t *ccp=container_of(ld,typeof(*ccp),ld); + + log_debug("ccp_layer_start\n"); + + ccp_options_init(ccp); + ppp_fsm_lower_up(&ccp->fsm); + ppp_fsm_open(&ccp->fsm); +} + +void ccp_layer_finish(struct ppp_layer_data_t *ld) +{ + struct ppp_ccp_t *ccp=container_of(ld,typeof(*ccp),ld); + + log_debug("ccp_layer_finish\n"); + + ppp_fsm_lower_down(&ccp->fsm); + + ppp_unregister_handler(ccp->ppp,&ccp->hnd); + ccp_options_free(ccp); + + ppp_layer_finished(ccp->ppp,ld); +} + +void ccp_layer_free(struct ppp_layer_data_t *ld) +{ + struct ppp_ccp_t *ccp=container_of(ld,typeof(*ccp),ld); + + log_debug("ccp_layer_free\n"); + + free(ccp); +} + +static void ccp_layer_up(struct ppp_fsm_t *fsm) +{ + struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm); + log_debug("ccp_layer_started\n"); + ppp_layer_started(ccp->ppp,&ccp->ld); +} + +static void ccp_layer_down(struct ppp_fsm_t *fsm) +{ + struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm); + log_debug("ccp_layer_finished\n"); + ppp_layer_finished(ccp->ppp,&ccp->ld); +} + +static void print_ropt(struct recv_opt_t *ropt) +{ + int i; + uint8_t *ptr=(uint8_t*)ropt->hdr; + + log_debug(" <"); + for(i=0; i<ropt->len; i++) + { + log_debug(" %x",ptr[i]); + } + log_debug(" >"); +} + +static void send_conf_req(struct ppp_fsm_t *fsm) +{ + struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm); + uint8_t *buf=malloc(ccp->conf_req_len), *ptr=buf; + struct ccp_hdr_t *ccp_hdr=(struct ccp_hdr_t*)ptr; + struct ccp_option_t *lopt; + int n; + + log_debug("send [CCP ConfReq"); + ccp_hdr->proto=htons(PPP_CCP); + ccp_hdr->code=CONFREQ; + ccp_hdr->id=++ccp->fsm.id; + ccp_hdr->len=0; + log_debug(" id=%x",ccp_hdr->id); + + ptr+=sizeof(*ccp_hdr); + + list_for_each_entry(lopt,&ccp->options,entry) + { + n=lopt->h->send_conf_req(ccp,lopt,ptr); + if (n) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,NULL); + ptr+=n; + } + } + + log_debug("]\n"); + + ccp_hdr->len=htons((ptr-buf)-2); + ppp_unit_send(ccp->ppp,ccp_hdr,ptr-buf); +} + +static void send_conf_ack(struct ppp_fsm_t *fsm) +{ + struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm); + struct ccp_hdr_t *hdr=(struct ccp_hdr_t*)ccp->ppp->unit_buf; + + hdr->code=CONFACK; + log_debug("send [CCP ConfAck id=%x ]\n",ccp->fsm.recv_id); + + ppp_unit_send(ccp->ppp,hdr,ntohs(hdr->len)+2); +} + +static void send_conf_nak(struct ppp_fsm_t *fsm) +{ + struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm); + uint8_t *buf=malloc(ccp->conf_req_len), *ptr=buf; + struct ccp_hdr_t *ccp_hdr=(struct ccp_hdr_t*)ptr; + struct recv_opt_t *ropt; + + log_debug("send [CCP ConfNak id=%x",ccp->fsm.recv_id); + + ccp_hdr->proto=htons(PPP_CCP); + ccp_hdr->code=CONFNAK; + ccp_hdr->id=ccp->fsm.recv_id; + ccp_hdr->len=0; + + ptr+=sizeof(*ccp_hdr); + + list_for_each_entry(ropt,&ccp->ropt_list,entry) + { + if (ropt->state==CCP_OPT_NAK) + { + log_debug(" "); + ropt->lopt->h->print(log_debug,ropt->lopt,NULL); + ptr+=ropt->lopt->h->send_conf_nak(ccp,ropt->lopt,ptr); + } + } + + log_debug("]\n"); + + ccp_hdr->len=htons((ptr-buf)-2); + ppp_unit_send(ccp->ppp,ccp_hdr,ptr-buf); +} + +static void send_conf_rej(struct ppp_fsm_t *fsm) +{ + struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm); + uint8_t *buf=malloc(ccp->ropt_len), *ptr=buf; + struct ccp_hdr_t *ccp_hdr=(struct ccp_hdr_t*)ptr; + struct recv_opt_t *ropt; + + log_debug("send [CCP ConfRej id=%x ",ccp->fsm.recv_id); + + ccp_hdr->proto=htons(PPP_CCP); + ccp_hdr->code=CONFREJ; + ccp_hdr->id=ccp->fsm.recv_id; + ccp_hdr->len=0; + + ptr+=sizeof(*ccp_hdr); + + list_for_each_entry(ropt,&ccp->ropt_list,entry) + { + if (ropt->state==CCP_OPT_REJ) + { + log_debug(" "); + if (ropt->lopt) ropt->lopt->h->print(log_debug,ropt->lopt,(uint8_t*)ropt->hdr); + else print_ropt(ropt); + memcpy(ptr,ropt->hdr,ropt->len); + ptr+=ropt->len; + } + } + + log_debug("]\n"); + + ccp_hdr->len=htons((ptr-buf)-2); + ppp_unit_send(ccp->ppp,ccp_hdr,ptr-buf); +} + +static int ccp_recv_conf_req(struct ppp_ccp_t *ccp,uint8_t *data,int size) +{ + struct ccp_opt_hdr_t *hdr; + struct recv_opt_t *ropt; + struct ccp_option_t *lopt; + int r,ret=1,ack=0; + + ccp->ropt_len=size; + + while(size>0) + { + hdr=(struct ccp_opt_hdr_t *)data; + + ropt=malloc(sizeof(*ropt)); + memset(ropt,0,sizeof(*ropt)); + if (hdr->len>size) ropt->len=size; + else ropt->len=hdr->len; + ropt->hdr=hdr; + ropt->state=CCP_OPT_NONE; + list_add_tail(&ropt->entry,&ccp->ropt_list); + + data+=ropt->len; + size-=ropt->len; + } + + list_for_each_entry(lopt,&ccp->options,entry) + lopt->state=CCP_OPT_NONE; + + log_debug("recv [CCP ConfReq id=%x",ccp->fsm.recv_id); + list_for_each_entry(ropt,&ccp->ropt_list,entry) + { + list_for_each_entry(lopt,&ccp->options,entry) + { + if (lopt->id==ropt->hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,(uint8_t*)ropt->hdr); + r=lopt->h->recv_conf_req(ccp,lopt,(uint8_t*)ropt->hdr); + if (ack) + { + lopt->state=CCP_OPT_REJ; + ropt->state=CCP_OPT_REJ; + }else + { + lopt->state=r; + ropt->state=r; + } + ropt->lopt=lopt; + if (r<ret) ret=r; + break; + } + } + if (ropt->state==CCP_OPT_ACK || ropt->state==CCP_OPT_NAK) + ack=1; + else if (!ropt->lopt) + { + log_debug(" "); + print_ropt(ropt); + ropt->state=CCP_OPT_REJ; + ret=CCP_OPT_REJ; + } + } + log_debug("]\n"); + + /*list_for_each_entry(lopt,&ccp->options,entry) + { + if (lopt->state==CCP_OPT_NONE) + { + r=lopt->h->recv_conf_req(ccp,lopt,NULL); + lopt->state=r; + if (r<ret) ret=r; + } + }*/ + + return ret; +} + +static void ccp_free_conf_req(struct ppp_ccp_t *ccp) +{ + struct recv_opt_t *ropt; + + while(!list_empty(&ccp->ropt_list)) + { + ropt=list_entry(ccp->ropt_list.next,typeof(*ropt),entry); + list_del(&ropt->entry); + free(ropt); + } +} + +static int ccp_recv_conf_rej(struct ppp_ccp_t *ccp,uint8_t *data,int size) +{ + struct ccp_opt_hdr_t *hdr; + struct ccp_option_t *lopt; + int res=0; + + log_debug("recv [CCP ConfRej id=%x",ccp->fsm.recv_id); + + if (ccp->fsm.recv_id!=ccp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct ccp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&ccp->options,entry) + { + if (lopt->id==hdr->id) + { + if (!lopt->h->recv_conf_rej) + res=-1; + else if (lopt->h->recv_conf_rej(ccp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static int ccp_recv_conf_nak(struct ppp_ccp_t *ccp,uint8_t *data,int size) +{ + struct ccp_opt_hdr_t *hdr; + struct ccp_option_t *lopt; + int res=0; + + log_debug("recv [CCP ConfNak id=%x",ccp->fsm.recv_id); + + if (ccp->fsm.recv_id!=ccp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct ccp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&ccp->options,entry) + { + if (lopt->id==hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,data); + if (lopt->h->recv_conf_nak(ccp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static int ccp_recv_conf_ack(struct ppp_ccp_t *ccp,uint8_t *data,int size) +{ + struct ccp_opt_hdr_t *hdr; + struct ccp_option_t *lopt; + int res=0; + + log_debug("recv [CCP ConfAck id=%x",ccp->fsm.recv_id); + + if (ccp->fsm.recv_id!=ccp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct ccp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&ccp->options,entry) + { + if (lopt->id==hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,data); + if (!lopt->h->recv_conf_ack) + break; + if (lopt->h->recv_conf_ack(ccp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static void ccp_recv(struct ppp_handler_t*h) +{ + struct ccp_hdr_t *hdr; + struct ppp_ccp_t *ccp=container_of(h,typeof(*ccp),hnd); + int r; + char *term_msg; + + if (ccp->fsm.fsm_state==FSM_Initial || ccp->fsm.fsm_state==FSM_Closed) + { + log_error("CCP: discaring packet\n"); + return; + } + + if (ccp->ppp->unit_buf_size<PPP_HEADERLEN+2) + { + log_warn("CCP: short packet received\n"); + return; + } + + hdr=(struct ccp_hdr_t *)ccp->ppp->unit_buf; + if (ntohs(hdr->len)<PPP_HEADERLEN) + { + log_warn("CCP: short packet received\n"); + return; + } + + ccp->fsm.recv_id=hdr->id; + switch(hdr->code) + { + case CONFREQ: + r=ccp_recv_conf_req(ccp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + switch(r) + { + case CCP_OPT_ACK: + ppp_fsm_recv_conf_req_ack(&ccp->fsm); + break; + case CCP_OPT_NAK: + ppp_fsm_recv_conf_req_nak(&ccp->fsm); + break; + case CCP_OPT_REJ: + ppp_fsm_recv_conf_req_rej(&ccp->fsm); + break; + } + ccp_free_conf_req(ccp); + if (r==CCP_OPT_FAIL) + ppp_terminate(ccp->ppp, 0); + break; + case CONFACK: + if (ccp_recv_conf_ack(ccp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN)) + ppp_terminate(ccp->ppp, 0); + else + ppp_fsm_recv_conf_ack(&ccp->fsm); + break; + case CONFNAK: + ccp_recv_conf_nak(ccp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + ppp_fsm_recv_conf_rej(&ccp->fsm); + break; + case CONFREJ: + if (ccp_recv_conf_rej(ccp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN)) + ppp_terminate(ccp->ppp, 0); + else + ppp_fsm_recv_conf_rej(&ccp->fsm); + break; + case TERMREQ: + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); + log_debug("recv [CCP TermReq id=%x \"%s\"]\n",hdr->id,term_msg); + free(term_msg); + ppp_fsm_recv_term_req(&ccp->fsm); + ppp_terminate(ccp->ppp, 0); + break; + case TERMACK: + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); + log_debug("recv [CCP TermAck id=%x \"%s\"]\n",hdr->id,term_msg); + free(term_msg); + ppp_fsm_recv_term_ack(&ccp->fsm); + break; + case CODEREJ: + log_debug("recv [CCP CodeRej id=%x]\n",hdr->id); + ppp_fsm_recv_code_rej_bad(&ccp->fsm); + break; + default: + ppp_fsm_recv_unk(&ccp->fsm); + break; + } +} + +int ccp_option_register(struct ccp_option_handler_t *h) +{ + /*struct ccp_option_drv_t *p; + + list_for_each_entry(p,option_drv_list,entry) + if (p->id==h->id) + return -1;*/ + + list_add_tail(&h->entry,&option_handlers); + + return 0; +} + +static struct ppp_layer_t ccp_layer= +{ + .init=ccp_layer_init, + .start=ccp_layer_start, + .finish=ccp_layer_finish, + .free=ccp_layer_free, +}; + +static void __init ccp_init(void) +{ + ppp_register_layer("ccp",&ccp_layer); +} diff --git a/accel-pptpd/ppp/ppp_ccp.h b/accel-pptpd/ppp/ppp_ccp.h new file mode 100644 index 00000000..3e459697 --- /dev/null +++ b/accel-pptpd/ppp/ppp_ccp.h @@ -0,0 +1,94 @@ +#ifndef PPP_CCP_H +#define PPP_CCP_H + +#include <stdint.h> + +#include "triton.h" +#include "ppp_fsm.h" +/* + * Options. + */ +#define CI_COMP 2 /* IP-Compress-Protocol */ +#define CI_ADDR 3 /* IP-Address */ +#define CI_DNS1 129 /* Primary-DNS-Address */ +#define CI_DNS2 131 /* Secondary-DNS-Address */ + +struct ccp_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); +struct ccp_opt_hdr_t +{ + uint8_t id; + uint8_t len; +} __attribute__((packed)); +struct ccp_opt8_t +{ + struct ccp_opt_hdr_t hdr; + uint8_t val; +} __attribute__((packed)); +struct ccp_opt16_t +{ + struct ccp_opt_hdr_t hdr; + uint16_t val; +} __attribute__((packed)); +struct ccp_opt32_t +{ + struct ccp_opt_hdr_t hdr; + uint32_t val; +} __attribute__((packed)); + +#define CCP_OPT_NONE 0 +#define CCP_OPT_ACK 1 +#define CCP_OPT_NAK -1 +#define CCP_OPT_REJ -2 +#define CCP_OPT_FAIL -3 + +struct ppp_ccp_t; +struct ccp_option_handler_t; + +struct ccp_option_t +{ + struct list_head entry; + int id; + int len; + int state; + struct ccp_option_handler_t *h; +}; + +struct ccp_option_handler_t +{ + struct list_head entry; + struct ccp_option_t* (*init)(struct ppp_ccp_t*); + int (*send_conf_req)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + int (*send_conf_rej)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + int (*send_conf_nak)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + int (*recv_conf_req)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + int (*recv_conf_rej)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + int (*recv_conf_nak)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + int (*recv_conf_ack)(struct ppp_ccp_t*,struct ccp_option_t*,uint8_t*); + void (*free)(struct ppp_ccp_t*,struct ccp_option_t*); + void (*print)(void (*print)(const char *fmt,...), struct ccp_option_t*,uint8_t*); +}; + +struct ppp_ccp_t +{ + struct ppp_layer_data_t ld; + struct ppp_handler_t hnd; + struct ppp_fsm_t fsm; + struct ppp_t *ppp; + struct list_head options; + + struct list_head ropt_list; // last received ConfReq + int ropt_len; + + int conf_req_len; +}; + +int ccp_option_register(struct ccp_option_handler_t *h); + +#endif + diff --git a/accel-pptpd/ppp/ppp_fsm.c b/accel-pptpd/ppp/ppp_fsm.c new file mode 100644 index 00000000..85cf15a2 --- /dev/null +++ b/accel-pptpd/ppp/ppp_fsm.c @@ -0,0 +1,534 @@ +#include <arpa/inet.h> +#include <stdlib.h> + +#include "triton.h" + +#include "ppp.h" +#include "ppp_fsm.h" +#include "ppp_lcp.h" +#include "log.h" + +static int conf_max_terminate = 2; +static int conf_max_configure = 5; +static int conf_max_failure = 5; +static int conf_timeout = 3; + +void send_term_req(struct ppp_fsm_t *layer); +void send_term_ack(struct ppp_fsm_t *layer); +void send_echo_reply(struct ppp_fsm_t *layer); + +static void init_req_counter(struct ppp_fsm_t *layer,int timeout); +static void zero_req_counter(struct ppp_fsm_t *layer); +static void restart_timer_func(struct triton_timer_t *t); +static void stop_timer(struct ppp_fsm_t *fsm); + +void ppp_fsm_init(struct ppp_fsm_t *layer) +{ + layer->fsm_state = FSM_Initial; + layer->restart_timer.expire = restart_timer_func; + layer->restart_counter = 0; + + layer->max_terminate = conf_max_terminate; + layer->max_configure = conf_max_configure; + layer->max_failure = conf_max_failure; + layer->timeout = conf_timeout; +} +void ppp_fsm_free(struct ppp_fsm_t *layer) +{ + stop_timer(layer); +} + +void ppp_fsm_lower_up(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Initial: + layer->fsm_state=FSM_Closed; + break; + case FSM_Starting: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_lower_down(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + case FSM_Closing: + layer->fsm_state=FSM_Initial; + break; + case FSM_Stopped: + if (layer->layer_started) layer->layer_started(layer); + layer->fsm_state=FSM_Starting; + break; + case FSM_Stopping: + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + layer->fsm_state=FSM_Starting; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + layer->fsm_state=FSM_Starting; + break; + default: + break; + } +} + +void ppp_fsm_open(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Initial: + if (layer->layer_started) layer->layer_started(layer); + layer->fsm_state=FSM_Starting; + break; + case FSM_Starting: + break; + case FSM_Closed: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Closing: + case FSM_Stopping: + case FSM_Stopped: + case FSM_Opened: + ppp_fsm_lower_down(layer); + ppp_fsm_lower_up(layer); + break; + default: + break; + } +} + +void ppp_fsm_close(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Starting: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Initial; + break; + case FSM_Stopped: + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + layer->fsm_state=FSM_Closing; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_terminate); + send_term_req(layer); + layer->fsm_state=FSM_Closing; + break; + default: + break; + } +} + +void ppp_fsm_timeout0(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closing: + case FSM_Stopping: + send_term_req(layer); + break; + case FSM_Ack_Rcvd: + layer->fsm_state=FSM_Req_Sent; + case FSM_Req_Sent: + case FSM_Ack_Sent: + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + break; + default: + break; + } +} + +void ppp_fsm_timeout1(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closing: + stop_timer(layer); + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + stop_timer(layer); + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + case FSM_Ack_Rcvd: + case FSM_Req_Sent: + case FSM_Ack_Sent: + stop_timer(layer); + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_req_ack(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + send_term_ack(layer); + break; + case FSM_Stopped: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + case FSM_Req_Sent: + case FSM_Ack_Sent: + if (layer->send_conf_ack) layer->send_conf_ack(layer); + layer->fsm_state=FSM_Ack_Sent; + break; + case FSM_Ack_Rcvd: + if (layer->send_conf_ack) layer->send_conf_ack(layer); + stop_timer(layer); + if (layer->layer_up) layer->layer_up(layer); + layer->fsm_state=FSM_Opened; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + if (layer->send_conf_ack) layer->send_conf_ack(layer); + layer->fsm_state=FSM_Ack_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_req_nak(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + send_term_ack(layer); + break; + case FSM_Stopped: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + case FSM_Ack_Sent: + if (layer->send_conf_nak) layer->send_conf_nak(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + if (layer->send_conf_nak) layer->send_conf_nak(layer); + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + if (layer->send_conf_nak) layer->send_conf_nak(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_req_rej(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + send_term_ack(layer); + break; + case FSM_Stopped: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + case FSM_Ack_Sent: + if (layer->send_conf_rej) layer->send_conf_rej(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + if (layer->send_conf_rej) layer->send_conf_rej(layer); + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + if (layer->send_conf_rej) layer->send_conf_rej(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_ack(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + case FSM_Stopped: + send_term_ack(layer); + break; + case FSM_Req_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + layer->fsm_state=FSM_Ack_Rcvd; + break; + case FSM_Ack_Rcvd: + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Ack_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + //init_req_counter(layer,layer->max_configure); + //tlu + stop_timer(layer); + if (layer->layer_up) layer->layer_up(layer); + layer->fsm_state=FSM_Opened; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + default: + break; + } +} + +void ppp_fsm_recv_conf_rej(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + case FSM_Stopped: + send_term_ack(layer); + break; + case FSM_Req_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_failure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + break; + case FSM_Ack_Rcvd: + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Ack_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_term_req(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + send_term_req(layer); + send_term_ack(layer); + //if (layer->zero_req_cnt) layer->zero_req_cnt(layer); + zero_req_counter(layer); + layer->fsm_state=FSM_Stopping; + break; + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + send_term_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + send_term_req(layer); + break; + } +} + +void ppp_fsm_recv_term_ack(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closing: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + case FSM_Ack_Rcvd: + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + --layer->restart_counter; + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_unk(struct ppp_fsm_t *layer) +{ + if (layer->send_conf_rej) layer->send_conf_rej(layer); +} + +void ppp_fsm_recv_code_rej_perm(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Ack_Rcvd: + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_code_rej_bad(struct ppp_fsm_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + send_term_req(layer); + layer->fsm_state=FSM_Stopping; + break; + case FSM_Closing: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + default: + break; + } +} + +void send_term_req(struct ppp_fsm_t *layer) +{ + struct lcp_hdr_t hdr = { + .proto = htons(PPP_LCP), + .code = TERMREQ, + .id = ++layer->id, + .len = htons(4), + }; + + log_debug("send [LCP TermReq id=%i \"\"]\n",hdr.id); + + --layer->restart_counter; + ppp_chan_send(layer->ppp, &hdr, 6); +} +void send_term_ack(struct ppp_fsm_t *layer) +{ + struct lcp_hdr_t hdr = { + .proto = htons(PPP_LCP), + .code = TERMACK, + .id = layer->recv_id, + .len = htons(4), + }; + + log_debug("send [LCP TermAck id=%i \"\"]\n", hdr.id); + + ppp_chan_send(layer->ppp, &hdr, 6); +} + +static void stop_timer(struct ppp_fsm_t *fsm) +{ + if (fsm->restart_timer.period) { + fsm->restart_timer.period = 0; + triton_timer_del(&fsm->restart_timer); + } +} +static void init_req_counter(struct ppp_fsm_t *layer,int timeout) +{ + layer->restart_timer.expire_tv.tv_sec=0; + layer->restart_counter = timeout; + + if (!layer->restart_timer.period) { + layer->restart_timer.period = layer->timeout * 1000; + triton_timer_add(layer->ppp->ctrl->ctx, &layer->restart_timer, 0); + } +} +static void zero_req_counter(struct ppp_fsm_t *layer) +{ + layer->restart_timer.expire_tv.tv_sec=0; + layer->restart_counter=0; +} + +static void restart_timer_func(struct triton_timer_t *t) +{ + struct ppp_fsm_t *layer = container_of(t, typeof(*layer), restart_timer); + + if (layer->restart_counter>0) + ppp_fsm_timeout0(layer); + else + ppp_fsm_timeout1(layer); +} + +void __init fsm_init(void) +{ + char *opt; + + opt = conf_get_opt("lcp", "max-terminate"); + if (opt && atoi(opt) > 0) + conf_max_terminate = atoi(opt); + + opt = conf_get_opt("lcp", "max-configure"); + if (opt && atoi(opt) > 0) + conf_max_configure = atoi(opt); + + opt = conf_get_opt("lcp", "max-failure"); + if (opt && atoi(opt) > 0) + conf_max_failure = atoi(opt); + + opt = conf_get_opt("lcp", "timeout"); + if (opt && atoi(opt) > 0) + conf_timeout = atoi(opt); +} diff --git a/accel-pptpd/ppp/ppp_fsm.h b/accel-pptpd/ppp/ppp_fsm.h new file mode 100644 index 00000000..bc958fe9 --- /dev/null +++ b/accel-pptpd/ppp/ppp_fsm.h @@ -0,0 +1,65 @@ +#ifndef PPP_FSM_H +#define PPP_FSM_H + +typedef enum {FSM_Initial=0,FSM_Starting,FSM_Closed,FSM_Stopped,FSM_Closing,FSM_Stopping,FSM_Req_Sent,FSM_Ack_Rcvd,FSM_Ack_Sent,FSM_Opened} FSM_STATE; +/* + * CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ 1 /* Configuration Request */ +#define CONFACK 2 /* Configuration Ack */ +#define CONFNAK 3 /* Configuration Nak */ +#define CONFREJ 4 /* Configuration Reject */ +#define TERMREQ 5 /* Termination Request */ +#define TERMACK 6 /* Termination Ack */ +#define CODEREJ 7 /* Code Reject */ +#define ECHOREQ 9 /* Echo Request */ +#define ECHOREP 10 /* Echo Reply */ + +struct ppp_t; + +struct ppp_fsm_t +{ + struct ppp_t *ppp; + FSM_STATE fsm_state; + + struct triton_timer_t restart_timer; + int restart_counter; + int max_terminate; + int max_configure; + int max_failure; + int timeout; + + int id; + int recv_id; + + //fsm handling + void (*layer_up)(struct ppp_fsm_t*); + void (*layer_down)(struct ppp_fsm_t*); + void (*layer_started)(struct ppp_fsm_t*); + void (*layer_finished)(struct ppp_fsm_t*); + void (*send_conf_req)(struct ppp_fsm_t*); + void (*send_conf_ack)(struct ppp_fsm_t*); + void (*send_conf_nak)(struct ppp_fsm_t*); + void (*send_conf_rej)(struct ppp_fsm_t*); +}; + +void ppp_fsm_init(struct ppp_fsm_t*); +void ppp_fsm_free(struct ppp_fsm_t*); + +void ppp_fsm_lower_up(struct ppp_fsm_t*); +void ppp_fsm_lower_down(struct ppp_fsm_t*); +void ppp_fsm_open(struct ppp_fsm_t*); +void ppp_fsm_close(struct ppp_fsm_t*); +void ppp_fsm_timeout0(struct ppp_fsm_t *layer); +void ppp_fsm_timeout1(struct ppp_fsm_t *layer); +void ppp_fsm_recv_conf_req_ack(struct ppp_fsm_t *layer); +void ppp_fsm_recv_conf_req_nak(struct ppp_fsm_t *layer); +void ppp_fsm_recv_conf_req_rej(struct ppp_fsm_t *layer); +void ppp_fsm_recv_conf_ack(struct ppp_fsm_t *layer); +void ppp_fsm_recv_conf_rej(struct ppp_fsm_t *layer); +void ppp_fsm_recv_term_req(struct ppp_fsm_t *layer); +void ppp_fsm_recv_term_ack(struct ppp_fsm_t *layer); +void ppp_fsm_recv_unk(struct ppp_fsm_t *layer); +void ppp_fsm_recv_code_rej_bad(struct ppp_fsm_t *layer); + +#endif diff --git a/accel-pptpd/ppp/ppp_ipcp.c b/accel-pptpd/ppp/ppp_ipcp.c new file mode 100644 index 00000000..6ac145b2 --- /dev/null +++ b/accel-pptpd/ppp/ppp_ipcp.c @@ -0,0 +1,568 @@ +#include <stdlib.h> +#include <string.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <arpa/inet.h> + +#include "triton.h" + +#include "log.h" + +#include "ppp.h" +#include "ppp_ipcp.h" + +struct recv_opt_t +{ + struct list_head entry; + struct ipcp_opt_hdr_t *hdr; + int len; + int state; + struct ipcp_option_t *lopt; +}; + +static LIST_HEAD(option_handlers); + +static void ipcp_layer_up(struct ppp_fsm_t*); +static void ipcp_layer_down(struct ppp_fsm_t*); +static void send_conf_req(struct ppp_fsm_t*); +static void send_conf_ack(struct ppp_fsm_t*); +static void send_conf_nak(struct ppp_fsm_t*); +static void send_conf_rej(struct ppp_fsm_t*); +static void ipcp_recv(struct ppp_handler_t*); + +static void ipcp_options_init(struct ppp_ipcp_t *ipcp) +{ + struct ipcp_option_t *lopt; + struct ipcp_option_handler_t *h; + + INIT_LIST_HEAD(&ipcp->options); + + list_for_each_entry(h,&option_handlers,entry) + { + lopt=h->init(ipcp); + if (lopt) + { + lopt->h=h; + list_add_tail(&lopt->entry,&ipcp->options); + ipcp->conf_req_len+=lopt->len; + } + } +} + +static void ipcp_options_free(struct ppp_ipcp_t *ipcp) +{ + struct ipcp_option_t *lopt; + + while(!list_empty(&ipcp->options)) + { + lopt=list_entry(ipcp->options.next,typeof(*lopt),entry); + list_del(&lopt->entry); + lopt->h->free(ipcp,lopt); + } +} + +static struct ppp_layer_data_t *ipcp_layer_init(struct ppp_t *ppp) +{ + struct ppp_ipcp_t *ipcp=malloc(sizeof(*ipcp)); + memset(ipcp,0,sizeof(*ipcp)); + + log_debug("ipcp_layer_init\n"); + + ipcp->ppp=ppp; + ipcp->fsm.ppp=ppp; + + ipcp->hnd.proto=PPP_IPCP; + ipcp->hnd.recv=ipcp_recv; + + ppp_register_unit_handler(ppp,&ipcp->hnd); + + ppp_fsm_init(&ipcp->fsm); + + ipcp->fsm.layer_up=ipcp_layer_up; + ipcp->fsm.layer_finished=ipcp_layer_down; + ipcp->fsm.send_conf_req=send_conf_req; + ipcp->fsm.send_conf_ack=send_conf_ack; + ipcp->fsm.send_conf_nak=send_conf_nak; + ipcp->fsm.send_conf_rej=send_conf_rej; + + INIT_LIST_HEAD(&ipcp->ropt_list); + + return &ipcp->ld; +} + +void ipcp_layer_start(struct ppp_layer_data_t *ld) +{ + struct ppp_ipcp_t *ipcp=container_of(ld,typeof(*ipcp),ld); + + log_debug("ipcp_layer_start\n"); + + ipcp_options_init(ipcp); + ppp_fsm_lower_up(&ipcp->fsm); + ppp_fsm_open(&ipcp->fsm); +} + +void ipcp_layer_finish(struct ppp_layer_data_t *ld) +{ + struct ppp_ipcp_t *ipcp=container_of(ld,typeof(*ipcp),ld); + + log_debug("ipcp_layer_finish\n"); + + ppp_fsm_lower_down(&ipcp->fsm); + + ppp_unregister_handler(ipcp->ppp,&ipcp->hnd); + ipcp_options_free(ipcp); + + ppp_layer_finished(ipcp->ppp,ld); +} + +void ipcp_layer_free(struct ppp_layer_data_t *ld) +{ + struct ppp_ipcp_t *ipcp=container_of(ld,typeof(*ipcp),ld); + + log_debug("ipcp_layer_free\n"); + + free(ipcp); +} + +static void ipcp_layer_up(struct ppp_fsm_t *fsm) +{ + struct ppp_ipcp_t *ipcp=container_of(fsm,typeof(*ipcp),fsm); + log_debug("ipcp_layer_started\n"); + ppp_layer_started(ipcp->ppp,&ipcp->ld); +} + +static void ipcp_layer_down(struct ppp_fsm_t *fsm) +{ + struct ppp_ipcp_t *ipcp=container_of(fsm,typeof(*ipcp),fsm); + log_debug("ipcp_layer_finished\n"); + ppp_layer_finished(ipcp->ppp,&ipcp->ld); +} + +static void print_ropt(struct recv_opt_t *ropt) +{ + int i; + uint8_t *ptr=(uint8_t*)ropt->hdr; + + log_debug(" <"); + for(i=0; i<ropt->len; i++) + { + log_debug(" %x",ptr[i]); + } + log_debug(" >"); +} + +static void send_conf_req(struct ppp_fsm_t *fsm) +{ + struct ppp_ipcp_t *ipcp=container_of(fsm,typeof(*ipcp),fsm); + uint8_t *buf=malloc(ipcp->conf_req_len), *ptr=buf; + struct ipcp_hdr_t *ipcp_hdr=(struct ipcp_hdr_t*)ptr; + struct ipcp_option_t *lopt; + int n; + + log_debug("send [IPCP ConfReq"); + ipcp_hdr->proto=htons(PPP_IPCP); + ipcp_hdr->code=CONFREQ; + ipcp_hdr->id=++ipcp->fsm.id; + ipcp_hdr->len=0; + log_debug(" id=%x",ipcp_hdr->id); + + ptr+=sizeof(*ipcp_hdr); + + list_for_each_entry(lopt,&ipcp->options,entry) + { + n=lopt->h->send_conf_req(ipcp,lopt,ptr); + if (n) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,NULL); + ptr+=n; + } + } + + log_debug("]\n"); + + ipcp_hdr->len=htons((ptr-buf)-2); + ppp_unit_send(ipcp->ppp,ipcp_hdr,ptr-buf); +} + +static void send_conf_ack(struct ppp_fsm_t *fsm) +{ + struct ppp_ipcp_t *ipcp=container_of(fsm,typeof(*ipcp),fsm); + struct ipcp_hdr_t *hdr=(struct ipcp_hdr_t*)ipcp->ppp->unit_buf; + + hdr->code=CONFACK; + log_debug("send [IPCP ConfAck id=%x ]\n",ipcp->fsm.recv_id); + + ppp_unit_send(ipcp->ppp,hdr,ntohs(hdr->len)+2); +} + +static void send_conf_nak(struct ppp_fsm_t *fsm) +{ + struct ppp_ipcp_t *ipcp=container_of(fsm,typeof(*ipcp),fsm); + uint8_t *buf=malloc(ipcp->conf_req_len), *ptr=buf; + struct ipcp_hdr_t *ipcp_hdr=(struct ipcp_hdr_t*)ptr; + struct recv_opt_t *ropt; + + log_debug("send [IPCP ConfNak id=%x",ipcp->fsm.recv_id); + + ipcp_hdr->proto=htons(PPP_IPCP); + ipcp_hdr->code=CONFNAK; + ipcp_hdr->id=ipcp->fsm.recv_id; + ipcp_hdr->len=0; + + ptr+=sizeof(*ipcp_hdr); + + list_for_each_entry(ropt,&ipcp->ropt_list,entry) + { + if (ropt->state==IPCP_OPT_NAK) + { + log_debug(" "); + ropt->lopt->h->print(log_debug,ropt->lopt,NULL); + ptr+=ropt->lopt->h->send_conf_nak(ipcp,ropt->lopt,ptr); + } + } + + log_debug("]\n"); + + ipcp_hdr->len=htons((ptr-buf)-2); + ppp_unit_send(ipcp->ppp,ipcp_hdr,ptr-buf); +} + +static void send_conf_rej(struct ppp_fsm_t *fsm) +{ + struct ppp_ipcp_t *ipcp=container_of(fsm,typeof(*ipcp),fsm); + uint8_t *buf=malloc(ipcp->ropt_len), *ptr=buf; + struct ipcp_hdr_t *ipcp_hdr=(struct ipcp_hdr_t*)ptr; + struct recv_opt_t *ropt; + + log_debug("send [IPCP ConfRej id=%x ",ipcp->fsm.recv_id); + + ipcp_hdr->proto=htons(PPP_IPCP); + ipcp_hdr->code=CONFREJ; + ipcp_hdr->id=ipcp->fsm.recv_id; + ipcp_hdr->len=0; + + ptr+=sizeof(*ipcp_hdr); + + list_for_each_entry(ropt,&ipcp->ropt_list,entry) + { + if (ropt->state==IPCP_OPT_REJ) + { + log_debug(" "); + if (ropt->lopt) ropt->lopt->h->print(log_debug,ropt->lopt,(uint8_t*)ropt->hdr); + else print_ropt(ropt); + memcpy(ptr,ropt->hdr,ropt->len); + ptr+=ropt->len; + } + } + + log_debug("]\n"); + + ipcp_hdr->len=htons((ptr-buf)-2); + ppp_unit_send(ipcp->ppp,ipcp_hdr,ptr-buf); +} + +static int ipcp_recv_conf_req(struct ppp_ipcp_t *ipcp,uint8_t *data,int size) +{ + struct ipcp_opt_hdr_t *hdr; + struct recv_opt_t *ropt; + struct ipcp_option_t *lopt; + int r,ret=1; + + ipcp->ropt_len=size; + + while(size>0) + { + hdr=(struct ipcp_opt_hdr_t *)data; + + ropt=malloc(sizeof(*ropt)); + memset(ropt,0,sizeof(*ropt)); + if (hdr->len>size) ropt->len=size; + else ropt->len=hdr->len; + ropt->hdr=hdr; + ropt->state=IPCP_OPT_NONE; + list_add_tail(&ropt->entry,&ipcp->ropt_list); + + data+=ropt->len; + size-=ropt->len; + } + + list_for_each_entry(lopt,&ipcp->options,entry) + lopt->state=IPCP_OPT_NONE; + + log_debug("recv [IPCP ConfReq id=%x",ipcp->fsm.recv_id); + list_for_each_entry(ropt,&ipcp->ropt_list,entry) + { + list_for_each_entry(lopt,&ipcp->options,entry) + { + if (lopt->id==ropt->hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,(uint8_t*)ropt->hdr); + r=lopt->h->recv_conf_req(ipcp,lopt,(uint8_t*)ropt->hdr); + lopt->state=r; + ropt->state=r; + ropt->lopt=lopt; + if (r<ret) ret=r; + break; + } + } + if (!ropt->lopt) + { + log_debug(" "); + print_ropt(ropt); + ropt->state=IPCP_OPT_REJ; + ret=IPCP_OPT_REJ; + } + } + log_debug("]\n"); + + /*list_for_each_entry(lopt,&ipcp->options,entry) + { + if (lopt->state==IPCP_OPT_NONE) + { + r=lopt->h->recv_conf_req(ipcp,lopt,NULL); + lopt->state=r; + if (r<ret) ret=r; + } + }*/ + + return ret; +} + +static void ipcp_free_conf_req(struct ppp_ipcp_t *ipcp) +{ + struct recv_opt_t *ropt; + + while(!list_empty(&ipcp->ropt_list)) + { + ropt=list_entry(ipcp->ropt_list.next,typeof(*ropt),entry); + list_del(&ropt->entry); + free(ropt); + } +} + +static int ipcp_recv_conf_rej(struct ppp_ipcp_t *ipcp,uint8_t *data,int size) +{ + struct ipcp_opt_hdr_t *hdr; + struct ipcp_option_t *lopt; + int res=0; + + log_debug("recv [IPCP ConfRej id=%x",ipcp->fsm.recv_id); + + if (ipcp->fsm.recv_id!=ipcp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct ipcp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&ipcp->options,entry) + { + if (lopt->id==hdr->id) + { + if (!lopt->h->recv_conf_rej) + res=-1; + else if (lopt->h->recv_conf_rej(ipcp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static int ipcp_recv_conf_nak(struct ppp_ipcp_t *ipcp,uint8_t *data,int size) +{ + struct ipcp_opt_hdr_t *hdr; + struct ipcp_option_t *lopt; + int res=0; + + log_debug("recv [IPCP ConfNak id=%x",ipcp->fsm.recv_id); + + if (ipcp->fsm.recv_id!=ipcp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct ipcp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&ipcp->options,entry) + { + if (lopt->id==hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,data); + if (lopt->h->recv_conf_nak(ipcp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static int ipcp_recv_conf_ack(struct ppp_ipcp_t *ipcp,uint8_t *data,int size) +{ + struct ipcp_opt_hdr_t *hdr; + struct ipcp_option_t *lopt; + int res=0; + + log_debug("recv [IPCP ConfAck id=%x",ipcp->fsm.recv_id); + + if (ipcp->fsm.recv_id!=ipcp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct ipcp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&ipcp->options,entry) + { + if (lopt->id==hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,data); + if (!lopt->h->recv_conf_ack) + break; + if (lopt->h->recv_conf_ack(ipcp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static void ipcp_recv(struct ppp_handler_t*h) +{ + struct ipcp_hdr_t *hdr; + struct ppp_ipcp_t *ipcp=container_of(h,typeof(*ipcp),hnd); + int r; + char *term_msg; + + if (ipcp->fsm.fsm_state==FSM_Initial || ipcp->fsm.fsm_state==FSM_Closed) + { + log_error("IPCP: discaring packet\n"); + return; + } + + if (ipcp->ppp->unit_buf_size<PPP_HEADERLEN+2) + { + log_warn("IPCP: short packet received\n"); + return; + } + + hdr=(struct ipcp_hdr_t *)ipcp->ppp->unit_buf; + if (ntohs(hdr->len)<PPP_HEADERLEN) + { + log_warn("IPCP: short packet received\n"); + return; + } + + ipcp->fsm.recv_id=hdr->id; + switch(hdr->code) + { + case CONFREQ: + r=ipcp_recv_conf_req(ipcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + switch(r) + { + case IPCP_OPT_ACK: + ppp_fsm_recv_conf_req_ack(&ipcp->fsm); + break; + case IPCP_OPT_NAK: + ppp_fsm_recv_conf_req_nak(&ipcp->fsm); + break; + case IPCP_OPT_REJ: + ppp_fsm_recv_conf_req_rej(&ipcp->fsm); + break; + } + ipcp_free_conf_req(ipcp); + if (r==IPCP_OPT_FAIL) + ppp_terminate(ipcp->ppp, 0); + break; + case CONFACK: + if (ipcp_recv_conf_ack(ipcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN)) + ppp_terminate(ipcp->ppp, 0); + else + ppp_fsm_recv_conf_ack(&ipcp->fsm); + break; + case CONFNAK: + ipcp_recv_conf_nak(ipcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + ppp_fsm_recv_conf_rej(&ipcp->fsm); + break; + case CONFREJ: + if (ipcp_recv_conf_rej(ipcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN)) + ppp_terminate(ipcp->ppp, 0); + else + ppp_fsm_recv_conf_rej(&ipcp->fsm); + break; + case TERMREQ: + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); + log_debug("recv [IPCP TermReq id=%x \"%s\"]\n",hdr->id,term_msg); + free(term_msg); + ppp_fsm_recv_term_req(&ipcp->fsm); + ppp_terminate(ipcp->ppp, 0); + break; + case TERMACK: + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); + log_debug("recv [IPCP TermAck id=%x \"%s\"]\n",hdr->id,term_msg); + free(term_msg); + ppp_fsm_recv_term_ack(&ipcp->fsm); + break; + case CODEREJ: + log_debug("recv [IPCP CodeRej id=%x]\n",hdr->id); + ppp_fsm_recv_code_rej_bad(&ipcp->fsm); + break; + default: + ppp_fsm_recv_unk(&ipcp->fsm); + break; + } +} + +int ipcp_option_register(struct ipcp_option_handler_t *h) +{ + /*struct ipcp_option_drv_t *p; + + list_for_each_entry(p,option_drv_list,entry) + if (p->id==h->id) + return -1;*/ + + list_add_tail(&h->entry,&option_handlers); + + return 0; +} + +static struct ppp_layer_t ipcp_layer= +{ + .init=ipcp_layer_init, + .start=ipcp_layer_start, + .finish=ipcp_layer_finish, + .free=ipcp_layer_free, +}; + +static void __init ipcp_init(void) +{ + ppp_register_layer("ipcp",&ipcp_layer); +} diff --git a/accel-pptpd/ppp/ppp_ipcp.h b/accel-pptpd/ppp/ppp_ipcp.h new file mode 100644 index 00000000..9e0c99ee --- /dev/null +++ b/accel-pptpd/ppp/ppp_ipcp.h @@ -0,0 +1,94 @@ +#ifndef PPP_IPCP_H +#define PPP_IPCP_H + +#include <stdint.h> + +#include "triton.h" +#include "ppp_fsm.h" +/* + * Options. + */ +#define CI_COMP 2 /* IP-Compress-Protocol */ +#define CI_ADDR 3 /* IP-Address */ +#define CI_DNS1 129 /* Primary-DNS-Address */ +#define CI_DNS2 131 /* Secondary-DNS-Address */ + +struct ipcp_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); +struct ipcp_opt_hdr_t +{ + uint8_t id; + uint8_t len; +} __attribute__((packed)); +struct ipcp_opt8_t +{ + struct ipcp_opt_hdr_t hdr; + uint8_t val; +} __attribute__((packed)); +struct ipcp_opt16_t +{ + struct ipcp_opt_hdr_t hdr; + uint16_t val; +} __attribute__((packed)); +struct ipcp_opt32_t +{ + struct ipcp_opt_hdr_t hdr; + uint32_t val; +} __attribute__((packed)); + +#define IPCP_OPT_NONE 0 +#define IPCP_OPT_ACK 1 +#define IPCP_OPT_NAK -1 +#define IPCP_OPT_REJ -2 +#define IPCP_OPT_FAIL -3 + +struct ppp_ipcp_t; +struct ipcp_option_handler_t; + +struct ipcp_option_t +{ + struct list_head entry; + int id; + int len; + int state; + struct ipcp_option_handler_t *h; +}; + +struct ipcp_option_handler_t +{ + struct list_head entry; + struct ipcp_option_t* (*init)(struct ppp_ipcp_t*); + int (*send_conf_req)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + int (*send_conf_rej)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + int (*send_conf_nak)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + int (*recv_conf_req)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + int (*recv_conf_rej)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + int (*recv_conf_nak)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + int (*recv_conf_ack)(struct ppp_ipcp_t*,struct ipcp_option_t*,uint8_t*); + void (*free)(struct ppp_ipcp_t*,struct ipcp_option_t*); + void (*print)(void (*print)(const char *fmt,...), struct ipcp_option_t*,uint8_t*); +}; + +struct ppp_ipcp_t +{ + struct ppp_layer_data_t ld; + struct ppp_handler_t hnd; + struct ppp_fsm_t fsm; + struct ppp_t *ppp; + struct list_head options; + + struct list_head ropt_list; // last received ConfReq + int ropt_len; + + int conf_req_len; +}; + +int ipcp_option_register(struct ipcp_option_handler_t *h); + +#endif + diff --git a/accel-pptpd/ppp/ppp_lcp.c b/accel-pptpd/ppp/ppp_lcp.c new file mode 100644 index 00000000..afcfc102 --- /dev/null +++ b/accel-pptpd/ppp/ppp_lcp.c @@ -0,0 +1,659 @@ +#include <stdlib.h> +#include <string.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <arpa/inet.h> + +#include "triton.h" + +#include "log.h" + +#include "ppp.h" +#include "ppp_lcp.h" + +struct recv_opt_t +{ + struct list_head entry; + struct lcp_opt_hdr_t *hdr; + int len; + int state; + struct lcp_option_t *lopt; +}; + +static int conf_echo_interval = 0; +static int conf_echo_failure = 3; + +static LIST_HEAD(option_handlers); + +static void lcp_layer_up(struct ppp_fsm_t*); +static void lcp_layer_down(struct ppp_fsm_t*); +static void send_conf_req(struct ppp_fsm_t*); +static void send_conf_ack(struct ppp_fsm_t*); +static void send_conf_nak(struct ppp_fsm_t*); +static void send_conf_rej(struct ppp_fsm_t*); +static void lcp_recv(struct ppp_handler_t*); +static void start_echo(struct ppp_lcp_t *lcp); +static void stop_echo(struct ppp_lcp_t *lcp); + +static void lcp_options_init(struct ppp_lcp_t *lcp) +{ + struct lcp_option_t *lopt; + struct lcp_option_handler_t *h; + + INIT_LIST_HEAD(&lcp->options); + + list_for_each_entry(h,&option_handlers,entry) + { + lopt=h->init(lcp); + if (lopt) + { + lopt->h=h; + list_add_tail(&lopt->entry,&lcp->options); + lcp->conf_req_len+=lopt->len; + } + } +} + +static void lcp_options_free(struct ppp_lcp_t *lcp) +{ + struct lcp_option_t *lopt; + + while(!list_empty(&lcp->options)) + { + lopt=list_entry(lcp->options.next,typeof(*lopt),entry); + list_del(&lopt->entry); + lopt->h->free(lcp,lopt); + } +} + +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; + + lcp->hnd.proto=PPP_LCP; + lcp->hnd.recv=lcp_recv; + + ppp_register_chan_handler(ppp,&lcp->hnd); + + ppp_fsm_init(&lcp->fsm); + + lcp->fsm.layer_up=lcp_layer_up; + 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; + + 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); +} + +void lcp_layer_finish(struct ppp_layer_data_t *ld) +{ + struct ppp_lcp_t *lcp=container_of(ld,typeof(*lcp),ld); + + log_debug("lcp_layer_finish\n"); + + stop_echo(lcp); + + ppp_fsm_close(&lcp->fsm); +} + +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"); + + stop_echo(lcp); + ppp_unregister_handler(lcp->ppp,&lcp->hnd); + lcp_options_free(lcp); + ppp_fsm_free(&lcp->fsm); + + free(lcp); +} + +static void lcp_layer_up(struct ppp_fsm_t *fsm) +{ + struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); + log_debug("lcp_layer_started\n"); + ppp_layer_started(lcp->ppp,&lcp->ld); + + start_echo(lcp); +} + +static void lcp_layer_down(struct ppp_fsm_t *fsm) +{ + struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); + log_debug("lcp_layer_finished\n"); + stop_echo(lcp); + ppp_layer_finished(lcp->ppp,&lcp->ld); +} + +static void print_ropt(struct recv_opt_t *ropt) +{ + int i; + uint8_t *ptr=(uint8_t*)ropt->hdr; + + log_debug(" <"); + for(i=0; i<ropt->len; i++) + { + log_debug(" %x",ptr[i]); + } + log_debug(" >"); +} + +static void send_conf_req(struct ppp_fsm_t *fsm) +{ + struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); + uint8_t *buf=malloc(lcp->conf_req_len), *ptr=buf; + struct lcp_hdr_t *lcp_hdr=(struct lcp_hdr_t*)ptr; + struct lcp_option_t *lopt; + int n; + + log_debug("send [LCP ConfReq"); + lcp_hdr->proto=htons(PPP_LCP); + lcp_hdr->code=CONFREQ; + lcp_hdr->id=++lcp->fsm.id; + lcp_hdr->len=0; + log_debug(" id=%x",lcp_hdr->id); + + ptr+=sizeof(*lcp_hdr); + + list_for_each_entry(lopt,&lcp->options,entry) + { + n=lopt->h->send_conf_req(lcp,lopt,ptr); + if (n) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,NULL); + ptr+=n; + } + } + + log_debug("]\n"); + + lcp_hdr->len=htons((ptr-buf)-2); + 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->chan_buf; + + hdr->code=CONFACK; + log_debug("send [LCP ConfAck id=%x ]\n",lcp->fsm.recv_id); + + ppp_chan_send(lcp->ppp,hdr,ntohs(hdr->len)+2); +} + +static void send_conf_nak(struct ppp_fsm_t *fsm) +{ + struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); + uint8_t *buf=malloc(lcp->conf_req_len), *ptr=buf; + struct lcp_hdr_t *lcp_hdr=(struct lcp_hdr_t*)ptr; + struct recv_opt_t *ropt; + + log_debug("send [LCP ConfNak id=%x",lcp->fsm.recv_id); + + lcp_hdr->proto=htons(PPP_LCP); + lcp_hdr->code=CONFNAK; + lcp_hdr->id=lcp->fsm.recv_id; + lcp_hdr->len=0; + + ptr+=sizeof(*lcp_hdr); + + list_for_each_entry(ropt,&lcp->ropt_list,entry) + { + if (ropt->state==LCP_OPT_NAK) + { + log_debug(" "); + ropt->lopt->h->print(log_debug,ropt->lopt,NULL); + ptr+=ropt->lopt->h->send_conf_nak(lcp,ropt->lopt,ptr); + } + } + + log_debug("]\n"); + + lcp_hdr->len=htons((ptr-buf)-2); + ppp_chan_send(lcp->ppp,lcp_hdr,ptr-buf); +} + +static void send_conf_rej(struct ppp_fsm_t *fsm) +{ + struct ppp_lcp_t *lcp=container_of(fsm,typeof(*lcp),fsm); + uint8_t *buf=malloc(lcp->ropt_len), *ptr=buf; + struct lcp_hdr_t *lcp_hdr=(struct lcp_hdr_t*)ptr; + struct recv_opt_t *ropt; + + log_debug("send [LCP ConfRej id=%x ",lcp->fsm.recv_id); + + lcp_hdr->proto=htons(PPP_LCP); + lcp_hdr->code=CONFREJ; + lcp_hdr->id=lcp->fsm.recv_id; + lcp_hdr->len=0; + + ptr+=sizeof(*lcp_hdr); + + list_for_each_entry(ropt,&lcp->ropt_list,entry) + { + if (ropt->state==LCP_OPT_REJ) + { + log_debug(" "); + if (ropt->lopt) ropt->lopt->h->print(log_debug,ropt->lopt,(uint8_t*)ropt->hdr); + else print_ropt(ropt); + memcpy(ptr,ropt->hdr,ropt->len); + ptr+=ropt->len; + } + } + + log_debug("]\n"); + + lcp_hdr->len=htons((ptr-buf)-2); + 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) +{ + struct lcp_opt_hdr_t *hdr; + struct recv_opt_t *ropt; + struct lcp_option_t *lopt; + int r,ret=1; + + lcp->ropt_len=size; + + while(size>0) + { + hdr=(struct lcp_opt_hdr_t *)data; + + ropt=malloc(sizeof(*ropt)); + if (hdr->len>size) ropt->len=size; + else ropt->len=hdr->len; + ropt->hdr=hdr; + ropt->state=LCP_OPT_NONE; + list_add_tail(&ropt->entry,&lcp->ropt_list); + + data+=ropt->len; + size-=ropt->len; + } + + list_for_each_entry(lopt,&lcp->options,entry) + lopt->state=LCP_OPT_NONE; + + log_debug("recv [LCP ConfReq id=%x",lcp->fsm.recv_id); + list_for_each_entry(ropt,&lcp->ropt_list,entry) + { + list_for_each_entry(lopt,&lcp->options,entry) + { + if (lopt->id==ropt->hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,(uint8_t*)ropt->hdr); + r=lopt->h->recv_conf_req(lcp,lopt,(uint8_t*)ropt->hdr); + lopt->state=r; + ropt->state=r; + ropt->lopt=lopt; + if (r<ret) ret=r; + break; + } + } + if (!ropt->lopt) + { + log_debug(" "); + print_ropt(ropt); + ropt->state=LCP_OPT_REJ; + ret=LCP_OPT_REJ; + } + } + log_debug("]\n"); + + /*list_for_each_entry(lopt,&lcp->options,entry) + { + if (lopt->state==LCP_OPT_NONE) + { + r=lopt->h->recv_conf_req(lcp,lopt,NULL); + lopt->state=r; + if (r<ret) ret=r; + } + }*/ + + return ret; +} + +static void lcp_free_conf_req(struct ppp_lcp_t *lcp) +{ + struct recv_opt_t *ropt; + + while(!list_empty(&lcp->ropt_list)) + { + ropt=list_entry(lcp->ropt_list.next,typeof(*ropt),entry); + list_del(&ropt->entry); + free(ropt); + } +} + +static int lcp_recv_conf_rej(struct ppp_lcp_t *lcp,uint8_t *data,int size) +{ + struct lcp_opt_hdr_t *hdr; + struct lcp_option_t *lopt; + int res=0; + + log_debug("recv [LCP ConfRej id=%x",lcp->fsm.recv_id); + + if (lcp->fsm.recv_id!=lcp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct lcp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&lcp->options,entry) + { + if (lopt->id==hdr->id) + { + if (!lopt->h->recv_conf_rej) + res=-1; + else if (lopt->h->recv_conf_rej(lcp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static int lcp_recv_conf_nak(struct ppp_lcp_t *lcp,uint8_t *data,int size) +{ + struct lcp_opt_hdr_t *hdr; + struct lcp_option_t *lopt; + int res=0; + + log_debug("recv [LCP ConfNak id=%x",lcp->fsm.recv_id); + + if (lcp->fsm.recv_id!=lcp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct lcp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&lcp->options,entry) + { + if (lopt->id==hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,data); + if (lopt->h->recv_conf_nak(lcp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static int lcp_recv_conf_ack(struct ppp_lcp_t *lcp,uint8_t *data,int size) +{ + struct lcp_opt_hdr_t *hdr; + struct lcp_option_t *lopt; + int res=0; + + log_debug("recv [LCP ConfAck id=%x",lcp->fsm.recv_id); + + if (lcp->fsm.recv_id!=lcp->fsm.id) + { + log_debug(": id mismatch ]\n"); + return 0; + } + + while(size>0) + { + hdr=(struct lcp_opt_hdr_t *)data; + + list_for_each_entry(lopt,&lcp->options,entry) + { + if (lopt->id==hdr->id) + { + log_debug(" "); + lopt->h->print(log_debug,lopt,data); + if (!lopt->h->recv_conf_ack) + break; + if (lopt->h->recv_conf_ack(lcp,lopt,data)) + res=-1; + break; + } + } + + data+=hdr->len; + size-=hdr->len; + } + log_debug("]\n"); + return res; +} + +static void lcp_recv_echo_repl(struct ppp_lcp_t *lcp,uint8_t *data,int size) +{ + uint32_t magic = *(uint32_t *)data; + + if (size != 4) { + log_error("lcp:echo: magic number size mismatch\n"); + ppp_terminate(lcp->ppp, 0); + } + + log_debug("recv [LCP EchoRep id=%x <magic %x>]\n",lcp->fsm.recv_id,magic); + + if (magic == lcp->magic) { + log_error("lcp:echo: loop-back detected\n"); + ppp_terminate(lcp->ppp, 0); + } + + lcp->echo_sent = 0; +} + +static void send_echo_reply(struct ppp_lcp_t *lcp) +{ + struct lcp_hdr_t *hdr=(struct lcp_hdr_t*)lcp->ppp->chan_buf; + uint32_t magic = *(uint32_t *)(hdr+1); + + hdr->code=ECHOREP; + log_debug("send [LCP EchoRep id=%x <magic %x>]\n", hdr->id, magic); + + ppp_chan_send(lcp->ppp,hdr,ntohs(hdr->len)+2); +} +static void send_echo_request(struct triton_timer_t *t) +{ + struct ppp_lcp_t *lcp = container_of(t, typeof(*lcp), echo_timer); + struct lcp_echo_req_t + { + struct lcp_hdr_t hdr; + uint32_t magic; + } __attribute__((packed)) msg = { + .hdr.proto = htons(PPP_LCP), + .hdr.code = ECHOREQ, + .hdr.id = ++lcp->fsm.id, + .hdr.len = htons(8), + .magic = lcp->magic, + }; + + if (++lcp->echo_sent > lcp->echo_failure) { + log_warn("lcp: no echo reply\n"); + ppp_terminate(lcp->ppp, 0); + } else { + log_debug("send [LCP EchoReq id=%x <magic %x>]\n", msg.hdr.id, msg.magic); + ppp_chan_send(lcp->ppp,&msg,ntohs(msg.hdr.len)+2); + } +} + +static void start_echo(struct ppp_lcp_t *lcp) +{ + lcp->echo_interval = conf_echo_interval; + lcp->echo_failure = conf_echo_failure; + + lcp->echo_timer.period = lcp->echo_interval * 1000; + lcp->echo_timer.expire = send_echo_request; + if (lcp->echo_timer.period) + triton_timer_add(lcp->ppp->ctrl->ctx, &lcp->echo_timer, 0); +} +static void stop_echo(struct ppp_lcp_t *lcp) +{ + if (lcp->echo_interval) { + triton_timer_del(&lcp->echo_timer); + lcp->echo_interval = 0; + } +} + +static void lcp_recv(struct ppp_handler_t*h) +{ + struct lcp_hdr_t *hdr; + struct ppp_lcp_t *lcp=container_of(h,typeof(*lcp),hnd); + int r; + char *term_msg; + + if (lcp->ppp->chan_buf_size<PPP_HEADERLEN+2) + { + log_warn("LCP: short packet received\n"); + return; + } + + hdr=(struct lcp_hdr_t *)lcp->ppp->chan_buf; + if (ntohs(hdr->len)<PPP_HEADERLEN) + { + log_warn("LCP: short packet received\n"); + return; + } + + lcp->fsm.recv_id=hdr->id; + switch(hdr->code) + { + case CONFREQ: + r=lcp_recv_conf_req(lcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + switch(r) + { + case LCP_OPT_ACK: + ppp_fsm_recv_conf_req_ack(&lcp->fsm); + break; + case LCP_OPT_NAK: + ppp_fsm_recv_conf_req_nak(&lcp->fsm); + break; + case LCP_OPT_REJ: + ppp_fsm_recv_conf_req_rej(&lcp->fsm); + break; + } + lcp_free_conf_req(lcp); + if (r==LCP_OPT_FAIL) + ppp_terminate(lcp->ppp, 0); + break; + case CONFACK: + if (lcp_recv_conf_ack(lcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN)) + ppp_terminate(lcp->ppp, 0); + else + ppp_fsm_recv_conf_ack(&lcp->fsm); + break; + case CONFNAK: + lcp_recv_conf_nak(lcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + ppp_fsm_recv_conf_rej(&lcp->fsm); + break; + case CONFREJ: + if (lcp_recv_conf_rej(lcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN)) + ppp_terminate(lcp->ppp, 0); + else + ppp_fsm_recv_conf_rej(&lcp->fsm); + break; + case TERMREQ: + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); + log_debug("recv [LCP TermReq id=%x \"%s\"]\n",hdr->id,term_msg); + free(term_msg); + ppp_fsm_recv_term_req(&lcp->fsm); + ppp_terminate(lcp->ppp, 0); + break; + case TERMACK: + term_msg=strndup((char*)(hdr+1),ntohs(hdr->len)); + log_debug("recv [LCP TermAck id=%x \"%s\"]\n",hdr->id,term_msg); + free(term_msg); + ppp_fsm_recv_term_ack(&lcp->fsm); + break; + case CODEREJ: + log_debug("recv [LCP CodeRej id=%x]\n",hdr->id); + ppp_fsm_recv_code_rej_bad(&lcp->fsm); + break; + case ECHOREQ: + send_echo_reply(lcp); + break; + case ECHOREP: + lcp_recv_echo_repl(lcp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN); + break; + default: + ppp_fsm_recv_unk(&lcp->fsm); + break; + } +} + +int lcp_option_register(struct lcp_option_handler_t *h) +{ + /*struct lcp_option_drv_t *p; + + list_for_each_entry(p,option_drv_list,entry) + if (p->id==h->id) + return -1;*/ + + list_add_tail(&h->entry,&option_handlers); + + return 0; +} + +static struct ppp_layer_t lcp_layer= +{ + .init=lcp_layer_init, + .start=lcp_layer_start, + .finish=lcp_layer_finish, + .free=lcp_layer_free, +}; + +static void __init lcp_init(void) +{ + char *opt; + + ppp_register_layer("lcp",&lcp_layer); + + opt = conf_get_opt("lcp", "echo-interval"); + if (opt && atoi(opt) > 0) + conf_echo_interval = atoi(opt); + + opt = conf_get_opt("lcp", "echo-failure"); + if (opt && atoi(opt) > 0) + conf_echo_failure = atoi(opt); + +} diff --git a/accel-pptpd/ppp/ppp_lcp.h b/accel-pptpd/ppp/ppp_lcp.h new file mode 100644 index 00000000..46bc17b9 --- /dev/null +++ b/accel-pptpd/ppp/ppp_lcp.h @@ -0,0 +1,134 @@ +#ifndef PPP_LCP_H +#define PPP_LCP_H + +#include <stdint.h> + +#include "triton.h" +#include "ppp_fsm.h" +/* + * Options. + */ +#define CI_VENDOR 0 /* Vendor Specific */ +#define CI_MRU 1 /* Maximum Receive Unit */ +#define CI_ASYNCMAP 2 /* Async Control Character Map */ +#define CI_AUTH 3 /* Authentication Type */ +#define CI_QUALITY 4 /* Quality Protocol */ +#define CI_MAGIC 5 /* Magic Number */ +#define CI_PCOMP 7 /* Protocol Field Compression */ +#define CI_ACCOMP 8 /* Address/Control Field Compression */ +#define CI_FCSALTERN 9 /* FCS-Alternatives */ +#define CI_SDP 10 /* Self-Describing-Pad */ +#define CI_NUMBERED 11 /* Numbered-Mode */ +#define CI_CALLBACK 13 /* callback */ +#define CI_MRRU 17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF 18 /* short sequence numbers for multilink */ +#define CI_EPDISC 19 /* endpoint discriminator */ +#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ +#define CI_LDISC 23 /* Link-Discriminator */ +#define CI_LCPAUTH 24 /* LCP Authentication */ +#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ +#define CI_PREFELIS 26 /* Prefix Elision */ +#define CI_MPHDRFMT 27 /* MP Header Format */ +#define CI_I18N 28 /* Internationalization */ +#define CI_SDL 29 /* Simple Data Link */ + +struct lcp_hdr_t +{ + uint16_t proto; + uint8_t code; + uint8_t id; + uint16_t len; +} __attribute__((packed)); +struct lcp_opt_hdr_t +{ + uint8_t id; + uint8_t len; +} __attribute__((packed)); +struct lcp_opt8_t +{ + struct lcp_opt_hdr_t hdr; + uint8_t val; +} __attribute__((packed)); +struct lcp_opt16_t +{ + struct lcp_opt_hdr_t hdr; + uint16_t val; +} __attribute__((packed)); +struct lcp_opt32_t +{ + struct lcp_opt_hdr_t hdr; + uint32_t val; +} __attribute__((packed)); + +/*struct lcp_options_t +{ + int magic; + int mtu; + int 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 + // negotiated options; + int neg_mru; + int neg_mtu; + int neg_accomp; // -1 - rejected + int neg_pcomp; + int neg_auth[AUTH_MAX]; +};*/ + +#define LCP_OPT_NONE 0 +#define LCP_OPT_ACK 1 +#define LCP_OPT_NAK -1 +#define LCP_OPT_REJ -2 +#define LCP_OPT_FAIL -3 + +struct ppp_lcp_t; +struct lcp_option_handler_t; + +struct lcp_option_t +{ + struct list_head entry; + int id; + int len; + int state; + struct lcp_option_handler_t *h; +}; + +struct lcp_option_handler_t +{ + struct list_head entry; + struct lcp_option_t* (*init)(struct ppp_lcp_t*); + int (*send_conf_req)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + int (*send_conf_rej)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + int (*send_conf_nak)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + int (*recv_conf_req)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + int (*recv_conf_rej)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + int (*recv_conf_nak)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + int (*recv_conf_ack)(struct ppp_lcp_t*,struct lcp_option_t*,uint8_t*); + void (*free)(struct ppp_lcp_t*,struct lcp_option_t*); + void (*print)(void (*print)(const char *fmt,...), struct lcp_option_t*,uint8_t*); +}; + +struct ppp_lcp_t +{ + struct ppp_layer_data_t ld; + struct ppp_handler_t hnd; + struct ppp_fsm_t fsm; + struct ppp_t *ppp; + struct list_head options; + + struct triton_timer_t echo_timer; + int echo_interval; + int echo_failure; + int echo_sent; + int magic; + + struct list_head ropt_list; // last received ConfReq + int ropt_len; + + int conf_req_len; +}; + +int lcp_option_register(struct lcp_option_handler_t *h); + +#endif + |