#include #include #include #include #include #include "linux_ppp.h" #include "ppp.h" #include "ppp_lcp.h" #include "log.h" #include "events.h" #include "memdebug.h" static int conf_pcomp = 0; 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_recv_conf_req(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); static int pcomp_recv_conf_rej(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); static int pcomp_recv_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr); static int pcomp_recv_conf_ack(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 *opt, 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, .recv_conf_req = pcomp_recv_conf_req, .recv_conf_rej = pcomp_recv_conf_rej, .recv_conf_nak = pcomp_recv_conf_nak, .recv_conf_ack = pcomp_recv_conf_ack, .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 = conf_pcomp; 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) { opt0->id = CI_PCOMP; opt0->len = 2; return 2; } return 0; } 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); struct lcp_opt_hdr_t *opt0 = (struct lcp_opt_hdr_t*)ptr; if (opt0->len != 2) return LCP_OPT_REJ; if (pcomp_opt->pcomp & 2) return LCP_OPT_ACK; else return LCP_OPT_REJ; } static int pcomp_recv_conf_rej(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); pcomp_opt->pcomp &= ~1; return 0; } static int pcomp_recv_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; if (opt0->len != 2) return -1; /* treat as reject */ return pcomp_recv_conf_rej(lcp, opt, ptr); } static int pcomp_recv_conf_ack(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); int flags; if (net->ppp_ioctl(lcp->ppp->chan_fd, PPPIOCGFLAGS, &flags)) goto err; flags &= ~SC_COMP_PROT; if (pcomp_opt->pcomp & 1) flags |= SC_COMP_PROT; if (net->ppp_ioctl(lcp->ppp->chan_fd, PPPIOCSFLAGS, &flags)) goto err; return 0; err: if (errno != EIO) log_ppp_error("lcp:pcomp: failed to set channel ACCOMP: %s\n", strerror(errno)); return -1; } static void pcomp_print(void (*print)(const char *fmt, ...), struct lcp_option_t *opt, uint8_t *ptr) { print(""); } static void load_config(void) { char *opt; opt = conf_get_opt("ppp", "pcomp"); if (opt) { if (!strcmp(opt, "deny")) conf_pcomp = 0; else if (!strcmp(opt, "allow")) conf_pcomp = 1 | 2; else conf_pcomp = atoi(opt); } } static void pcomp_opt_init() { lcp_option_register(&pcomp_opt_hnd); load_config(); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); } DEFINE_INIT(4, pcomp_opt_init);