summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c12
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h2
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c53
-rw-r--r--drivers/ipoe/ipoe.c106
-rw-r--r--drivers/ipoe/ipoe.h2
5 files changed, 165 insertions, 10 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 1ba53ea7..09bd8873 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -1419,6 +1419,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
opt_dhcpv4 = conf_dhcpv4;
}
+ if (opt_up)
+ ipoe_nl_add_interface(ifindex);
+
list_for_each_entry(serv, &serv_list, entry) {
if (strcmp(ifname, serv->ifname))
continue;
@@ -1576,6 +1579,8 @@ static void load_interfaces(struct conf_sect_t *sect)
struct conf_option_t *opt;
struct list_head *pos, *n;
+ ipoe_nl_delete_interfaces();
+
list_for_each_entry(serv, &serv_list, entry)
serv->active = 0;
@@ -1629,7 +1634,12 @@ static void parse_local_net(const char *opt)
if (mask == 32)
mask = 0xffffffff;
else
- mask = (1 << mask) - 1;
+ mask = (1 << (32-mask)) - 1;
+
+ addr = ntohl(addr);
+ mask = ~mask;
+
+ //printf("%x/%x %x\n", htonl(addr), ~mask, htonl(addr)&(~mask));
ipoe_nl_add_net(addr & mask, mask);
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index 827cba31..bb5841e5 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -85,6 +85,8 @@ 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_delete_interfaces(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);
diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
index b92ec928..dde83a52 100644
--- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c
+++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
@@ -82,6 +82,59 @@ void ipoe_nl_add_net(uint32_t addr, int mask)
log_error("ipoe: nl_add_net: error talking to kernel\n");
}
+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)
+{
+ 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_IF;
+
+ addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 )
+ log_error("ipoe: nl_add_iface: 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;
diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c
index 54cb2176..bf86e8cd 100644
--- a/drivers/ipoe/ipoe.c
+++ b/drivers/ipoe/ipoe.c
@@ -49,16 +49,14 @@
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
-struct ipoe_stats
-{
+struct ipoe_stats {
struct u64_stats_sync sync;
u64 packets;
u64 bytes;
};
#endif
-struct ipoe_session
-{
+struct ipoe_session {
struct list_head entry;
struct list_head entry2;
@@ -78,8 +76,7 @@ struct ipoe_session
#endif
};
-struct ipoe_network
-{
+struct ipoe_network {
struct rcu_head rcu_head;
struct list_head entry;
@@ -87,8 +84,14 @@ struct ipoe_network
__be32 mask;
};
-struct ipoe_entry_u
-{
+struct ipoe_iface {
+ struct rcu_head rcu_head;
+ struct list_head entry;
+
+ int ifindex;
+};
+
+struct ipoe_entry_u {
struct rcu_head rcu_head;
struct list_head entry1;
struct list_head entry2;
@@ -103,6 +106,7 @@ 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;
@@ -155,7 +159,26 @@ static int ipoe_check_network(__be32 addr)
rcu_read_lock();
list_for_each_entry_rcu(n, &ipoe_networks, entry) {
- if ((addr & n->mask) == n->addr) {
+ if ((ntohl(addr) & n->mask) == n->addr) {
+ r = 1;
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+
+ 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;
}
@@ -166,6 +189,7 @@ static int ipoe_check_network(__be32 addr)
return r;
}
+
static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer)
{
struct iphdr *iph;
@@ -690,6 +714,8 @@ static unsigned int ipt_in_hook(unsigned int hook, struct sk_buff *skb, const st
ses = ipoe_lookup(iph->saddr);
if (!ses) {
+ if (!ipoe_check_interface(in->ifindex))
+ return NF_ACCEPT;
ipoe_queue_u(skb, iph->saddr);
return NF_DROP;
}
@@ -1369,6 +1395,56 @@ static int ipoe_nl_cmd_del_net(struct sk_buff *skb, struct genl_info *info)
return 0;
}
+static int ipoe_nl_cmd_add_interface(struct sk_buff *skb, struct genl_info *info)
+{
+ struct ipoe_iface *i;
+
+ if (!info->attrs[IPOE_ATTR_IFINDEX])
+ return -EINVAL;
+
+ i = kmalloc(sizeof(*i), GFP_KERNEL);
+ if (!i)
+ return -ENOMEM;
+
+ i->ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]);
+
+ down(&ipoe_wlock);
+ list_add_tail_rcu(&i->entry, &ipoe_interfaces);
+ up(&ipoe_wlock);
+
+ return 0;
+}
+
+static int ipoe_nl_cmd_del_interface(struct sk_buff *skb, struct genl_info *info)
+{
+ struct ipoe_iface *i;
+ int ifindex;
+
+ 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) {
+ 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)
+ kfree_rcu(i, rcu_head);
+#else
+ call_rcu(&i->rcu_head, __kfree_rcu);
+#endif
+ }
+ }
+ rcu_read_unlock();
+
+ synchronize_rcu();
+
+ return 0;
+}
+
+
static struct nla_policy ipoe_nl_policy[IPOE_ATTR_MAX + 1] = {
[IPOE_ATTR_NONE] = { .type = NLA_UNSPEC, },
@@ -1422,6 +1498,18 @@ static struct genl_ops ipoe_nl_ops[] = {
.policy = ipoe_nl_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = IPOE_CMD_ADD_IF,
+ .doit = ipoe_nl_cmd_add_interface,
+ .policy = ipoe_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = IPOE_CMD_DEL_IF,
+ .doit = ipoe_nl_cmd_del_interface,
+ .policy = ipoe_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
static struct genl_family ipoe_nl_family = {
diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h
index d40ac21a..d0ac1e41 100644
--- a/drivers/ipoe/ipoe.h
+++ b/drivers/ipoe/ipoe.h
@@ -11,6 +11,8 @@ enum {
IPOE_CMD_GET,
IPOE_CMD_ADD_NET,
IPOE_CMD_DEL_NET,
+ IPOE_CMD_ADD_IF,
+ IPOE_CMD_DEL_IF,
IPOE_REP_PKT,
__IPOE_CMD_MAX,
};