diff options
-rw-r--r-- | accel-pppd/CMakeLists.txt | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/CMakeLists.txt | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/dhcpv4.c | 2 | ||||
l--------- | accel-pppd/ctrl/ipoe/if_ipoe.h | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 242 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 11 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe_netlink.c | 351 | ||||
l--------- | accel-pppd/include/genl.h | 1 | ||||
-rw-r--r-- | accel-pppd/libnetlink/genl.c | 108 | ||||
-rw-r--r-- | accel-pppd/libnetlink/genl.h | 6 | ||||
-rw-r--r-- | accel-pppd/libnetlink/libnetlink.c | 2 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 271 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.h | 7 |
13 files changed, 902 insertions, 102 deletions
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index 787dbd8c..c50dc585 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -69,6 +69,7 @@ ADD_EXECUTABLE(accel-pppd libnetlink/libnetlink.c libnetlink/iplink.c + libnetlink/genl.c pwdb.c ipdb.c diff --git a/accel-pppd/ctrl/ipoe/CMakeLists.txt b/accel-pppd/ctrl/ipoe/CMakeLists.txt index e2b71cbc..297d81b1 100644 --- a/accel-pppd/ctrl/ipoe/CMakeLists.txt +++ b/accel-pppd/ctrl/ipoe/CMakeLists.txt @@ -4,6 +4,7 @@ SET(sources ipoe.c dhcpv4.c dhcpv4_options.c + ipoe_netlink.c ) IF (LUA) diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c index 12923eee..78911811 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4.c +++ b/accel-pppd/ctrl/ipoe/dhcpv4.c @@ -109,7 +109,7 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna } fcntl(raw_sock, F_SETFL, O_NONBLOCK); - fcntl(raw_sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); + fcntl(raw_sock, F_SETFD, fcntl(raw_sock, F_GETFD) | FD_CLOEXEC); fcntl(sock, F_SETFL, O_NONBLOCK); fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); diff --git a/accel-pppd/ctrl/ipoe/if_ipoe.h b/accel-pppd/ctrl/ipoe/if_ipoe.h new file mode 120000 index 00000000..1f0e053e --- /dev/null +++ b/accel-pppd/ctrl/ipoe/if_ipoe.h @@ -0,0 +1 @@ +../../../drivers/ipoe/ipoe.h
\ No newline at end of file diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 1c54b7c9..eedd8cf9 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -8,6 +8,8 @@ #include <time.h> #include <arpa/inet.h> #include <netinet/in.h> +#include <net/ethernet.h> +#include <netinet/ip.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <linux/if.h> @@ -49,6 +51,7 @@ 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; @@ -153,14 +156,37 @@ static void ipoe_session_start(struct ipoe_session *ses) { int r; char *passwd; + struct ifreq ifr; if (ses->serv->opt_single) strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN); + else { + ses->ifindex = ipoe_nl_create(0, 0, ses->serv->ifname, ses->hwaddr); + if (ses->ifindex == -1) { + log_ppp_error("ipoe: failed to create interface\n"); + ipoe_session_finished(&ses->ses); + return; + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = ses->ifindex; + if (ioctl(sock_fd, SIOCGIFNAME, &ifr, sizeof(ifr))) { + log_ppp_error("ipoe: failed to get interface name\n"); + ses->ifindex = -1; + ipoe_session_finished(&ses->ses); + return; + } + + strncpy(ses->ses.ifname, ifr.ifr_name, AP_IFNAME_LEN); + } - ipoe_session_set_username(ses); if (!ses->ses.username) { - ipoe_session_finished(&ses->ses); - return; + ipoe_session_set_username(ses); + + if (!ses->ses.username) { + ipoe_session_finished(&ses->ses); + return; + } } triton_event_fire(EV_CTRL_STARTING, &ses->ses); @@ -186,44 +212,46 @@ static void ipoe_session_start(struct ipoe_session *ses) return; } - if (ses->dhcpv4_request) { - ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses); - if (!ses->ses.ipv4) { - log_ppp_warn("no free IPv4 address\n"); - ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0); - return; - } + ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses); + if (!ses->ses.ipv4) { + log_ppp_warn("no free IPv4 address\n"); + ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0); + return; + } - if (conf_gw_address) - ses->ses.ipv4->addr = conf_gw_address; - - if (conf_netmask) - ses->ses.ipv4->mask = conf_netmask; - else if (!ses->ses.ipv4->mask) - ses->ses.ipv4->mask = 24; + if (conf_gw_address) + ses->ses.ipv4->addr = conf_gw_address; + + if (conf_netmask) + ses->ses.ipv4->mask = conf_netmask; + else if (!ses->ses.ipv4->mask) + ses->ses.ipv4->mask = 24; + if (ses->dhcpv4_request) { dhcpv4_send_reply(DHCPOFFER, ses->serv->dhcpv4, ses->dhcpv4_request, &ses->ses, conf_lease_time); dhcpv4_packet_free(ses->dhcpv4_request); ses->dhcpv4_request = NULL; + + ses->timer.expire = ipoe_session_timeout; + ses->timer.expire_tv.tv_sec = conf_offer_timeout; + triton_timer_add(&ses->ctx, &ses->timer, 0); } - - ses->timer.expire = ipoe_session_timeout; - ses->timer.expire_tv.tv_sec = conf_offer_timeout; - triton_timer_add(&ses->ctx, &ses->timer, 0); } static void ipoe_session_activate(struct ipoe_session *ses) { ap_session_activate(&ses->ses); - if (ses->ses.state == AP_STATE_ACTIVE) - dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, &ses->ses, conf_lease_time); - else - dhcpv4_send_nak(ses->serv->dhcpv4, ses->dhcpv4_request); + if (ses->dhcpv4_request) { + if (ses->ses.state == AP_STATE_ACTIVE) + dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, &ses->ses, conf_lease_time); + else + dhcpv4_send_nak(ses->serv->dhcpv4, ses->dhcpv4_request); - dhcpv4_packet_free(ses->dhcpv4_request); - ses->dhcpv4_request = NULL; + dhcpv4_packet_free(ses->dhcpv4_request); + ses->dhcpv4_request = NULL; + } } static void ipoe_session_keepalive(struct ipoe_session *ses) @@ -262,10 +290,19 @@ static void ipoe_session_free(struct ipoe_session *ses) if (ses->dhcpv4_request) dhcpv4_packet_free(ses->dhcpv4_request); + if (ses->ctrl.called_station_id) + _free(ses->ctrl.called_station_id); + + if (ses->ctrl.calling_station_id) + _free(ses->ctrl.calling_station_id); + triton_context_unregister(&ses->ctx); if (ses->data) _free(ses->data); + + if (ses->ifindex != -1) + ipoe_nl_delete(ses->ifindex); mempool_free(ses); } @@ -299,7 +336,7 @@ static void ipoe_session_close(struct triton_context_t *ctx) ipoe_session_finished(&ses->ses); } -static struct ipoe_session *ipoe_session_create(struct ipoe_serv *serv, struct dhcpv4_packet *pack) +static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, struct dhcpv4_packet *pack) { struct ipoe_session *ses; int dlen = 0; @@ -316,6 +353,7 @@ static struct ipoe_session *ipoe_session_create(struct ipoe_serv *serv, struct d ap_session_init(&ses->ses); ses->serv = serv; + ses->ifindex = -1; ses->dhcpv4_request = pack; ses->xid = pack->hdr->xid; @@ -372,7 +410,7 @@ static struct ipoe_session *ipoe_session_create(struct ipoe_serv *serv, struct d ses->ctrl.name = "ipoe"; ses->ctrl.calling_station_id = _malloc(19); - ses->ctrl.called_station_id = serv->ifname; + ses->ctrl.called_station_id = _strdup(serv->ifname); ptr = ses->hwaddr; sprintf(ses->ctrl.calling_station_id, "%02x:%02x:%02x:%02x:%02x:%02x", @@ -394,7 +432,7 @@ static struct ipoe_session *ipoe_session_create(struct ipoe_serv *serv, struct d return ses; } -static void ipoe_dhcpv4_recv(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *pack) +static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *pack) { struct ipoe_serv *serv = container_of(dhcpv4->ctx, typeof(*serv), ctx); struct ipoe_session *ses; @@ -404,7 +442,7 @@ static void ipoe_dhcpv4_recv(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p if (pack->msg_type == DHCPDISCOVER) { ses = ipoe_session_lookup(serv, pack); if (!ses) { - ses = ipoe_session_create(serv, pack); + ses = ipoe_session_create_dhcpv4(serv, pack); if (conf_verbose && ses) { log_switch(dhcpv4->ctx, &ses->ses); @@ -487,6 +525,80 @@ static void ipoe_dhcpv4_recv(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p pthread_mutex_unlock(&serv->lock); } +static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struct ethhdr *eth, struct iphdr *iph) +{ + struct ipoe_session *ses; + + ses = mempool_alloc(ses_pool); + if (!ses) { + log_emerg("out of memery\n"); + return NULL; + } + + memset(ses, 0, sizeof(*ses)); + + ap_session_init(&ses->ses); + + ses->serv = serv; + ses->ifindex = -1; + + memcpy(ses->hwaddr, eth->h_source, 6); + + ses->ctx.before_switch = log_switch; + ses->ctx.close = ipoe_session_close; + ses->ctrl.ctx = &ses->ctx; + ses->ctrl.started = ipoe_session_started; + ses->ctrl.finished = ipoe_session_finished; + ses->ctrl.terminate = ipoe_session_terminate; + ses->ctrl.type = CTRL_TYPE_IPOE; + ses->ctrl.name = "ipoe"; + + ses->ctrl.calling_station_id = _malloc(17); + ses->ctrl.called_station_id = _malloc(17); + + u_inet_ntoa(iph->saddr, ses->ctrl.calling_station_id); + u_inet_ntoa(iph->daddr, ses->ctrl.called_station_id); + + ses->ses.username = _strdup(ses->ctrl.calling_station_id); + + ses->ses.ctrl = &ses->ctrl; + ses->ses.chan_name = ses->ctrl.calling_station_id; + + triton_context_register(&ses->ctx, &ses->ses); + + triton_context_wakeup(&ses->ctx); + + //pthread_mutex_lock(&serv->lock); + list_add_tail(&ses->entry, &serv->sessions); + //pthread_mutex_unlock(&serv->lock); + + triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_start, ses); + + return ses; +} + +void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph) +{ + struct ipoe_serv *serv; + struct ipoe_session *ses; + + list_for_each_entry(serv, &serv_list, entry) { + if (serv->ifindex != ifindex) + continue; + + pthread_mutex_lock(&serv->lock); + list_for_each_entry(ses, &serv->sessions, entry) { + if (memcmp(ses->hwaddr, eth->h_source, 6) == 0) { + pthread_mutex_unlock(&serv->lock); + return; + } + } + pthread_mutex_unlock(&serv->lock); + + ipoe_session_create_up(serv, eth, iph); + } +} + static void ipoe_serv_close(struct triton_context_t *ctx) { struct ipoe_serv *serv = container_of(ctx, typeof(*serv), ctx); @@ -546,9 +658,15 @@ static void add_interface(const char *ifname, int ifindex, const char *opt) if (ptr[7] && ptr[7] != ',') goto out_err_parse; opt_single = 1; - } else - opt_single = 0; - + } 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; + } list_for_each_entry(serv, &serv_list, entry) { if (strcmp(ifname, serv->ifname) == 0) { @@ -567,6 +685,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt) serv->ifindex = ifindex; serv->opt_single = opt_single; serv->opt_dhcpv4 = conf_dhcpv4; + serv->active = 1; INIT_LIST_HEAD(&serv->sessions); pthread_mutex_init(&serv->lock, NULL); @@ -575,11 +694,13 @@ static void add_interface(const char *ifname, int ifindex, const char *opt) if (serv->opt_dhcpv4) { serv->dhcpv4 = dhcpv4_create(&serv->ctx, serv->ifname); if (serv->dhcpv4) - serv->dhcpv4->recv = ipoe_dhcpv4_recv; + serv->dhcpv4->recv = ipoe_recv_dhcpv4; } triton_context_wakeup(&serv->ctx); + list_add_tail(&serv->entry, &serv_list); + return; out_err_parse: @@ -678,6 +799,56 @@ static void load_interfaces(struct conf_sect_t *sect) } } +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; + } + + mask = (1 << mask) - 1; + + ipoe_nl_add_net(addr & mask, 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_config(void) { const char *opt; @@ -687,6 +858,7 @@ static void load_config(void) return; load_interfaces(s); + load_local_nets(s); opt = conf_get_opt("ipoe", "username"); if (opt) { diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index adbc5cff..30760906 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -44,11 +44,22 @@ struct ipoe_session uint32_t giaddr; uint8_t *data; struct dhcpv4_packet *dhcpv4_request; + int ifindex; }; #ifdef USE_LUA int ipoe_lua_set_username(struct ipoe_session *, const char *func); #endif +struct iphdr; +struct ethhdr; + +void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph); + +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); + #endif diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c new file mode 100644 index 00000000..57da0def --- /dev/null +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -0,0 +1,351 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/ethernet.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <linux/if.h> +#include <linux/genetlink.h> + +#include "triton.h" +#include "log.h" +#include "genl.h" +#include "libnetlink.h" + +#include "ipoe.h" +#include "if_ipoe.h" + +#define PKT_ATTR_MAX 256 + +static struct rtnl_handle rth; +static struct triton_md_handler_t up_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; + + 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_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct rtattr *tb[IPOE_ATTR_MAX + 1]; + struct rtattr *attrs; + int len; + int ret = -1; + 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_DELETE; + + 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"); + + if (nlh->nlmsg_type != ipoe_genl_id) { + log_ppp_error("ipoe: not a IPoE message %d\n", nlh->nlmsg_type); + goto out; + } + + ghdr = NLMSG_DATA(nlh); + + if (ghdr->cmd != IPOE_CMD_CREATE) { + log_ppp_error("ipoe: unknown IPoE command %d\n", ghdr->cmd); + goto out; + } + + len = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + + if (len < 0) { + log_ppp_error("ipoe: wrong IPoE message len %d\n", len); + goto out; + } + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + parse_rtattr(tb, IPOE_ATTR_MAX, attrs, len); + + if (!tb[IPOE_ATTR_IFINDEX]) { + log_ppp_error("ipoe: missing IPOE_ATTR_IFINDEX attribute\n"); + goto out; + } + + ret = *(uint32_t *)(RTA_DATA(tb[IPOE_ATTR_IFINDEX])); + +out: + rtnl_close(&rth); + + return ret; +} + +void ipoe_nl_delete(int ifindex) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + + if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { + log_ppp_error("ipoe: cannot open generic netlink socket\n"); + 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_DELETE; + + addattr32(nlh, 128, IPOE_ATTR_IFINDEX, ifindex); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) + log_ppp_error("ipoe: nl_delete: error talking to kernel\n"); + + rtnl_close(&rth); +} + +static void ipoe_up_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h) +{ + struct rtattr *tb[PKT_ATTR_MAX + 1]; + struct rtattr *tb2[IPOE_ATTR_MAX + 1]; + struct genlmsghdr *ghdr = NLMSG_DATA(h); + int len = h->nlmsg_len; + struct rtattr *attrs; + int i; + int ifindex; + struct iphdr *iph; + struct ethhdr *eth; + + if (ghdr->cmd != IPOE_REP_PKT) + return; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + + if (len < 0) { + log_warn("ipoe: wrong controller message length %d\n", len); + return; + } + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + parse_rtattr(tb, PKT_ATTR_MAX, attrs, len); + + for (i = 1; i < PKT_ATTR_MAX; i++) { + if (!tb[i]) + break; + + parse_rtattr_nested(tb2, IPOE_ATTR_MAX, tb[i]); + + if (!tb2[IPOE_ATTR_ETH_HDR] || !tb2[IPOE_ATTR_IP_HDR] || !tb2[IPOE_ATTR_IFINDEX]) + continue; + + ifindex = *(uint32_t *)(RTA_DATA(tb2[IPOE_ATTR_IFINDEX])); + iph = (struct iphdr *)(RTA_DATA(tb2[IPOE_ATTR_IP_HDR])); + eth = (struct ethhdr *)(RTA_DATA(tb2[IPOE_ATTR_ETH_HDR])); + + ipoe_recv_up(ifindex, eth, iph); + } +} + +static int ipoe_up_read(struct triton_md_handler_t *h) +{ + int status; + struct nlmsghdr *hdr; + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[8192]; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + iov.iov_base = buf; + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(h->fd, &msg, 0); + + if (status < 0) { + if (errno == EAGAIN) + break; + log_error("ipoe: netlink error: %s\n", strerror(errno)); + if (errno == ENOBUFS) + continue; + return 0; + } + if (status == 0) { + log_error("ipoe: EOF on netlink\n"); + return 0; + } + if (msg.msg_namelen != sizeof(nladdr)) { + log_error("ipoe: netlink sender address length == %d\n", msg.msg_namelen); + return 0; + } + for (hdr = (struct nlmsghdr*)buf; status >= sizeof(*hdr); ) { + int len = hdr->nlmsg_len; + int l = len - sizeof(*h); + + if (l<0 || len>status) { + if (msg.msg_flags & MSG_TRUNC) { + log_warn("ipoe: truncated netlink message\n"); + continue; + } + log_error("ipoe: malformed netlink message\n"); + continue; + } + + ipoe_up_handler(&nladdr, hdr); + + status -= NLMSG_ALIGN(len); + hdr = (struct nlmsghdr*)((char*)hdr + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + log_warn("ipoe: netlink message truncated\n"); + continue; + } + if (status) { + log_error("ipoe: netlink remnant of size %d\n", status); + return 0; + } + } + + return 0; +} + +static void ipoe_up_close(struct triton_context_t *ctx) +{ + rtnl_close(&rth); + triton_md_unregister_handler(&up_hnd); + triton_context_unregister(ctx); +} + +static struct triton_context_t up_ctx = { + .close = ipoe_up_close, +}; + +static struct triton_md_handler_t up_hnd = { + .read = ipoe_up_read, +}; + +static void init(void) +{ + + int mcg_id = genl_resolve_mcg(IPOE_GENL_NAME, IPOE_GENL_MCG_PKT, &ipoe_genl_id); + if (mcg_id == -1) { + log_warn("ipoe: unclassified packet handling is disabled\n"); + rth.fd = -1; + return; + } + + if (rtnl_open_byproto(&rth, 1 << (mcg_id - 1), NETLINK_GENERIC)) { + log_error("ipoe: cannot open generic netlink socket\n"); + rth.fd = -1; + return; + } + + fcntl(rth.fd, F_SETFL, O_NONBLOCK); + fcntl(rth.fd, F_SETFD, fcntl(rth.fd, F_GETFD) | FD_CLOEXEC); + + triton_context_register(&up_ctx, NULL); + up_hnd.fd = rth.fd; + triton_md_register_handler(&up_ctx, &up_hnd); + triton_md_enable_handler(&up_hnd, MD_MODE_READ); + triton_context_wakeup(&up_ctx); +} + +DEFINE_INIT(19, init); diff --git a/accel-pppd/include/genl.h b/accel-pppd/include/genl.h new file mode 120000 index 00000000..d790809f --- /dev/null +++ b/accel-pppd/include/genl.h @@ -0,0 +1 @@ +../libnetlink/genl.h
\ No newline at end of file diff --git a/accel-pppd/libnetlink/genl.c b/accel-pppd/libnetlink/genl.c new file mode 100644 index 00000000..7d745566 --- /dev/null +++ b/accel-pppd/libnetlink/genl.c @@ -0,0 +1,108 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <fcntl.h> +#include <net/if_arp.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <sys/uio.h> +#include <linux/genetlink.h> + +#include "triton.h" +#include "log.h" + +#include "libnetlink.h" + +#define GENL_MAX_FAM_GRPS 128 + +int __export genl_resolve_mcg(const char *family, const char *name, int *fam_id) +{ + struct rtnl_handle rth; + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct rtattr *tb[CTRL_ATTR_MAX + 1]; + struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1]; + struct rtattr *tb3[CTRL_ATTR_MCAST_GRP_MAX + 1]; + struct rtattr *attrs; + int i, len, ret = -1; + struct { + struct nlmsghdr n; + char buf[4096]; + } req; + + if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { + log_error("genl: cannot open rtnetlink\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 = GENL_ID_CTRL; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = CTRL_CMD_GETFAMILY; + + addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { + log_error("genl: error talking to kernel\n"); + goto out; + } + + if (nlh->nlmsg_type != GENL_ID_CTRL) { + log_error("genl: not a controller message %d\n", nlh->nlmsg_type); + goto out; + } + + ghdr = NLMSG_DATA(nlh); + + if (ghdr->cmd != CTRL_CMD_NEWFAMILY) { + log_error("genl: unknown controller command %d\n", ghdr->cmd); + goto out; + } + + len = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + + if (len < 0) { + log_error("genl: wrong controller message len %d\n", len); + goto out; + } + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); + + if (!tb[CTRL_ATTR_FAMILY_ID]) { + log_error("genl: missing CTRL_FAMILY_ID attribute\n"); + goto out; + } + + if (!tb[CTRL_ATTR_MCAST_GROUPS]) + goto out; + + if (fam_id) + *fam_id = *(uint32_t *)(RTA_DATA(tb[CTRL_ATTR_FAMILY_ID])); + + parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS, tb[CTRL_ATTR_MCAST_GROUPS]); + + for (i = 1; i < GENL_MAX_FAM_GRPS; i++) { + if (tb2[i]) { + parse_rtattr_nested(tb3, CTRL_ATTR_MCAST_GRP_MAX, tb2[i]); + if (!tb3[CTRL_ATTR_MCAST_GRP_ID] || !tb3[CTRL_ATTR_MCAST_GRP_NAME]) + continue; + if (strcmp(RTA_DATA(tb3[CTRL_ATTR_MCAST_GRP_NAME]), name)) + continue; + ret = *(uint32_t *)(RTA_DATA(tb3[CTRL_ATTR_MCAST_GRP_ID])); + break; + } + } + +out: + + rtnl_close(&rth); + return ret; +} diff --git a/accel-pppd/libnetlink/genl.h b/accel-pppd/libnetlink/genl.h new file mode 100644 index 00000000..5239d869 --- /dev/null +++ b/accel-pppd/libnetlink/genl.h @@ -0,0 +1,6 @@ +#ifndef __GENL_H +#define __GENL_H + +int genl_resolve_mcg(const char *family, const char *name, int *fam_id); + +#endif diff --git a/accel-pppd/libnetlink/libnetlink.c b/accel-pppd/libnetlink/libnetlink.c index 55a1a67a..808e4339 100644 --- a/accel-pppd/libnetlink/libnetlink.c +++ b/accel-pppd/libnetlink/libnetlink.c @@ -652,7 +652,7 @@ int __export rta_addattr_l(struct rtattr *rta, int maxlen, int type, return 0; } -int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +int __export parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); while (RTA_OK(rta, len)) { diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index fe796c5c..1776a449 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -57,6 +57,7 @@ struct ipoe_stats struct ipoe_session { struct list_head entry; + struct list_head entry2; __be32 addr; __be32 peer_addr; @@ -94,6 +95,7 @@ struct ipoe_entry_u static struct list_head ipoe_list[HASH_BITS + 1]; static struct list_head ipoe_list1_u[HASH_BITS + 1]; +static LIST_HEAD(ipoe_list2); static LIST_HEAD(ipoe_list2_u); static DEFINE_SEMAPHORE(ipoe_wlock); static LIST_HEAD(ipoe_networks); @@ -338,6 +340,9 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) __be32 tip;*/ int noff; + if (!ses->peer_addr) + goto drop; + noff = skb_network_offset(skb); if (skb->protocol == htons(ETH_P_IP)) { @@ -447,6 +452,8 @@ static int ipoe_rcv_arp(struct sk_buff *skb, struct net_device *dev, struct pack memcpy(&sip, arp_ptr + ETH_ALEN, 4); + if (!sip) + goto drop; //pr_info("ipoe: recv arp %08x\n", sip); ses = ipoe_lookup(sip); @@ -454,9 +461,6 @@ static int ipoe_rcv_arp(struct sk_buff *skb, struct net_device *dev, struct pack if (!ses) goto drop; - if (!ses->dev) - goto drop_unlock; - stats = &ses->dev->stats; if (ses->addr || skb->dev == ses->dev) { @@ -518,6 +522,9 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t iph = ip_hdr(skb); + if (!iph->saddr) + goto drop; + //pr_info("ipoe: recv %08x %08x\n", iph->saddr, iph->daddr); if (!ipoe_check_network(iph->saddr)) goto drop; @@ -531,9 +538,6 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t //pr_info("ipoe: recv cb=%x\n", *(__u16 *)cb_ptr); - if (ses->dev) - goto drop_unlock; - stats = &ses->dev->stats; if (skb->dev == ses->dev) { @@ -646,6 +650,7 @@ static void ipoe_process_queue(struct work_struct *w) struct sk_buff *report_skb = NULL; void *header = NULL; struct nlattr *ns; + int id = 1; do { while ((skb = skb_dequeue(&ipoe_queue))) { @@ -680,9 +685,12 @@ static void ipoe_process_queue(struct work_struct *w) } if (report_skb) { - ns = nla_nest_start(report_skb, IPOE_ATTR_PKT); + ns = nla_nest_start(report_skb, id++); if (!ns) goto nl_err; + + if (nla_put_u32(report_skb, IPOE_ATTR_IFINDEX, skb->dev ? skb->dev->ifindex : skb->skb_iif)) + goto nl_err; if (nla_put(report_skb, IPOE_ATTR_ETH_HDR, sizeof(*eth), eth)) goto nl_err; @@ -866,14 +874,8 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c struct ipoe_session *ses; struct net_device *dev, *link_dev = NULL; char name[IFNAMSIZ]; - int r = 0; - int h; - -#ifdef __LITTLE_ENDIAN - h = ((peer_addr >> 24) ^ (peer_addr >> 16)) & HASH_BITS; -#else - h = (peer_addr ^ (peer_addr >> 8)) & HASH_BITS; -#endif + int r = -EINVAL; + int h = hash_addr(peer_addr); if (link_ifname) { link_dev = dev_get_by_name(&init_net, link_ifname); @@ -884,8 +886,10 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c sprintf(name, "ipoe%%d"); dev = alloc_netdev(sizeof(*ses), name, ipoe_netdev_setup); - if (dev == NULL) + if (dev == NULL) { + r = -ENOMEM; goto failed; + } dev_net_set(dev, &init_net); @@ -929,7 +933,10 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c goto failed_free; down(&ipoe_wlock); - list_add_tail_rcu(&ses->entry, &ipoe_list[h]); + if (peer_addr) + list_add_tail_rcu(&ses->entry, &ipoe_list[h]); + list_add_tail(&ses->entry2, &ipoe_list2); + r = dev->ifindex; up(&ipoe_wlock); return r; @@ -942,35 +949,6 @@ failed: return r; } -static int ipoe_delete(__be32 addr) -{ - struct ipoe_session *ses; - - down(&ipoe_wlock); - - ses = ipoe_lookup(addr); - if (!ses) { - up(&ipoe_wlock); - return -EINVAL; - } - - list_del_rcu(&ses->entry); - - up(&ipoe_wlock); - - atomic_dec(&ses->refs); - - while (atomic_read(&ses->refs)) - schedule_timeout_uninterruptible(1); - - if (ses->link_dev) - dev_put(ses->link_dev); - - unregister_netdev(ses->dev); - - return 0; -} - static int ipoe_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; @@ -1007,29 +985,61 @@ out: static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) { - __be32 peer_addr, addr = 0; + struct sk_buff *msg; + void *hdr; + __be32 peer_addr = 0, addr = 0; int ret = 0; char ifname[IFNAMSIZ]; __u8 hwaddr[ETH_ALEN]; //struct net *net = genl_info_net(info); - if (!info->attrs[IPOE_ATTR_PEER_ADDR] || !info->attrs[IPOE_ATTR_IFNAME]) { - ret = -EINVAL; + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; goto out; } - peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]); + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &ipoe_nl_family, 0, IPOE_CMD_CREATE); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto err_out; + } + + if (info->attrs[IPOE_ATTR_PEER_ADDR]) + peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]); + if (info->attrs[IPOE_ATTR_ADDR]) addr = nla_get_be32(info->attrs[IPOE_ATTR_ADDR]); - nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1); + + if (info->attrs[IPOE_ATTR_IFNAME]) + nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1); + if (info->attrs[IPOE_ATTR_HWADDR]) nla_memcpy(hwaddr, info->attrs[IPOE_ATTR_HWADDR], ETH_ALEN); else memset(hwaddr, 0, sizeof(hwaddr)); - pr_info("ipoe: create %08x %08x %s\n", peer_addr, addr, ifname); + pr_info("ipoe: create %08x %08x %s\n", peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : "-"); - ret = ipoe_create(peer_addr, addr, ifname, hwaddr); + ret = ipoe_create(peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : NULL, hwaddr); + + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + nla_put_u32(msg, IPOE_ATTR_IFINDEX, ret); + + genlmsg_end(msg, hdr); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + return genlmsg_unicast(msg, info->snd_pid); +#else + return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); +#endif + +err_out: + nlmsg_free(msg); out: return ret; @@ -1037,18 +1047,131 @@ out: static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info) { - __be32 addr; - //struct net *net = genl_info_net(info); - + struct net_device *dev; + int ifindex; + int r = 0; + int ret = -EINVAL; - if (!info->attrs[IPOE_ATTR_PEER_ADDR]) + if (!info->attrs[IPOE_ATTR_IFINDEX]) return -EINVAL; - addr = nla_get_u32(info->attrs[IPOE_ATTR_PEER_ADDR]); + ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); + + down(&ipoe_wlock); + + rcu_read_lock(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + dev = dev_get_by_index_rcu(ifindex); +#else + dev = dev_get_by_index_rcu(&init_net, ifindex); +#endif + if (!dev || dev->header_ops != &ipoe_hard_header_ops) + r = 1; + rcu_read_unlock(); + + if (r) + goto out_unlock; + + ses = netdev_priv(dev); + + pr_info("ipoe: delete %08x\n", ses->peer_addr); + + if (ses->peer_addr) + list_del_rcu(&ses->entry); + list_del(&ses->entry2); + + up(&ipoe_wlock); + + synchronize_rcu(); + + atomic_dec(&ses->refs); + + while (atomic_read(&ses->refs)) + schedule_timeout_uninterruptible(1); + + if (ses->link_dev) + dev_put(ses->link_dev); + + unregister_netdev(ses->dev); + + ret = 0; + +out_unlock: + up(&ipoe_wlock); +out: + return ret; +} + +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 ipoe_session *ses; + int ifindex; + + if (!info->attrs[IPOE_ATTR_IFINDEX]) + goto out; + + down(&ipoe_wlock); + + ifindex = nla_get_be32(info->attrs[IPOE_ATTR_IFINDEX]); + + rcu_read_lock(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + dev = dev_get_by_index_rcu(ifindex); +#else + dev = dev_get_by_index_rcu(&init_net, ifindex); +#endif + if (!dev || dev->header_ops != &ipoe_hard_header_ops) + r = 1; + rcu_read_unlock(); - pr_info("ipoe: delete %08x\n", addr); + if (r) + goto out_unlock; - return ipoe_delete(addr); + ses = netdev_priv(dev); + + if (info->attrs[IPOE_ATTR_IFNAME]) { + nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1); + + link_dev = dev_get_by_name(&init_net, ifname); + + if (!link_dev) + goto out_unlock; + + old_dev = ses->link_dev; + ses->link_dev = link_dev; + if (old_dev) + dev_put(old_dev); + } + + if (info->attrs[IPOE_ATTR_PEER_ADDR]) { + if (ses->peer_addr) { + list_del_rcu(&ses->entry); + synchronize_rcu(); + } + + ses->peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]); + + if (ses->peer_addr) + list_add_tail_rcu(&ses->entry, &ipoe_list[hash_addr(ses->peer_addr)]) + } + + if (info->attrs[IPOE_ATTR_ADDR]) + ses->addr = nla_get_be32(info->attrs[IPOE_ATTR_ADDR]); + + if (info->attrs[IPOE_ATTR_HWADDR]) + nla_memcpy(ses->hwaddr, info->attrs[IPOE_ATTR_HWADDR], ETH_ALEN); + + pr_info("ipoe: modify %08x %08x\n", ses->peer_addr, ses->addr); + + ret = 0; + +out_unlock: + up(&ipoe_wlock); +out: + return ret; } static int ipoe_nl_cmd_add_net(struct sk_buff *skb, struct genl_info *info) @@ -1064,7 +1187,7 @@ static int ipoe_nl_cmd_add_net(struct sk_buff *skb, struct genl_info *info) n->addr = nla_get_u32(info->attrs[IPOE_ATTR_ADDR]); n->mask = nla_get_u32(info->attrs[IPOE_ATTR_MASK]); - pr_info("add net %08x/%08x\n", 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); @@ -1086,7 +1209,7 @@ static int ipoe_nl_cmd_del_net(struct sk_buff *skb, struct genl_info *info) 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); + //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); @@ -1133,6 +1256,12 @@ static struct genl_ops ipoe_nl_ops[] = { .flags = GENL_ADMIN_PERM, }, { + .cmd = IPOE_CMD_MODIFY, + .doit = ipoe_nl_cmd_modify, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { .cmd = IPOE_CMD_ADD_NET, .doit = ipoe_nl_cmd_add_net, .policy = ipoe_nl_policy, @@ -1248,6 +1377,8 @@ static void __exit ipoe_fini(void) { struct ipoe_network *n; struct ipoe_entry_u *e; + struct ipoe_session *ses; + int i; genl_unregister_mc_group(&ipoe_nl_family, &ipoe_nl_mcg); genl_unregister_family(&ipoe_nl_family); @@ -1259,9 +1390,25 @@ static void __exit ipoe_fini(void) 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]); rcu_barrier(); + while (!list_empty(&ipoe_list2)) { + ses = list_entry(ipoe_list2.next, typeof(*ses), entry); + list_del(&ses->entry2); + + if (ses->link_dev) + dev_put(ses->link_dev); + + unregister_netdev(ses->dev); + } + while (!list_empty(&ipoe_networks)) { n = list_entry(ipoe_networks.next, typeof(*n), entry); list_del(&n->entry); diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h index 8d628cf0..14833105 100644 --- a/drivers/ipoe/ipoe.h +++ b/drivers/ipoe/ipoe.h @@ -1,5 +1,5 @@ -#ifndef __LINUX_ISG_H -#define __LINUX_ISG_H +#ifndef __LINUX_IPOE_H +#define __LINUX_IPOE_H #include <linux/types.h> @@ -7,6 +7,7 @@ enum { IPOE_CMD_NOOP, IPOE_CMD_CREATE, IPOE_CMD_DELETE, + IPOE_CMD_MODIFY, IPOE_CMD_ADD_NET, IPOE_CMD_DEL_NET, IPOE_REP_PKT, @@ -22,7 +23,7 @@ enum { IPOE_ATTR_IFNAME, /* u32 */ IPOE_ATTR_HWADDR, /* u32 */ IPOE_ATTR_MASK, /* u32 */ - IPOE_ATTR_PKT, /* u32 */ + IPOE_ATTR_IFINDEX, /* u32 */ IPOE_ATTR_ETH_HDR, /* u32 */ IPOE_ATTR_IP_HDR, /* u32 */ __IPOE_ATTR_MAX, |