diff options
-rw-r--r-- | accel-pppd/accel-ppp.conf | 1 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 3 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 241 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 13 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe_netlink.c | 128 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 675 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.h | 8 |
7 files changed, 272 insertions, 797 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index fc0fc762..bd58a7a7 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -132,7 +132,6 @@ start=dhcpv4 #attr-l4-redirect=L4-Redirect #attr-l4-redirect-table=4 #attr-l4-redirect-ipset=l4-redirect -#local-net=192.168.0.0/16 #lua-file=/etc/accel-ppp.lua #offer-delay=0,100:100,200:200,-1:1000 #vlan-mon=eth0,10-200 diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 648fd247..4deec4e1 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -354,9 +354,6 @@ The .B proxy-arp parameter specifies whether accel-ppp should reply to arp requests. .TP -.BI "local-net=" x.x.x.x/mask -Specifies networks from which packets will be treated as unclassified. You may specify multiple local-net options. -.TP .BI "proto=" n Specifies number of protocol to be used for inserted routes. .TP diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index e7f1ca50..55bedac8 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -43,15 +43,8 @@ #define USERNAME_IFNAME 1 #define USERNAME_LUA 2 -#define MODE_L2 0 -#define MODE_L3 1 - -struct ifaddr { - struct list_head entry; - in_addr_t addr; - int mask; - int refs; -}; +#define MODE_L2 2 +#define MODE_L3 3 struct iplink_arg { pcre *re; @@ -510,7 +503,8 @@ static int ipoe_create_interface(struct ipoe_session *ses) mempool_free(uc); } else { pthread_mutex_unlock(&uc_lock); - ses->ifindex = ipoe_nl_create(0, 0, ses->serv->opt_mode == MODE_L2 ? ses->serv->ifname : NULL, ses->hwaddr); + + ses->ifindex = ipoe_nl_create(ses->serv->ifindex); if (ses->ifindex == -1) { log_ppp_error("ipoe: failed to create interface\n"); ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 1); @@ -530,7 +524,6 @@ static int ipoe_create_interface(struct ipoe_session *ses) strncpy(ses->ses.ifname, ifr.ifr_name, AP_IFNAME_LEN); ses->ses.ifindex = ses->ifindex; ses->ses.unit_idx = ses->ifindex; - ses->ctrl.dont_ifcfg = !conf_ip_unnumbered; log_ppp_info2("create interface %s parent %s\n", ifr.ifr_name, ses->serv->ifname); @@ -802,115 +795,39 @@ static void __ipoe_session_start(struct ipoe_session *ses) } } -static void ipoe_serv_add_addr(struct ipoe_serv *serv, in_addr_t addr, int mask) -{ - struct ifaddr *a; - - pthread_mutex_lock(&serv->lock); - - if (serv->opt_shared) { - list_for_each_entry(a, &serv->addr_list, entry) { - if (a->addr == addr) { - a->refs++; - pthread_mutex_unlock(&serv->lock); - - return; - } - } - } - - a = _malloc(sizeof(*a)); - a->addr = addr; - a->mask = mask; - a->refs = 1; - list_add_tail(&a->entry, &serv->addr_list); - - if (ipaddr_add(serv->ifindex, a->addr, mask)) - log_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname); - - pthread_mutex_unlock(&serv->lock); -} - -static void ipoe_serv_del_addr(struct ipoe_serv *serv, in_addr_t addr, int lock) -{ - struct ifaddr *a; - - if (lock) - pthread_mutex_lock(&serv->lock); - - list_for_each_entry(a, &serv->addr_list, entry) { - if (a->addr == addr) { - if (--a->refs == 0) { - if (ipaddr_del(serv->ifindex, a->addr, a->mask)) - log_warn("ipoe: failed to delete addess from interface '%s'\n", serv->ifname); - list_del(&a->entry); - _free(a); - } - break; - } - } - - if (lock) - pthread_mutex_unlock(&serv->lock); -} - -static void ipoe_ifcfg_add(struct ipoe_session *ses) -{ - struct ipoe_serv *serv = ses->serv; - - if (ses->serv->opt_ifcfg) - ipoe_serv_add_addr(ses->serv, ses->siaddr, conf_ip_unnumbered ? 32 : ses->mask); - - if (conf_ip_unnumbered) { - if (iproute_add(serv->ifindex, ses->serv->opt_src ? ses->serv->opt_src : ses->router, ses->yiaddr, 0, conf_proto, 32)) - log_ppp_warn("ipoe: failed to add route to interface '%s'\n", serv->ifname); - } - - ses->ifcfg = 1; -} - -static void ipoe_ifcfg_del(struct ipoe_session *ses, int lock) -{ - struct ipoe_serv *serv = ses->serv; - - if (conf_ip_unnumbered) { - if (iproute_del(serv->ifindex, ses->yiaddr, conf_proto, 32)) - log_ppp_warn("ipoe: failed to delete route from interface '%s'\n", serv->ifname); - } - - if (ses->serv->opt_ifcfg) - ipoe_serv_del_addr(ses->serv, ses->siaddr, lock); -} - static void __ipoe_session_activate(struct ipoe_session *ses) { - uint32_t addr; + uint32_t addr, gw = 0; + struct ipoe_serv *serv = ses->serv; if (ses->terminating) return; if (ses->ifindex != -1) { addr = 0; - if (!ses->ses.ipv4) { + /*if (!ses->ses.ipv4) { if (ses->serv->opt_mode == MODE_L3) { addr = 1; ses->ctrl.dont_ifcfg = 1; } - } else if (ses->ses.ipv4->peer_addr != ses->yiaddr) + } else*/ + if (ses->ses.ipv4 && ses->ses.ipv4->peer_addr != ses->yiaddr) addr = ses->ses.ipv4->peer_addr; - else if (!conf_ip_unnumbered) - ses->ctrl.dont_ifcfg = 1; - if (ses->dhcpv4_request && ses->serv->opt_mode == MODE_L3) { + /*if (ses->dhcpv4_request && ses->serv->opt_mode == MODE_L3) { in_addr_t gw; - iproute_get(ses->router, &gw); + iproute_get(ses->router, &gw, NULL); if (gw) iproute_add(0, ses->siaddr, ses->yiaddr, gw, conf_proto, 32); else iproute_add(0, ses->siaddr, ses->router, gw, conf_proto, 32); - } + }*/ - if (ipoe_nl_modify(ses->ifindex, ses->yiaddr, addr, NULL, NULL)) { + if (serv->opt_mode == MODE_L3) + iproute_get(ses->yiaddr, &gw); + + //if (ipoe_nl_modify(ses->ifindex, ses->yiaddr, addr, gw, gw ? 0 : ses->serv->ifindex, gw ? NULL : ses->hwaddr)) { + if (ipoe_nl_modify(ses->ifindex, ses->yiaddr, addr, gw, serv->ifindex, ses->hwaddr)) { ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 1); return; } @@ -924,17 +841,15 @@ static void __ipoe_session_activate(struct ipoe_session *ses) } if (ses->ifindex == -1) { - if (ses->serv->opt_ifcfg || (ses->serv->opt_mode == MODE_L2)) - ipoe_ifcfg_add(ses); - - ipoe_nl_add_exclude(ses->yiaddr, 32); - - ses->ctrl.dont_ifcfg = 1; - } else if (ses->ctrl.dont_ifcfg && ses->serv->opt_mode == MODE_L2) - ipaddr_add(ses->ifindex, ses->siaddr, ses->mask); + if (serv->opt_ifcfg) + ipaddr_add(serv->ifindex, ses->router, conf_ip_unnumbered ? 32 : ses->mask); + else if (!conf_ip_unnumbered) + iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask); - if (ses->l4_redirect) - ipoe_change_l4_redirect(ses, 0); + if (conf_ip_unnumbered) + iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32); + } else + ses->ctrl.dont_ifcfg = 0; if (ses->serv->opt_mode == MODE_L2 && ses->serv->opt_ipv6 && sock6_fd != -1) { ses->ses.ipv6 = ipdb_get_ipv6(&ses->ses); @@ -950,6 +865,9 @@ static void __ipoe_session_activate(struct ipoe_session *ses) ap_session_activate(&ses->ses); + if (ses->l4_redirect) + ipoe_change_l4_redirect(ses, 0); + if (ses->dhcpv4_request) { if (ses->ses.state == AP_STATE_ACTIVE) dhcpv4_send_reply(DHCPACK, ses->dhcpv4 ?: ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->router, ses->mask, ses->lease_time, ses->renew_time, ses->dhcpv4_relay_reply); @@ -1090,12 +1008,13 @@ static void ipoe_session_free(struct ipoe_session *ses) static void ipoe_session_finished(struct ap_session *s) { struct ipoe_session *ses = container_of(s, typeof(*ses), ses); + struct ipoe_serv *serv = ses->serv; struct unit_cache *uc; log_ppp_info1("ipoe: session finished\n"); if (ses->ifindex != -1) { - if (uc_size < conf_unit_cache && ipoe_nl_modify(ses->ifindex, 0, 0, "", NULL)) { + if (uc_size < conf_unit_cache && !ipoe_nl_modify(ses->ifindex, 0, 0, 0, 0, NULL)) { uc = mempool_alloc(uc_pool); uc->ifindex = ses->ifindex; pthread_mutex_lock(&uc_lock); @@ -1104,8 +1023,14 @@ static void ipoe_session_finished(struct ap_session *s) pthread_mutex_unlock(&uc_lock); } else ipoe_nl_delete(ses->ifindex); - } else - ipoe_nl_del_exclude(ses->yiaddr); + } else if (ses->started) { + if (serv->opt_ifcfg) + ipaddr_del(serv->ifindex, ses->router, conf_ip_unnumbered ? 32 : ses->mask); + else if (conf_ip_unnumbered) + iproute_del(serv->ifindex, ses->yiaddr, conf_proto, 32); + else + iproute_del(serv->ifindex, ses->yiaddr, conf_proto, ses->mask); + } if (ses->dhcp_addr) dhcpv4_put_ip(ses->serv->dhcpv4, ses->yiaddr); @@ -1113,9 +1038,6 @@ static void ipoe_session_finished(struct ap_session *s) if (ses->relay_addr && ses->serv->dhcpv4_relay) dhcpv4_relay_send_release(ses->serv->dhcpv4_relay, ses->hwaddr, ses->xid, ses->yiaddr, ses->client_id, ses->relay_agent, ses->serv->ifname, conf_agent_remote_id); - if (ses->ifcfg) - ipoe_ifcfg_del(ses, 1); - if (ses->dhcpv4) dhcpv4_free(ses->dhcpv4); @@ -1152,9 +1074,6 @@ static void ipoe_session_terminated(struct ipoe_session *ses) if (ses->l4_redirect_set) ipoe_change_l4_redirect(ses, 1); - if (!ses->serv->opt_shared) - ses->ctrl.dont_ifcfg = 1; - ap_session_finished(&ses->ses); } @@ -1850,6 +1769,8 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc if (conf_ip_pool) ses->ses.ipv4_pool_name = _strdup(conf_ip_pool); + ses->ctrl.dont_ifcfg = 1; + triton_context_register(&ses->ctx, &ses->ses); triton_context_wakeup(&ses->ctx); @@ -2098,10 +2019,8 @@ static void ipoe_serv_release(struct ipoe_serv *serv) if (serv->dhcpv4) dhcpv4_free(serv->dhcpv4); - if (serv->dhcpv4_relay) { - ipoe_serv_del_addr(serv, serv->dhcpv4_relay->giaddr, 0); + if (serv->dhcpv4_relay) dhcpv4_relay_free(serv->dhcpv4_relay, &serv->ctx); - } if (serv->arp) arpd_stop(serv->arp); @@ -2126,8 +2045,7 @@ static void ipoe_serv_release(struct ipoe_serv *serv) if (serv->timer.tpd) triton_timer_del(&serv->timer); - if (serv->opt_up) - ipoe_nl_del_interface(serv->ifindex); + ipoe_nl_del_interface(serv->ifindex); if (serv->vid) { log_info2("ipoe: remove vlan %s\n", serv->ifname); @@ -2226,10 +2144,6 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip continue; ses->terminating = 1; - if (ses->ifcfg) { - ipoe_ifcfg_del(ses, 0); - ses->ifcfg = 0; - } if (ses->ses.state == AP_STATE_ACTIVE) ap_session_ifdown(&ses->ses); @@ -2490,7 +2404,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int } if (opt_up) - ipoe_nl_add_interface(ifindex); + ipoe_nl_add_interface(ifindex, opt_mode); + else + ipoe_nl_add_interface(ifindex, 0); pthread_mutex_lock(&serv_lock); list_for_each_entry(serv, &serv_list, entry) { @@ -2516,17 +2432,12 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (serv->dhcpv4_relay && (serv->dhcpv4_relay->addr != relay_addr || serv->dhcpv4_relay->giaddr != opt_giaddr)) { - if (serv->opt_ifcfg) - ipoe_serv_del_addr(serv, serv->dhcpv4_relay->giaddr, 0); dhcpv4_relay_free(serv->dhcpv4_relay, &serv->ctx); serv->dhcpv4_relay = NULL; } - if (!serv->dhcpv4_relay && serv->opt_dhcpv4 && opt_relay) { - if (opt_ifcfg) - ipoe_serv_add_addr(serv, opt_giaddr, 32); + if (!serv->dhcpv4_relay && serv->opt_dhcpv4 && opt_relay) serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay); - } if (serv->arp && !conf_arp) { arpd_stop(serv->arp); @@ -2589,7 +2500,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int serv->ctx.close = ipoe_serv_close; serv->ctx.before_switch = ipoe_ctx_switch; pthread_mutex_init(&serv->lock, NULL); - serv->ifname = _strdup(ifname); + strcpy(serv->ifname, ifname); serv->ifindex = ifindex; serv->opt_shared = opt_shared; serv->opt_dhcpv4 = opt_dhcpv4; @@ -2608,7 +2519,6 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int serv->vid = vid; serv->active = 1; INIT_LIST_HEAD(&serv->sessions); - INIT_LIST_HEAD(&serv->addr_list); INIT_LIST_HEAD(&serv->disc_list); INIT_LIST_HEAD(&serv->req_list); memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); @@ -2621,11 +2531,8 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int if (serv->dhcpv4) serv->dhcpv4->recv = ipoe_recv_dhcpv4; - if (opt_relay) { - if (opt_ifcfg) - ipoe_serv_add_addr(serv, opt_giaddr, 32); + if (opt_relay) serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay); - } } if (serv->opt_arp) @@ -2741,8 +2648,6 @@ static void load_interfaces(struct conf_sect_t *sect) struct ipoe_serv *serv; struct conf_option_t *opt; - ipoe_nl_delete_interfaces(); - list_for_each_entry(serv, &serv_list, entry) serv->active = 0; @@ -2760,60 +2665,13 @@ static void load_interfaces(struct conf_sect_t *sect) list_for_each_entry(serv, &serv_list, entry) { if (!serv->active && !serv->vid) { + ipoe_nl_del_interface(serv->ifindex); ipoe_drop_sessions(serv, NULL); triton_context_call(&serv->ctx, (triton_event_func)ipoe_serv_release, serv); } } } -static void parse_local_net(const char *opt) -{ - const char *ptr; - char str[17]; - in_addr_t addr; - int mask; - char *endptr; - - ptr = strchr(opt, '/'); - if (ptr) { - memcpy(str, opt, ptr - opt); - str[ptr - opt] = 0; - addr = inet_addr(str); - if (addr == INADDR_NONE) - goto out_err; - mask = strtoul(ptr + 1, &endptr, 10); - if (mask > 32) - goto out_err; - } else { - addr = inet_addr(opt); - if (addr == INADDR_NONE) - goto out_err; - mask = 24; - } - - ipoe_nl_add_net(addr, mask); - - return; - -out_err: - log_error("ipoe: failed to parse 'local-net=%s'\n", opt); -} - -static void load_local_nets(struct conf_sect_t *sect) -{ - struct conf_option_t *opt; - - ipoe_nl_delete_nets(); - - list_for_each_entry(opt, §->items, entry) { - if (strcmp(opt->name, "local-net")) - continue; - if (!opt->val) - continue; - parse_local_net(opt->val); - } -} - static void load_gw_addr(struct conf_sect_t *sect) { struct conf_option_t *opt; @@ -3369,7 +3227,6 @@ static void load_config(void) parse_offer_delay(conf_get_opt("ipoe", "offer-delay")); load_interfaces(s); - load_local_nets(s); load_vlan_mon(s); load_gw_addr(s); } diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 8c647b78..5561646d 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -3,6 +3,7 @@ #include <stdint.h> #include <pthread.h> +#include <linux/if.h> #include "triton.h" #include "ap_session.h" @@ -20,11 +21,10 @@ struct ipoe_serv { struct list_head entry; struct triton_context_t ctx; - char *ifname; + char ifname[IFNAMSIZ]; int ifindex; uint8_t hwaddr[ETH_ALEN]; struct list_head sessions; - struct list_head addr_list; struct dhcpv4_serv *dhcpv4; struct dhcpv4_relay *dhcpv4_relay; void *arp; @@ -88,7 +88,6 @@ struct ipoe_session { #ifdef RADIUS struct rad_plugin_t radius; #endif - int ifcfg:1; int started:1; int terminating:1; int dhcp_addr:1; @@ -120,14 +119,12 @@ struct ipoe_session *ipoe_session_alloc(void); struct ipoe_serv *ipoe_find_serv(const char *ifname); -void ipoe_nl_add_net(uint32_t addr, int mask); -void ipoe_nl_delete_nets(void); -void ipoe_nl_add_interface(int ifindex); +void ipoe_nl_add_interface(int ifindex, uint8_t mode); void ipoe_nl_del_interface(int ifindex); void ipoe_nl_delete_interfaces(void); -int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr); +int ipoe_nl_create(int ifindex); 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); +int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, uint32_t gw, int link_ifindex, uint8_t *hwaddr); void ipoe_nl_get_sessions(struct list_head *list); int ipoe_nl_add_exclude(uint32_t addr, int mask); void ipoe_nl_del_exclude(uint32_t addr); diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index fa7b0a22..cd2433e9 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -17,6 +17,7 @@ #include "log.h" #include "genl.h" #include "libnetlink.h" +#include "iputils.h" #include "ipoe.h" #include "if_ipoe.h" @@ -29,61 +30,6 @@ static struct rtnl_handle rth; static struct triton_md_handler_t mc_hnd; static int ipoe_genl_id; -void ipoe_nl_delete_nets(void) -{ - struct nlmsghdr *nlh; - struct genlmsghdr *ghdr; - struct { - struct nlmsghdr n; - char buf[1024]; - } req; - - if (rth.fd == -1) - return; - - 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_DEL_NET; - - addattr32(nlh, 1024, IPOE_ATTR_ADDR, 0); - - if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) - log_error("ipoe: nl_del_net: error talking to kernel\n"); -} - -void ipoe_nl_add_net(uint32_t addr, int mask) -{ - struct nlmsghdr *nlh; - struct genlmsghdr *ghdr; - struct { - struct nlmsghdr n; - char buf[1024]; - } req; - - if (rth.fd == -1) - return; - - 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_ADD_NET; - - mask = mask ? ~0 << (32 - mask) : 0; - - addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); - addattr32(nlh, 1024, IPOE_ATTR_MASK, mask); - - if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) - log_error("ipoe: nl_add_net: error talking to kernel\n"); -} - int ipoe_nl_add_exclude(uint32_t addr, int mask) { struct rtnl_handle rth; @@ -152,33 +98,7 @@ void ipoe_nl_del_exclude(uint32_t addr) rtnl_close(&rth); } -void ipoe_nl_delete_interfaces(void) -{ - struct nlmsghdr *nlh; - struct genlmsghdr *ghdr; - struct { - struct nlmsghdr n; - char buf[1024]; - } req; - - if (rth.fd == -1) - return; - - 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_DEL_IF; - - addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, -1); - - if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) - log_error("ipoe: nl_del_iface: error talking to kernel\n"); -} - -void ipoe_nl_add_interface(int ifindex) +void ipoe_nl_add_interface(int ifindex, uint8_t mode) { struct nlmsghdr *nlh; struct genlmsghdr *ghdr; @@ -199,6 +119,7 @@ void ipoe_nl_add_interface(int ifindex) ghdr->cmd = IPOE_CMD_ADD_IF; addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); + addattr_l(nlh, 1024, IPOE_ATTR_MODE, &mode, 1); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) log_error("ipoe: nl_add_iface: error talking to kernel\n"); @@ -230,7 +151,12 @@ void ipoe_nl_del_interface(int ifindex) log_error("ipoe: nl_del_iface: error talking to kernel\n"); } -int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr) +void ipoe_nl_delete_interfaces(void) +{ + ipoe_nl_del_interface(-1); +} + +int ipoe_nl_create(int ifindex) { struct rtnl_handle rth; struct nlmsghdr *nlh; @@ -243,10 +169,6 @@ int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_ 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"); @@ -261,19 +183,7 @@ int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_ ghdr = NLMSG_DATA(&req.n); ghdr->cmd = IPOE_CMD_CREATE; - 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); + addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) log_ppp_error("ipoe: nl_create: error talking to kernel\n"); @@ -313,7 +223,7 @@ out: return ret; } -int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr) +int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, uint32_t gw, int link_ifindex, uint8_t *hwaddr) { struct rtnl_handle rth; struct nlmsghdr *nlh; @@ -323,10 +233,6 @@ int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *i 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"); @@ -344,14 +250,11 @@ int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *i addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr); addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); + addattr32(nlh, 1024, IPOE_ATTR_GW_ADDR, gw); + addattr32(nlh, 1024, IPOE_ATTR_LINK_IFINDEX, link_ifindex); - 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 (hwaddr) + addattr_l(nlh, 1024, IPOE_ATTR_HWADDR, hwaddr, 6); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_ppp_error("ipoe: nl_create: error talking to kernel\n"); @@ -631,6 +534,7 @@ static void init(void) triton_context_wakeup(&mc_ctx); ipoe_nl_del_exclude(0); + ipoe_nl_delete_interfaces(); } DEFINE_INIT(19, init); diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index dd5120c4..f0483066 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -52,13 +52,11 @@ #define DEFINE_SEMAPHORE(name) struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) #endif -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) struct ipoe_stats { struct u64_stats_sync sync; u64 packets; u64 bytes; }; -#endif struct ipoe_session { struct list_head entry; @@ -66,6 +64,7 @@ struct ipoe_session { __be32 addr; __be32 peer_addr; + __be32 gw; __u8 hwaddr[ETH_ALEN]; struct net_device *dev; @@ -73,10 +72,8 @@ struct ipoe_session { atomic_t refs; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) struct ipoe_stats __percpu *rx_stats; struct ipoe_stats __percpu *tx_stats; -#endif }; struct ipoe_network { @@ -92,6 +89,7 @@ struct ipoe_iface { struct list_head entry; int ifindex; + int mode; }; struct ipoe_entry_u { @@ -109,7 +107,6 @@ static struct list_head ipoe_excl_list[HASH_BITS + 1]; static LIST_HEAD(ipoe_list2); static LIST_HEAD(ipoe_list2_u); static DEFINE_SEMAPHORE(ipoe_wlock); -static LIST_HEAD(ipoe_networks); static LIST_HEAD(ipoe_interfaces); static struct work_struct ipoe_queue_work; static struct sk_buff_head ipoe_queue; @@ -119,12 +116,10 @@ static DEFINE_TIMER(ipoe_timer_u, ipoe_start_queue_work, 0, 0); static struct ipoe_session *ipoe_lookup(__be32 addr); static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer); -static void ipoe_queue_u(struct sk_buff *skb, __be32 addr); +static int ipoe_queue_u(struct sk_buff *skb, __be32 addr); static int ipoe_lookup1_u(__be32 addr, unsigned long *ts); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) static const struct net_device_ops ipoe_netdev_ops; -#endif static struct genl_family ipoe_nl_family; #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) @@ -156,7 +151,6 @@ static inline int hash_addr(__be32 addr) #endif } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) static void ipoe_update_stats(struct sk_buff *skb, struct ipoe_stats *st, int corr) { u64_stats_update_begin(&st->sync); @@ -164,33 +158,6 @@ static void ipoe_update_stats(struct sk_buff *skb, struct ipoe_stats *st, int co st->bytes += skb->len - corr; u64_stats_update_end(&st->sync); } -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) -static void ipoe_kfree_rcu(struct rcu_head *head) -{ - kfree(head); -} -#endif - -static int ipoe_check_network(__be32 addr) -{ - struct ipoe_network *n; - int r = 0; - - rcu_read_lock(); - - list_for_each_entry_rcu(n, &ipoe_networks, entry) { - if ((ntohl(addr) & n->mask) == n->addr) { - r = 1; - break; - } - } - - rcu_read_unlock(); - - return r; -} static int ipoe_check_exclude(__be32 addr) { @@ -214,25 +181,6 @@ static int ipoe_check_exclude(__be32 addr) return r; } -static int ipoe_check_interface(int ifindex) -{ - struct ipoe_iface *i; - int r = 0; - - rcu_read_lock(); - - list_for_each_entry_rcu(i, &ipoe_interfaces, entry) { - if (i->ifindex == ifindex) { - r = 1; - break; - } - } - - rcu_read_unlock(); - - return r; -} - static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer) { struct iphdr *iph; @@ -356,62 +304,41 @@ static struct net *pick_net(struct sk_buff *skb) return &init_net; } -static int ipoe_route4(struct sk_buff *skb) +/*static int ipoe_route4(struct sk_buff *skb, __be32 gw, int oif) { const struct iphdr *iph = ip_hdr(skb); struct net *net = pick_net(skb); struct rtable *rt; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) - struct flowi fl4; -#else struct flowi4 fl4; -#endif memset(&fl4, 0, sizeof(fl4)); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) - fl4.fl4_dst = iph->daddr; - fl4.fl4_tos = RT_TOS(iph->tos); - fl4.fl4_scope = RT_SCOPE_UNIVERSE; - if (ip_route_output_key(net, &rt, &fl4)) - return -1; -#else - fl4.daddr = iph->daddr; - fl4.flowi4_tos = RT_TOS(iph->tos); + fl4.daddr = gw; + fl4.flowi4_oif = oif; + fl4.flowi4_tos = RT_TOS(iph->tos) | RTO_ONLINK; fl4.flowi4_scope = RT_SCOPE_UNIVERSE; rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) return -1; -#endif skb_dst_drop(skb); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) - skb_dst_set(skb, &rt->u.dst); - skb->dev = rt->u.dst.dev; -#else skb_dst_set(skb, &rt->dst); - skb->dev = rt->dst.dev; -#endif + skb->dev = rt->dst.dev; return 0; -} +}*/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) -static int ipoe_xmit(struct sk_buff *skb, struct net_device *dev) -#else static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) -#endif { struct ipoe_session *ses = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; struct iphdr *iph; struct sk_buff *skb1; - struct dst_entry *dst; + //struct dst_entry *dst; /*struct arphdr *arp; unsigned char *arp_ptr; __be32 tip;*/ int noff; - unsigned char *cb_ptr; if (!ses->peer_addr) goto drop; @@ -428,25 +355,6 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) //pr_info("ipoe: xmit %08x %08x\n", iph->saddr, iph->daddr); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) - ipoe_update_stats(skb, this_cpu_ptr(ses->tx_stats), ETH_HLEN); -#else - stats->tx_packets++; - stats->tx_bytes += skb->len - ETH_HLEN; -#endif - - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) - dst = skb_dst(skb); -#else - dst = skb->dst; -#endif - if (dst && dst->dev != skb->dev) { - skb->dev = dst->dev; - dev_queue_xmit(skb); - return NETDEV_TX_OK; - } - //pr_info("ipoe: xmit1 %08x %08x\n", iph->saddr, iph->daddr); if (iph->daddr == ses->addr) { if (skb_shared(skb)) { @@ -461,24 +369,18 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } - if (!ses->link_dev) { + /*if (ses->gw) { iph = ip_hdr(skb); ip_send_check(iph); - if (ipoe_route4(skb)) + if (ipoe_route4(skb, ses->gw, ses->link_dev->ifindex)) goto drop; pskb_pull(skb, ETH_HLEN); skb_reset_network_header(skb); - cb_ptr = skb->cb + sizeof(skb->cb) - 2; - *(__u16 *)cb_ptr = IPOE_MAGIC; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) - skb->skb_iif = dev->ifindex; -#else - skb->iif = dev->ifindex; -#endif + //skb->skb_iif = dev->ifindex; //pr_info("ipoe: xmit2 %08x %08x %p %p\n", iph->saddr, iph->daddr, dev, skb->dev); nf_reset(skb); @@ -493,27 +395,22 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) #endif return NETDEV_TX_OK; - } else { - struct ethhdr *eth = (struct ethhdr *)skb->data; - - memcpy(eth->h_dest, ses->hwaddr, ETH_ALEN); - memcpy(eth->h_source, ses->link_dev->dev_addr, ETH_ALEN); - } + } else*/ } + ipoe_update_stats(skb, this_cpu_ptr(ses->tx_stats), ETH_HLEN); + if (ses->link_dev) { - cb_ptr = skb->cb + sizeof(skb->cb) - 2; - *(__u16 *)cb_ptr = IPOE_MAGIC; + struct ethhdr *eth = (struct ethhdr *)skb->data; + memcpy(eth->h_dest, ses->hwaddr, ETH_ALEN); + memcpy(eth->h_source, ses->link_dev->dev_addr, ETH_ALEN); + skb->dev = ses->link_dev; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) - skb->skb_iif = dev->ifindex; -#else - skb->iif = dev->ifindex; -#endif dev_queue_xmit(skb); return NETDEV_TX_OK; } + drop: stats->tx_dropped++; dev_kfree_skb(skb); @@ -555,26 +452,24 @@ static struct ipoe_entry_u *ipoe_lookup2_u(__be32 addr) } -static void ipoe_queue_u(struct sk_buff *skb, __u32 addr) +static int ipoe_queue_u(struct sk_buff *skb, __u32 addr) { unsigned long ts; if (ipoe_lookup1_u(addr, &ts) && jiffies_to_msecs(jiffies - ts) < IPOE_RATE_U) { //pr_info("not queue %08x\n", addr); - return; + return -1; } if (skb_queue_len(&ipoe_queue) > IPOE_QUEUE_LEN) - return; - - skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) - return; + return -1; //pr_info("queue %08x\n", addr); skb_queue_tail(&ipoe_queue, skb); schedule_work(&ipoe_queue_work); + + return 0; } static void ipoe_start_queue_work(unsigned long dummy) @@ -634,11 +529,7 @@ static void ipoe_process_queue(struct work_struct *w) if (!ns) goto nl_err; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) if (nla_put_u32(report_skb, IPOE_ATTR_IFINDEX, skb->dev ? skb->dev->ifindex : skb->skb_iif)) -#else - if (nla_put_u32(report_skb, IPOE_ATTR_IFINDEX, skb->dev ? skb->dev->ifindex : skb->iif)) -#endif goto nl_err; if (nla_put(report_skb, IPOE_ATTR_ETH_HDR, sizeof(*eth), eth)) @@ -677,11 +568,7 @@ nl_err: //pr_info("free %08x\n", e->addr); list_del(&e->entry2); list_del_rcu(&e->entry1); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) kfree_rcu(e, rcu_head); -#else - call_rcu(&e->rcu_head, ipoe_kfree_rcu); -#endif } synchronize_rcu(); @@ -724,47 +611,30 @@ static struct ipoe_session *ipoe_lookup(__be32 addr) return NULL; } -static struct ipoe_session *ipoe_lookup_rt(struct sk_buff *skb, __be32 addr) +static struct ipoe_session *ipoe_lookup_rt(struct sk_buff *skb, __be32 addr, struct net_device **dev) { struct net *net = pick_net(skb); struct rtable *rt; - struct net_device *dev; struct ipoe_session *ses; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) - struct flowi fl4; -#else struct flowi4 fl4; -#endif memset(&fl4, 0, sizeof(fl4)); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) - fl4.fl4_dst = addr; - fl4.fl4_tos = RT_TOS(0); - fl4.fl4_scope = RT_SCOPE_UNIVERSE; - if (ip_route_output_key(net, &rt, &fl4)) - return NULL; -#else fl4.daddr = addr; fl4.flowi4_tos = RT_TOS(0); fl4.flowi4_scope = RT_SCOPE_UNIVERSE; rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) return NULL; -#endif -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) - dev = rt->u.dst.dev; -#else - dev = rt->dst.dev; -#endif + *dev = rt->dst.dev; - if (dev->netdev_ops != &ipoe_netdev_ops) { + if ((*dev)->netdev_ops != &ipoe_netdev_ops) { ip_rt_put(rt); return NULL; } - ses = netdev_priv(dev); + ses = netdev_priv(*dev); atomic_inc(&ses->refs); ip_rt_put(rt); @@ -772,122 +642,96 @@ static struct ipoe_session *ipoe_lookup_rt(struct sk_buff *skb, __be32 addr) return ses; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) -static unsigned int ipt_in_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *skb)) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) -static unsigned int ipt_in_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *skb)) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) -static unsigned int ipt_in_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) -#else -static unsigned int ipt_in_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) -#endif +static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) { + struct sk_buff *skb = *pskb; + struct net_device *dev = skb->dev; + struct ipoe_iface *i = rcu_dereference(dev->rx_handler_data); + struct net_device *out = NULL; struct ipoe_session *ses = NULL; struct iphdr *iph; struct ethhdr *eth; int noff; - struct sk_buff *skb1; - unsigned char *cb_ptr; struct net_device_stats *stats; - int ret = NF_DROP; - if (skb->protocol != htons(ETH_P_IP)) - return NF_ACCEPT; + if (!i) + return RX_HANDLER_PASS; - cb_ptr = skb->cb + sizeof(skb->cb) - 2; + if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) + return RX_HANDLER_PASS; - if (*(__u16 *)cb_ptr == IPOE_MAGIC) - return NF_ACCEPT; + if (skb->protocol != htons(ETH_P_IP)) + return RX_HANDLER_PASS; noff = skb_network_offset(skb); if (!pskb_may_pull(skb, sizeof(*iph) + noff)) - return NF_ACCEPT; + return RX_HANDLER_PASS; iph = ip_hdr(skb); if (!iph->saddr) - return NF_ACCEPT; + return RX_HANDLER_PASS; //pr_info("ipoe: recv %08x %08x\n", iph->saddr, iph->daddr); - ses = ipoe_lookup_rt(skb, iph->saddr); + ses = ipoe_lookup_rt(skb, iph->saddr, &out); if (!ses) { - if (ipoe_check_exclude(iph->saddr)) - return NF_ACCEPT; + if (i->mode == 0) + return RX_HANDLER_PASS; - if (!ipoe_check_network(iph->saddr)) - return NF_ACCEPT; + if (out == dev && i->mode == 2) + return RX_HANDLER_PASS; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) - if (!ipoe_check_interface(in->ifindex)) -#else - if (!ipoe_check_interface(state->in->ifindex)) -#endif - return NF_ACCEPT; + if (out != dev && i->mode == 3) { + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } - ipoe_queue_u(skb, iph->saddr); - return NF_DROP; + if (ipoe_check_exclude(iph->saddr)) + return RX_HANDLER_PASS; + + if (ipoe_queue_u(skb, iph->saddr)) + kfree_skb(skb); + + return RX_HANDLER_CONSUMED; } stats = &ses->dev->stats; - if (ses->link_dev) { + /*if (ses->link_dev) { eth = eth_hdr(skb); if (memcmp(eth->h_source, ses->hwaddr, ETH_ALEN)) { stats->rx_dropped++; - goto out; + kfree_skb(skb); + return RX_HANDLER_CONSUMED; } - } - - if (skb->dev == ses->dev) { - ret = NF_ACCEPT; - goto out; - } - - if (ses->addr && ipoe_check_network(iph->daddr)) { - ret = NF_ACCEPT; - goto out; - } + }*/ + eth = eth_hdr(skb); + memcpy(ses->hwaddr, eth->h_source, ETH_ALEN); - skb1 = skb_clone(skb, GFP_ATOMIC); - if (!skb1) { - stats->rx_dropped++; - goto out; - } - - if (ses->addr > 1 && ipoe_do_nat(skb1, ses->addr, 0)) { - kfree_skb(skb1); - goto out; - } - - skb1->dev = ses->dev; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) - skb1->skb_iif = skb->dev->ifindex; -#else - skb1->iif = skb->dev->ifindex; -#endif + if (ses->addr > 1 && ipoe_do_nat(skb, ses->addr, 0)) + goto drop; - cb_ptr = skb1->cb + sizeof(skb1->cb) - 2; - *(__u16 *)cb_ptr = IPOE_MAGIC; + skb->dev = ses->dev; + skb->skb_iif = ses->dev->ifindex; + skb->tc_verd = SET_TC_NCLS(0); + memset(skb->cb, 0, sizeof(skb->cb)); - //skb1->tc_verd = SET_TC_NCLS(0); + ipoe_update_stats(skb, this_cpu_ptr(ses->rx_stats), 0); - netif_rx(skb1); + atomic_dec(&ses->refs); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) - ipoe_update_stats(skb, this_cpu_ptr(ses->rx_stats), 0); -#else - stats->rx_packets++; - stats->rx_bytes += skb->len; -#endif + return RX_HANDLER_ANOTHER; -out: +drop: atomic_dec(&ses->refs); - return ret; + stats->rx_dropped++; + kfree_skb(skb); + return RX_HANDLER_CONSUMED; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +/*#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) static unsigned int ipt_out_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *skb)) #elif LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) static unsigned int ipt_out_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *skb)) @@ -901,6 +745,13 @@ static unsigned int ipt_out_hook(void *priv, struct sk_buff *skb, const struct n struct iphdr *iph; struct ipoe_session *ses; unsigned char *cb_ptr; + struct net_device *dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) + struct net_device *out = state->out; +#endif + + if (!out->atalk_ptr) + return NF_ACCEPT; if (skb->protocol != htons(ETH_P_IP)) return NF_ACCEPT; @@ -919,13 +770,7 @@ static unsigned int ipt_out_hook(void *priv, struct sk_buff *skb, const struct n if (ipoe_check_exclude(iph->daddr)) return NF_ACCEPT; - if (!ipoe_check_network(iph->daddr)) - return NF_ACCEPT; - - if (ipoe_check_network(iph->saddr)) - return NF_ACCEPT; - - ses = ipoe_lookup_rt(skb, iph->daddr); + ses = ipoe_lookup_rt(skb, iph->daddr, &dev); if (!ses) return NF_ACCEPT; @@ -944,9 +789,8 @@ static unsigned int ipt_out_hook(void *priv, struct sk_buff *skb, const struct n atomic_dec(&ses->refs); return NF_ACCEPT; -} +}*/ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) static struct rtnl_link_stats64 *ipoe_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { @@ -991,18 +835,15 @@ static struct rtnl_link_stats64 *ipoe_stats64(struct net_device *dev, return stats; } -#endif static void ipoe_free_netdev(struct net_device *dev) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) struct ipoe_session *ses = netdev_priv(dev); if (ses->rx_stats) free_percpu(ses->rx_stats); if (ses->tx_stats) free_percpu(ses->tx_stats); -#endif free_netdev(dev); } @@ -1032,11 +873,7 @@ static const struct header_ops ipoe_hard_header_ops = { static void ipoe_netdev_setup(struct net_device *dev) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) - dev->hard_start_xmit = ipoe_xmit; -#else dev->netdev_ops = &ipoe_netdev_ops; -#endif dev->destructor = ipoe_free_netdev; dev->type = ARPHRD_ETHER; @@ -1050,22 +887,20 @@ static void ipoe_netdev_setup(struct net_device *dev) dev->features |= NETIF_F_NETNS_LOCAL; dev->features &= ~NETIF_F_HW_VLAN_FILTER; dev->header_ops = &ipoe_hard_header_ops; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; -#endif } -static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, const __u8 *hwaddr) +static int ipoe_create(__be32 peer_addr, __be32 addr, __be32 gw, int ifindex, const __u8 *hwaddr) { struct ipoe_session *ses; struct net_device *dev, *link_dev = NULL; char name[IFNAMSIZ]; int r = -EINVAL; int h = hash_addr(peer_addr); - struct in_device *in_dev; + //struct in_device *in_dev; - if (link_ifname) { - link_dev = dev_get_by_name(&init_net, link_ifname); + if (ifindex) { + link_dev = dev_get_by_index(&init_net, ifindex); if (!link_dev) return -EINVAL; } @@ -1095,16 +930,15 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c ses->dev = dev; ses->addr = addr; ses->peer_addr = peer_addr; + ses->gw = gw; ses->link_dev = link_dev; memcpy(ses->hwaddr, hwaddr, ETH_ALEN); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) ses->rx_stats = alloc_percpu(struct ipoe_stats); ses->tx_stats = alloc_percpu(struct ipoe_stats); if (!ses->rx_stats || !ses->tx_stats) { r = -ENOMEM; goto failed_free; } -#endif if (link_dev) { dev->features = link_dev->features & ~NETIF_F_HW_VLAN_FILTER; @@ -1117,13 +951,13 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c else dev->flags &= ~IFF_NOARP; - in_dev = __in_dev_get_rtnl(dev); + /*in_dev = __in_dev_get_rtnl(dev); if (in_dev) { if (addr == 1) IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; else IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 1; - } + }*/ dev->tx_queue_len = 100; @@ -1163,11 +997,10 @@ static int ipoe_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) } #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &ipoe_nl_family, 0, IPOE_CMD_NOOP); #else - hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &ipoe_nl_family, 0, IPOE_CMD_NOOP); #endif - &ipoe_nl_family, 0, IPOE_CMD_NOOP); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto err_out; @@ -1175,9 +1008,7 @@ static int ipoe_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) genlmsg_end(msg, hdr); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) - return genlmsg_unicast(msg, info->snd_pid); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); #else return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); @@ -1194,9 +1025,9 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; void *hdr; - __be32 peer_addr = 0, addr = 0; + __be32 peer_addr = 0, addr = 0, gw = 0; + int ifindex = 0; int ret = 0; - char ifname[IFNAMSIZ]; __u8 hwaddr[ETH_ALEN]; struct ipoe_session *ses; //struct net *net = genl_info_net(info); @@ -1215,8 +1046,11 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) if (info->attrs[IPOE_ATTR_ADDR]) addr = nla_get_be32(info->attrs[IPOE_ATTR_ADDR]); - if (info->attrs[IPOE_ATTR_IFNAME]) - nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1); + if (info->attrs[IPOE_ATTR_GW_ADDR]) + gw = nla_get_be32(info->attrs[IPOE_ATTR_GW_ADDR]); + + if (info->attrs[IPOE_ATTR_IFINDEX]) + ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); if (info->attrs[IPOE_ATTR_HWADDR]) nla_memcpy(hwaddr, info->attrs[IPOE_ATTR_HWADDR], ETH_ALEN); @@ -1230,11 +1064,10 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) } #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &ipoe_nl_family, 0, IPOE_CMD_CREATE); #else - hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &ipoe_nl_family, 0, IPOE_CMD_CREATE); #endif - &ipoe_nl_family, 0, IPOE_CMD_CREATE); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto err_out; @@ -1242,7 +1075,7 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) //pr_info("ipoe: create %08x %08x %s\n", peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : "-"); - ret = ipoe_create(peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : NULL, hwaddr); + ret = ipoe_create(peer_addr, addr, gw, ifindex, hwaddr); if (ret < 0) { nlmsg_free(msg); @@ -1252,9 +1085,7 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) nla_put_u32(msg, IPOE_ATTR_IFINDEX, ret); genlmsg_end(msg, hdr); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) - return genlmsg_unicast(msg, info->snd_pid); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); #else return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); @@ -1282,20 +1113,11 @@ static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info) down(&ipoe_wlock); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) - rtnl_lock(); - dev = __dev_get_by_index(&init_net, ifindex); -#else rcu_read_lock(); dev = dev_get_by_index_rcu(&init_net, ifindex); -#endif if (!dev || dev->header_ops != &ipoe_hard_header_ops) r = 1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) - rtnl_unlock(); -#else rcu_read_unlock(); -#endif if (r) goto out_unlock; @@ -1330,7 +1152,6 @@ out_unlock: static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info) { int ret = -EINVAL, r = 0; - char ifname[IFNAMSIZ]; struct net_device *dev, *link_dev, *old_dev; struct in_device *in_dev; struct ipoe_session *ses, *ses1; @@ -1344,20 +1165,11 @@ static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info) ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) - rtnl_lock(); - dev = __dev_get_by_index(&init_net, ifindex); -#else rcu_read_lock(); dev = dev_get_by_index_rcu(&init_net, ifindex); -#endif if (!dev || dev->header_ops != &ipoe_hard_header_ops) r = 1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) - rtnl_unlock(); -#else rcu_read_unlock(); -#endif if (r) goto out_unlock; @@ -1386,13 +1198,15 @@ static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info) if (peer_addr) list_add_tail_rcu(&ses->entry, &ipoe_list[hash_addr(peer_addr)]); + else + ses->dev->flags &= ~IFF_UP; } - if (info->attrs[IPOE_ATTR_IFNAME]) { - nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1); + if (info->attrs[IPOE_ATTR_LINK_IFINDEX]) { + int ifindex = nla_get_u32(info->attrs[IPOE_ATTR_LINK_IFINDEX]); - if (*ifname) { - link_dev = dev_get_by_name(&init_net, ifname); + if (ifindex) { + link_dev = dev_get_by_index(&init_net, ifindex); if (!link_dev) goto out_unlock; @@ -1428,6 +1242,9 @@ static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info) } } + if (info->attrs[IPOE_ATTR_GW_ADDR]) + ses->gw = nla_get_u32(info->attrs[IPOE_ATTR_GW_ADDR]); + if (info->attrs[IPOE_ATTR_HWADDR]) nla_memcpy(ses->hwaddr, info->attrs[IPOE_ATTR_HWADDR], ETH_ALEN); @@ -1453,12 +1270,8 @@ static int fill_info(struct sk_buff *skb, struct ipoe_session *ses, u32 pid, u32 nla_put_u32(skb, IPOE_ATTR_ADDR, ses->addr)) goto nla_put_failure; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) genlmsg_end(skb, hdr); return 0; -#else - return genlmsg_end(skb, hdr); -#endif nla_put_failure: genlmsg_cancel(skb, hdr); @@ -1494,58 +1307,6 @@ static int ipoe_nl_cmd_dump_sessions(struct sk_buff *skb, struct netlink_callbac return skb->len; } -static int ipoe_nl_cmd_add_net(struct sk_buff *skb, struct genl_info *info) -{ - struct ipoe_network *n; - - if (!info->attrs[IPOE_ATTR_ADDR] || !info->attrs[IPOE_ATTR_MASK]) - return -EINVAL; - - n = kmalloc(sizeof(*n), GFP_KERNEL); - if (!n) - return -ENOMEM; - - n->addr = nla_get_u32(info->attrs[IPOE_ATTR_ADDR]); - n->mask = nla_get_u32(info->attrs[IPOE_ATTR_MASK]); - n->addr = ntohl(n->addr) & n->mask; - //pr_info("add net %08x/%08x\n", n->addr, n->mask); - - down(&ipoe_wlock); - list_add_tail_rcu(&n->entry, &ipoe_networks); - up(&ipoe_wlock); - - return 0; -} - -static int ipoe_nl_cmd_del_net(struct sk_buff *skb, struct genl_info *info) -{ - struct ipoe_network *n; - __be32 addr; - - if (!info->attrs[IPOE_ATTR_ADDR]) - return -EINVAL; - - addr = nla_get_u32(info->attrs[IPOE_ATTR_ADDR]); - - rcu_read_lock(); - list_for_each_entry_rcu(n, &ipoe_networks, entry) { - if (!addr || addr == n->addr) { - //pr_info("del net %08x/%08x\n", n->addr, n->mask); - list_del_rcu(&n->entry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) - kfree_rcu(n, rcu_head); -#else - call_rcu(&n->rcu_head, ipoe_kfree_rcu); -#endif - } - } - rcu_read_unlock(); - - synchronize_rcu(); - - return 0; -} - static int ipoe_nl_cmd_add_exclude(struct sk_buff *skb, struct genl_info *info) { struct ipoe_network *n; @@ -1581,11 +1342,7 @@ static void clean_excl_list(void) ht = &ipoe_excl_list[i]; list_for_each_entry_rcu(n, ht, entry) { list_del_rcu(&n->entry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) kfree_rcu(n, rcu_head); -#else - call_rcu(&n->rcu_head, ipoe_kfree_rcu); -#endif } } rcu_read_unlock(); @@ -1614,11 +1371,7 @@ static int ipoe_nl_cmd_del_exclude(struct sk_buff *skb, struct genl_info *info) list_for_each_entry_rcu(n, ht, entry) { if (n->addr == addr) { list_del_rcu(&n->entry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) kfree_rcu(n, rcu_head); -#else - call_rcu(&n->rcu_head, ipoe_kfree_rcu); -#endif } } rcu_read_unlock(); @@ -1632,48 +1385,79 @@ static int ipoe_nl_cmd_del_exclude(struct sk_buff *skb, struct genl_info *info) static int ipoe_nl_cmd_add_interface(struct sk_buff *skb, struct genl_info *info) { struct ipoe_iface *i; + struct net_device *dev; + int ret = 0; + int ifindex; if (!info->attrs[IPOE_ATTR_IFINDEX]) return -EINVAL; + ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); + + rtnl_lock(); + + dev = __dev_get_by_index(&init_net, ifindex); + + if (!dev) { + rtnl_unlock(); + return -ENODEV; + } + i = kmalloc(sizeof(*i), GFP_KERNEL); - if (!i) - return -ENOMEM; + if (!i) { + ret = -ENOMEM; + goto out; + } - i->ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); + i->ifindex = ifindex; - down(&ipoe_wlock); - list_add_tail_rcu(&i->entry, &ipoe_interfaces); - up(&ipoe_wlock); + if (info->attrs[IPOE_ATTR_MODE]) + i->mode = nla_get_u8(info->attrs[IPOE_ATTR_MODE]); + else + i->mode = 2; - return 0; + ret = netdev_rx_handler_register(dev, ipoe_recv, i); + + if (ret) + kfree(i); + else + list_add_tail(&i->entry, &ipoe_interfaces); + +out: + rtnl_unlock(); + + return ret; } static int ipoe_nl_cmd_del_interface(struct sk_buff *skb, struct genl_info *info) { struct ipoe_iface *i; int ifindex; + struct list_head *pos, *n; + struct net_device *dev; if (!info->attrs[IPOE_ATTR_IFINDEX]) return -EINVAL; ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); - rcu_read_lock(); - list_for_each_entry_rcu(i, &ipoe_interfaces, entry) { + rtnl_lock(); + list_for_each_safe(pos, n, &ipoe_interfaces) { + i = list_entry(pos, typeof(*i), entry); if (ifindex == -1 || ifindex == i->ifindex) { - //pr_info("del net %08x/%08x\n", n->addr, n->mask); - list_del_rcu(&i->entry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + dev = __dev_get_by_index(&init_net, i->ifindex); + + netdev_rx_handler_unregister(dev); + + list_del(&i->entry); + kfree_rcu(i, rcu_head); -#else - call_rcu(&i->rcu_head, ipoe_kfree_rcu); -#endif + + if (ifindex == -1) + break; } } - rcu_read_unlock(); - - synchronize_rcu(); + rtnl_unlock(); return 0; } @@ -1681,11 +1465,13 @@ static int ipoe_nl_cmd_del_interface(struct sk_buff *skb, struct genl_info *info static struct nla_policy ipoe_nl_policy[IPOE_ATTR_MAX + 1] = { [IPOE_ATTR_NONE] = { .type = NLA_UNSPEC, }, [IPOE_ATTR_ADDR] = { .type = NLA_U32, }, - [IPOE_ATTR_PEER_ADDR] = { .type = NLA_U32, }, - [IPOE_ATTR_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, - [IPOE_ATTR_HWADDR] = { .type = NLA_U64 }, - [IPOE_ATTR_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, + [IPOE_ATTR_PEER_ADDR] = { .type = NLA_U32, }, [IPOE_ATTR_MASK] = { .type = NLA_U32, }, + [IPOE_ATTR_MODE] = { .type = NLA_U8, }, + [IPOE_ATTR_GW_ADDR] = { .type = NLA_U32, }, + [IPOE_ATTR_HWADDR] = { .len = ETH_ALEN, }, + [IPOE_ATTR_IFINDEX] = { .type = NLA_U32, }, + [IPOE_ATTR_LINK_IFINDEX]= { .type = NLA_U32, }, }; static struct genl_ops ipoe_nl_ops[] = { @@ -1719,18 +1505,6 @@ static struct genl_ops ipoe_nl_ops[] = { .policy = ipoe_nl_policy, }, { - .cmd = IPOE_CMD_ADD_NET, - .doit = ipoe_nl_cmd_add_net, - .policy = ipoe_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = IPOE_CMD_DEL_NET, - .doit = ipoe_nl_cmd_del_net, - .policy = ipoe_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { .cmd = IPOE_CMD_ADD_IF, .doit = ipoe_nl_cmd_add_interface, .policy = ipoe_nl_policy, @@ -1774,44 +1548,10 @@ static struct genl_multicast_group ipoe_nl_mcgs[] = { }; #endif -static struct nf_hook_ops ipt_ops[] __read_mostly = { - { - .hook = ipt_out_hook, - .pf = PF_INET, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP_PRI_LAST, -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) - .owner = THIS_MODULE, -#endif - }, - { - .hook = ipt_out_hook, - .pf = PF_INET, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP_PRI_LAST, -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) - .owner = THIS_MODULE, -#endif - }, - { - .hook = ipt_in_hook, - .pf = PF_INET, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP_PRI_FIRST, -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) - .owner = THIS_MODULE, -#endif - }, -}; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) static const struct net_device_ops ipoe_netdev_ops = { .ndo_start_xmit = ipoe_xmit, -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) .ndo_get_stats64 = ipoe_stats64, -#endif }; -#endif /*static struct pernet_operations ipoe_net_ops = { .init = ipoe_init_net, @@ -1829,6 +1569,7 @@ static int __init ipoe_init(void) /*err = register_pernet_device(&ipoe_net_ops); if (err < 0) return err;*/ + for (i = 0; i <= HASH_BITS; i++) { INIT_LIST_HEAD(&ipoe_list[i]); INIT_LIST_HEAD(&ipoe_list1_u[i]); @@ -1838,24 +1579,6 @@ static int __init ipoe_init(void) skb_queue_head_init(&ipoe_queue); INIT_WORK(&ipoe_queue_work, ipoe_process_queue); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) - err = genl_register_family(&ipoe_nl_family); - if (err < 0) { - printk(KERN_INFO "ipoe: can't register netlink interface\n"); - goto out; - } - - for (i = 0; i < ARRAY_SIZE(ipoe_nl_ops); i++) { - err = genl_register_ops(&ipoe_nl_family, &ipoe_nl_ops[i]); - if (err) - break; - } - - if (err < 0) { - printk(KERN_INFO "ipoe: can't register netlink interface\n"); - goto out_unreg; - } -#else #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) err = genl_register_family_with_ops(&ipoe_nl_family, ipoe_nl_ops, ARRAY_SIZE(ipoe_nl_ops)); #else @@ -1863,54 +1586,58 @@ static int __init ipoe_init(void) #endif if (err < 0) { printk(KERN_INFO "ipoe: can't register netlink interface\n"); - goto out; + return err; } -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) err = genl_register_mc_group(&ipoe_nl_family, &ipoe_nl_mcg); if (err < 0) { printk(KERN_INFO "ipoe: can't register netlink multicast group\n"); - goto out_unreg; + genl_unregister_family(&ipoe_nl_family); + return err; } #endif - err = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); - if (err < 0) { - printk(KERN_INFO "ipoe: can't register nf hooks\n"); - goto out_unreg; - } - return 0; - -out_unreg: - genl_unregister_family(&ipoe_nl_family); -out: - return err; } static void __exit ipoe_fini(void) { - struct ipoe_network *n; struct ipoe_entry_u *e; struct ipoe_session *ses; + struct net_device *dev; int i; - nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); - #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) genl_unregister_mc_group(&ipoe_nl_family, &ipoe_nl_mcg); #endif genl_unregister_family(&ipoe_nl_family); + down(&ipoe_wlock); + up(&ipoe_wlock); + + rtnl_lock(); + while (!list_empty(&ipoe_interfaces)) { + struct ipoe_iface *i = list_entry(ipoe_interfaces.next, typeof(*i), entry); + + dev = __dev_get_by_index(&init_net, i->ifindex); + + if (dev && rcu_dereference(dev->rx_handler) == ipoe_recv) + netdev_rx_handler_unregister(dev); + + list_del(&i->entry); + + kfree_rcu(i, rcu_head); + } + rtnl_unlock(); + + synchronize_net(); + flush_work(&ipoe_queue_work); skb_queue_purge(&ipoe_queue); del_timer(&ipoe_timer_u); - down(&ipoe_wlock); - up(&ipoe_wlock); - for (i = 0; i <= HASH_BITS; i++) rcu_assign_pointer(ipoe_list[i].next, &ipoe_list[i]); @@ -1926,12 +1653,6 @@ static void __exit ipoe_fini(void) unregister_netdev(ses->dev); } - while (!list_empty(&ipoe_networks)) { - n = list_entry(ipoe_networks.next, typeof(*n), entry); - list_del(&n->entry); - kfree(n); - } - while (!list_empty(&ipoe_list2_u)) { e = list_entry(ipoe_list2_u.next, typeof(*e), entry2); list_del(&e->entry2); diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h index e0cfc4e5..c37cb73e 100644 --- a/drivers/ipoe/ipoe.h +++ b/drivers/ipoe/ipoe.h @@ -9,8 +9,6 @@ enum { IPOE_CMD_DELETE, IPOE_CMD_MODIFY, IPOE_CMD_GET, - IPOE_CMD_ADD_NET, - IPOE_CMD_DEL_NET, IPOE_CMD_ADD_IF, IPOE_CMD_DEL_IF, IPOE_REP_PKT, @@ -25,12 +23,14 @@ enum { IPOE_ATTR_NONE, /* no data */ IPOE_ATTR_ADDR, /* u32 */ IPOE_ATTR_PEER_ADDR, /* u32 */ - IPOE_ATTR_IFNAME, /* u32 */ + IPOE_ATTR_GW_ADDR, /* u32 */ IPOE_ATTR_HWADDR, /* u32 */ IPOE_ATTR_MASK, /* u32 */ IPOE_ATTR_IFINDEX, /* u32 */ + IPOE_ATTR_LINK_IFINDEX, /* u32 */ IPOE_ATTR_ETH_HDR, /* u32 */ IPOE_ATTR_IP_HDR, /* u32 */ + IPOE_ATTR_MODE, /* u8 */ __IPOE_ATTR_MAX, }; @@ -41,7 +41,7 @@ enum { */ #define IPOE_GENL_NAME "IPoE" #define IPOE_GENL_MCG_PKT "Packet" -#define IPOE_GENL_VERSION 0x1 +#define IPOE_GENL_VERSION 0x02 #endif |