From 64b5b693764c4f36870fd988ccbb53bcb188e74d Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Thu, 5 Jul 2012 14:08:04 +0400 Subject: ipoe: futher work --- accel-pppd/ctrl/ipoe/ipoe.c | 183 +++++++++++++++++++++++++++++------- accel-pppd/ctrl/ipoe/ipoe.h | 7 +- accel-pppd/ctrl/ipoe/ipoe_netlink.c | 57 ++++++++++- accel-pppd/ifcfg.c | 8 +- accel-pppd/session.c | 22 +++-- 5 files changed, 228 insertions(+), 49 deletions(-) (limited to 'accel-pppd') diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index eedd8cf..5878b0c 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -37,7 +37,13 @@ #define USERNAME_IFNAME 0 #define USERNAME_LUA 1 +#define MODE_L2 0 +#define MODE_L3 1 + static int conf_dhcpv4 = 1; +static int conf_up = 0; +static int conf_mode = 0; +static int conf_shared = 1; //static int conf_dhcpv6; static int conf_username; @@ -51,7 +57,6 @@ static int conf_netmask = 24; static int conf_lease_time = 600; static int conf_lease_timeout = 660; static int conf_verbose; -static int conf_opt_single = 0; static unsigned int stat_starting; static unsigned int stat_active; @@ -158,10 +163,10 @@ static void ipoe_session_start(struct ipoe_session *ses) char *passwd; struct ifreq ifr; - if (ses->serv->opt_single) + if (ses->serv->opt_shared == 0) strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN); else { - ses->ifindex = ipoe_nl_create(0, 0, ses->serv->ifname, ses->hwaddr); + ses->ifindex = ipoe_nl_create(0, 0, ses->dhcpv4_request ? ses->serv->ifname : NULL, ses->hwaddr); if (ses->ifindex == -1) { log_ppp_error("ipoe: failed to create interface\n"); ipoe_session_finished(&ses->ses); @@ -178,6 +183,7 @@ static void ipoe_session_start(struct ipoe_session *ses) } strncpy(ses->ses.ifname, ifr.ifr_name, AP_IFNAME_LEN); + ses->ses.ifindex = ses->ifindex; } if (!ses->ses.username) { @@ -236,6 +242,11 @@ static void ipoe_session_start(struct ipoe_session *ses) ses->timer.expire = ipoe_session_timeout; ses->timer.expire_tv.tv_sec = conf_offer_timeout; triton_timer_add(&ses->ctx, &ses->timer, 0); + } else { + if (ipoe_nl_modify(ses->ifindex, ses->giaddr, ses->ses.ipv4->peer_addr, NULL, NULL)) + ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0); + else + ap_session_activate(&ses->ses); } } @@ -493,7 +504,7 @@ static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p dhcpv4_print_packet(pack, log_ppp_info2); } - if (serv->opt_single) + if (serv->opt_shared == 0) ipoe_drop_sessions(serv, ses); if (ses->ses.state == AP_STATE_STARTING && !ses->dhcpv4_request) { @@ -552,7 +563,9 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc ses->ctrl.terminate = ipoe_session_terminate; ses->ctrl.type = CTRL_TYPE_IPOE; ses->ctrl.name = "ipoe"; - + + ses->giaddr = iph->saddr; + ses->ctrl.calling_station_id = _malloc(17); ses->ctrl.called_station_id = _malloc(17); @@ -585,10 +598,13 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph) list_for_each_entry(serv, &serv_list, entry) { if (serv->ifindex != ifindex) continue; + + if (!serv->opt_up) + return; pthread_mutex_lock(&serv->lock); list_for_each_entry(ses, &serv->sessions, entry) { - if (memcmp(ses->hwaddr, eth->h_source, 6) == 0) { + if (ses->giaddr == iph->saddr) { pthread_mutex_unlock(&serv->lock); return; } @@ -649,42 +665,105 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip static void add_interface(const char *ifname, int ifindex, const char *opt) { - int opt_single; - const char *ptr; + char *str0, *str, *ptr1, *ptr2; + int end; struct ipoe_serv *serv; + int opt_shared = conf_shared; + int opt_dhcpv4 = 0; + int opt_up = 0; + int opt_mode = conf_mode; + + str0 = strchr(opt, ','); + if (str0) { + str0 = _strdup(str0 + 1); + str = str0; + + while (1) { + for (ptr1 = str + 1; *ptr1 && *ptr1 != '='; ptr1++); - ptr = strstr(opt, ",single"); - if (ptr) { - if (ptr[7] && ptr[7] != ',') - goto out_err_parse; - opt_single = 1; - } else { - ptr = strstr(opt, ",shared"); - if (ptr) { - if (ptr[7] && ptr[7] != ',') - goto out_err_parse; - opt_single = 0; - } else - opt_single = conf_opt_single; + if (!*ptr1) + goto parse_err; + + *ptr1 = 0; + + for (ptr2 = ++ptr1; *ptr2 && *ptr2 != ','; ptr2++); + + end = *ptr2 == 0; + + if (!end) + *ptr2 = 0; + + if (ptr2 == ptr1) + goto parse_err; + + if (strcmp(str, "start") == 0) { + if (!strcmp(ptr1, "up")) + opt_up = 1; + else if (!strcmp(ptr1, "dhcpv4")) + opt_dhcpv4 = 1; + else + goto parse_err; + } else if (strcmp(str, "shared") == 0) { + opt_shared = atoi(ptr1); + } else if (strcmp(str, "mode") == 0) { + if (!strcmp(ptr1, "L2")) + opt_mode = MODE_L2; + else if (!strcmp(ptr1, "L3")) + opt_mode = MODE_L3; + else + goto parse_err; + } else + goto parse_err; + + if (end) + break; + + str = ptr2 + 1; + } + + _free(str0); } - + + if (!opt_up && !opt_dhcpv4) { + opt_up = conf_up; + opt_dhcpv4 = conf_dhcpv4; + } + list_for_each_entry(serv, &serv_list, entry) { - if (strcmp(ifname, serv->ifname) == 0) { - serv->active = 1; - serv->ifindex = ifindex; - if (opt_single && !serv->opt_single) - ipoe_drop_sessions(serv, NULL); - serv->opt_single = opt_single; - return; + if (!strcmp(ifname, serv->ifname)) + continue; + + serv->active = 1; + serv->ifindex = ifindex; + + if ((opt_shared && !serv->opt_shared) || (!opt_shared && serv->opt_shared)) { + ipoe_drop_sessions(serv, NULL); + serv->opt_shared = opt_shared; } + + if (opt_dhcpv4 && !serv->dhcpv4) { + serv->dhcpv4 = dhcpv4_create(&serv->ctx, serv->ifname); + if (serv->dhcpv4) + serv->dhcpv4->recv = ipoe_recv_dhcpv4; + } else if (!opt_dhcpv4 && serv->dhcpv4) { + dhcpv4_free(serv->dhcpv4); + serv->dhcpv4 = NULL; + } + + serv->opt_up = opt_up; + serv->opt_mode = conf_mode; + + return; } serv = _malloc(sizeof(*serv)); memset(serv, 0, sizeof(*serv)); serv->ifname = _strdup(ifname); serv->ifindex = ifindex; - serv->opt_single = opt_single; - serv->opt_dhcpv4 = conf_dhcpv4; + serv->opt_shared = opt_shared; + serv->opt_dhcpv4 = opt_dhcpv4; + serv->opt_up = opt_up; + serv->opt_mode = opt_mode; serv->active = 1; INIT_LIST_HEAD(&serv->sessions); pthread_mutex_init(&serv->lock, NULL); @@ -703,8 +782,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt) return; -out_err_parse: +parse_err: log_error("ipoe: failed to parse '%s'\n", opt); + _free(str0); } static void load_interface(const char *opt) @@ -853,13 +933,11 @@ static void load_config(void) { const char *opt; struct conf_sect_t *s = conf_get_section("ipoe"); + struct conf_option_t *opt1; if (!s) return; - load_interfaces(s); - load_local_nets(s); - opt = conf_get_opt("ipoe", "username"); if (opt) { if (strcmp(opt, "ifname") == 0) @@ -901,6 +979,41 @@ static void load_config(void) opt = conf_get_opt("ipoe", "lease-timeout"); if (opt) conf_lease_timeout = atoi(opt); + + opt = conf_get_opt("ipoe", "shared"); + if (opt) + conf_shared = atoi(opt); + else + conf_shared = 1; + + opt = conf_get_opt("ipoe", "mode"); + if (opt) { + if (!strcmp(opt, "L2")) + conf_mode = MODE_L2; + else if (!strcmp(opt, "L3")) + conf_mode = MODE_L3; + else + log_emerg("ipoe: failed to parse 'mode=%s'\n", opt); + } else + conf_mode = MODE_L2; + + conf_dhcpv4 = 0; + conf_up = 0; + + list_for_each_entry(opt1, &s->items, entry) { + if (strcmp(opt1->name, "start")) + continue; + if (!strcmp(opt1->val, "dhcpv4")) + conf_dhcpv4 = 1; + else if (!strcmp(opt1->val, "up")) + conf_up = 1; + } + + if (!conf_dhcpv4 && !conf_up) + conf_dhcpv4 = 1; + + load_interfaces(s); + load_local_nets(s); } static void ipoe_init(void) diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 3076090..97b13e6 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -15,11 +15,13 @@ struct ipoe_serv char *ifname; int ifindex; int active; - int opt_single; - int opt_dhcpv4; struct list_head sessions; struct dhcpv4_serv *dhcpv4; pthread_mutex_t lock; + int opt_mode; + int opt_shared:1; + int opt_dhcpv4:1; + int opt_up:1; }; struct dhcp_opt @@ -60,6 +62,7 @@ void ipoe_nl_add_net(uint32_t addr, int mask); void ipoe_nl_delete_nets(void); int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr); void ipoe_nl_delete(int ifindex); +int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr); #endif diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index 57da0de..ec603d5 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -109,7 +109,7 @@ int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_ nlh->nlmsg_type = ipoe_genl_id; ghdr = NLMSG_DATA(&req.n); - ghdr->cmd = IPOE_CMD_DELETE; + ghdr->cmd = IPOE_CMD_CREATE; if (peer_addr) addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr); @@ -163,6 +163,61 @@ out: return ret; } +int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + int ret = 0; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + union { + uint8_t hwaddr[6]; + uint64_t u64; + } u; + + if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { + log_ppp_error("ipoe: cannot open generic netlink socket\n"); + return -1; + } + + nlh = &req.n; + nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_type = ipoe_genl_id; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = IPOE_CMD_MODIFY; + + addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); + + if (peer_addr) + addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr); + + if (addr) + addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); + + if (hwaddr) { + memcpy(u.hwaddr, hwaddr, 6); + addattr_l(nlh, 1024, IPOE_ATTR_HWADDR, &u.u64, 8); + } + + if (ifname) + addattr_l(nlh, 1024, IPOE_ATTR_IFNAME, ifname, strlen(ifname) + 1); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { + log_ppp_error("ipoe: nl_create: error talking to kernel\n"); + ret = -1; + } + + rtnl_close(&rth); + + return ret; +} + + void ipoe_nl_delete(int ifindex) { struct rtnl_handle rth; diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c index 11251e1..134edfb 100644 --- a/accel-pppd/ifcfg.c +++ b/accel-pppd/ifcfg.c @@ -82,16 +82,16 @@ void ap_session_ifup(struct ap_session *ses) if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno)); - if (ses->ctrl->type == CTRL_TYPE_IPOE) { + /*if (ses->ctrl->type == CTRL_TYPE_IPOE) { addr.sin_addr.s_addr = 0xffffffff; memcpy(&ifr.ifr_netmask, &addr, sizeof(addr)); if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr)) log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno)); - } + }*/ addr.sin_addr.s_addr = ses->ipv4->peer_addr; - if (ses->ctrl->type == CTRL_TYPE_IPOE) { + /*if (ses->ctrl->type == CTRL_TYPE_IPOE) { memset(&rt, 0, sizeof(rt)); memcpy(&rt.rt_dst, &addr, sizeof(addr)); rt.rt_flags = RTF_HOST | RTF_UP; @@ -99,7 +99,7 @@ void ap_session_ifup(struct ap_session *ses) rt.rt_dev = ifr.ifr_name; if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt))) log_ppp_error("failed to add route: %s\n", strerror(errno)); - } else { + } else*/ { memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr)); if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) diff --git a/accel-pppd/session.c b/accel-pppd/session.c index 0064f54..886aa40 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -17,6 +17,7 @@ #include "log.h" #include "events.h" #include "ap_session.h" +#include "spinlock.h" #include "mempool.h" #include "memdebug.h" @@ -24,6 +25,10 @@ int conf_sid_ucase; pthread_rwlock_t __export ses_lock = PTHREAD_RWLOCK_INITIALIZER; __export LIST_HEAD(ses_list); +#if __WORDSIZE == 32 +static spinlock_t seq_lock; +#endif + int __export sock_fd; int __export sock6_fd; int __export urandom_fd; @@ -39,6 +44,7 @@ void __export ap_session_init(struct ap_session *ses) { memset(ses, 0, sizeof(*ses)); INIT_LIST_HEAD(&ses->pd_list); + ses->ifindex = -1; } int __export ap_session_starting(struct ap_session *ses) @@ -47,14 +53,16 @@ int __export ap_session_starting(struct ap_session *ses) ses->start_time = time(NULL); - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, ses->ifname); - - if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) { - log_ppp_error("ioctl(SIOCGIFINDEX): %s\n", strerror(errno)); - return -1; + if (ses->ifindex == -1) { + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, ses->ifname); + + if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) { + log_ppp_error("ioctl(SIOCGIFINDEX): %s\n", strerror(errno)); + return -1; + } + ses->ifindex = ifr.ifr_ifindex; } - ses->ifindex = ifr.ifr_ifindex; generate_sessionid(ses); -- cgit v1.2.3