#include #include #include #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_mtu; static int conf_mru; static int conf_min_mtu = 100; static int conf_max_mtu = 1500; 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 int mru_recv_conf_nak(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; int naked:1; }; 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, .recv_conf_nak=mru_recv_conf_nak, .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->mru = (conf_mru && conf_mru <= lcp->ppp->ctrl->max_mtu) ? conf_mru : lcp->ppp->ctrl->max_mtu; if (mru_opt->mru > conf_max_mtu) mru_opt->mru = conf_max_mtu; mru_opt->mtu = (conf_mtu && conf_mtu <= lcp->ppp->ctrl->max_mtu) ? conf_mtu : lcp->ppp->ctrl->max_mtu; if (mru_opt->mtu > conf_max_mtu) mru_opt->mtu = conf_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; if (mru_opt->naked) return 0; 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 (!ptr) return LCP_OPT_NAK;*/ if (opt16->hdr.len != 4) return LCP_OPT_REJ; if (ntohs(opt16->val) < conf_min_mtu || ntohs(opt16->val) > lcp->ppp->ctrl->max_mtu || ntohs(opt16->val) > conf_max_mtu) return LCP_OPT_NAK; mru_opt->mtu = ntohs(opt16->val); return LCP_OPT_ACK; } 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, }; strcpy(ifr.ifr_name, lcp->ppp->ifname); if (ioctl(lcp->ppp->unit_fd, PPPIOCSMRU, &mru_opt->mru)) log_ppp_error("lcp:mru: failed to set MRU: %s\n", strerror(errno)); if (ioctl(sock_fd, SIOCSIFMTU, &ifr)) log_ppp_error("lcp:mru: failed to set MTU: %s\n", strerror(errno)); return 0; } static int mru_recv_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); mru_opt->naked = 1; 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("",ntohs(opt16->val)); else print("",mru_opt->mru); } static void load_config(void) { char *opt; opt = conf_get_opt("ppp", "mtu"); if (opt && atoi(opt) > 0) conf_mtu = atoi(opt); opt = conf_get_opt("ppp", "mru"); if (opt && atoi(opt) > 0) conf_mru = atoi(opt); opt = conf_get_opt("ppp", "min-mtu"); if (opt && atoi(opt) > 0) conf_min_mtu = atoi(opt); opt = conf_get_opt("ppp", "max-mtu"); if (opt && atoi(opt) > 0) conf_max_mtu = atoi(opt); if (conf_min_mtu > conf_mru) { log_emerg("min-mtu cann't be greater then mtu/mru\n"); conf_min_mtu = conf_mru; } if (conf_min_mtu > 1500) { log_emerg("min-mtu cann't be greater then 1500\n"); conf_min_mtu = 1500; } if (conf_mru > 1500 || conf_mtu > 1500) { log_emerg("mtu/mru cann't be greater then 1500\n"); conf_mru = 1500; } } static void mru_opt_init() { load_config(); lcp_option_register(&mru_opt_hnd); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); } DEFINE_INIT(4, mru_opt_init);