diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-07-05 14:08:04 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-07-05 14:08:04 +0400 |
commit | 64b5b693764c4f36870fd988ccbb53bcb188e74d (patch) | |
tree | 7af1897fdb9edd9cf40885c65f8567ae58bc0de6 /accel-pppd/ctrl/ipoe | |
parent | 046642d5729493b25e5fba4b11c507fe3d2e2687 (diff) | |
download | accel-ppp-64b5b693764c4f36870fd988ccbb53bcb188e74d.tar.gz accel-ppp-64b5b693764c4f36870fd988ccbb53bcb188e74d.zip |
ipoe: futher work
Diffstat (limited to 'accel-pppd/ctrl/ipoe')
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 183 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 7 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe_netlink.c | 57 |
3 files changed, 209 insertions, 38 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index eedd8cf9..5878b0c4 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 30760906..97b13e63 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 57da0def..ec603d5d 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; |