summaryrefslogtreecommitdiff
path: root/drivers/ipoe/ipoe.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ipoe/ipoe.c')
-rw-r--r--drivers/ipoe/ipoe.c135
1 files changed, 131 insertions, 4 deletions
diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c
index 1aafde62..04fc7113 100644
--- a/drivers/ipoe/ipoe.c
+++ b/drivers/ipoe/ipoe.c
@@ -65,7 +65,6 @@ struct ipoe_session {
__be32 addr;
__be32 peer_addr;
- __be32 l4_redirect;
__u8 hwaddr[ETH_ALEN];
struct net_device *dev;
@@ -121,6 +120,7 @@ struct vlan_notify {
static struct list_head ipoe_list[HASH_BITS + 1];
static struct list_head ipoe_list1_u[HASH_BITS + 1];
+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);
@@ -196,6 +196,28 @@ static int ipoe_check_network(__be32 addr)
return r;
}
+static int ipoe_check_exclude(__be32 addr)
+{
+ struct ipoe_network *n;
+ struct list_head *ht;
+ int r = 0;
+
+ ht = &ipoe_excl_list[hash_addr(addr)];
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(n, ht, entry) {
+ if (addr == n->addr) {
+ r = 1;
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+
+ return r;
+}
+
static int ipoe_check_interface(int ifindex)
{
struct ipoe_iface *i;
@@ -754,6 +776,9 @@ static unsigned int ipt_in_hook(const struct nf_hook_ops *ops, struct sk_buff *s
ses = ipoe_lookup(iph->saddr);
if (!ses) {
+ if (ipoe_check_exclude(iph->saddr))
+ return NF_ACCEPT;
+
if (!ipoe_check_network(iph->saddr))
return NF_ACCEPT;
@@ -847,6 +872,9 @@ static unsigned int ipt_out_hook(const struct nf_hook_ops *ops, struct sk_buff *
iph = ip_hdr(skb);
+ if (ipoe_check_exclude(iph->daddr))
+ return NF_ACCEPT;
+
if (!ipoe_check_network(iph->daddr))
return NF_ACCEPT;
@@ -1558,6 +1586,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]);
+ n->addr = ntohl(n->addr) & n->mask;
//pr_info("add net %08x/%08x\n", n->addr, n->mask);
down(&ipoe_wlock);
@@ -1596,6 +1625,89 @@ static int ipoe_nl_cmd_del_net(struct sk_buff *skb, struct genl_info *info)
return 0;
}
+static int ipoe_nl_cmd_add_exclude(struct sk_buff *skb, struct genl_info *info)
+{
+ struct ipoe_network *n;
+ struct list_head *ht;
+
+ if (!info->attrs[IPOE_ATTR_ADDR])
+ return -EINVAL;
+
+ n = kmalloc(sizeof(*n), GFP_KERNEL);
+ if (!n)
+ return -ENOMEM;
+
+ n->addr = nla_get_u32(info->attrs[IPOE_ATTR_ADDR]);
+
+ ht = &ipoe_excl_list[hash_addr(n->addr)];
+
+ down(&ipoe_wlock);
+ list_add_tail_rcu(&n->entry, ht);
+ up(&ipoe_wlock);
+
+ return 0;
+}
+
+static void clean_excl_list(void)
+{
+ struct ipoe_network *n;
+ struct list_head *ht;
+ int i;
+
+ down(&ipoe_wlock);
+ rcu_read_lock();
+ for (i = 0; i <= HASH_BITS; i++) {
+ 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();
+ up(&ipoe_wlock);
+}
+
+static int ipoe_nl_cmd_del_exclude(struct sk_buff *skb, struct genl_info *info)
+{
+ struct list_head *ht;
+ struct ipoe_network *n;
+ u32 addr;
+
+ if (!info->attrs[IPOE_ATTR_ADDR])
+ return -EINVAL;
+
+ addr = ntohl(nla_get_u32(info->attrs[IPOE_ATTR_ADDR]));
+ if (!addr) {
+ clean_excl_list();
+ return 0;
+ }
+
+ ht = &ipoe_excl_list[hash_addr(addr)];
+
+ down(&ipoe_wlock);
+ rcu_read_lock();
+ 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();
+ up(&ipoe_wlock);
+
+ synchronize_rcu();
+
+ return 0;
+}
+
static int ipoe_nl_cmd_add_interface(struct sk_buff *skb, struct genl_info *info)
{
struct ipoe_iface *i;
@@ -1907,6 +2019,18 @@ static struct genl_ops ipoe_nl_ops[] = {
.policy = ipoe_nl_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = IPOE_CMD_ADD_EXCLUDE,
+ .doit = ipoe_nl_cmd_add_exclude,
+ .policy = ipoe_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = IPOE_CMD_DEL_EXCLUDE,
+ .doit = ipoe_nl_cmd_del_exclude,
+ .policy = ipoe_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
static struct genl_family ipoe_nl_family = {
@@ -1976,14 +2100,15 @@ static int __init ipoe_init(void)
{
int err, i;
- printk("IPoE session driver v1.8.0.2\n");
+ printk("IPoE session driver v1.8.0.3\n");
/*err = register_pernet_device(&ipoe_net_ops);
if (err < 0)
return err;*/
- for (i = 0; i < HASH_BITS + 1; i++) {
+ for (i = 0; i <= HASH_BITS; i++) {
INIT_LIST_HEAD(&ipoe_list[i]);
INIT_LIST_HEAD(&ipoe_list1_u[i]);
+ INIT_LIST_HEAD(&ipoe_excl_list[i]);
}
skb_queue_head_init(&ipoe_queue);
@@ -2070,7 +2195,7 @@ static void __exit ipoe_fini(void)
down(&ipoe_wlock);
up(&ipoe_wlock);
- for (i = 0; i < HASH_BITS; i++)
+ for (i = 0; i <= HASH_BITS; i++)
rcu_assign_pointer(ipoe_list[i].next, &ipoe_list[i]);
rcu_barrier();
@@ -2122,6 +2247,8 @@ static void __exit ipoe_fini(void)
kfree(vn);
}
+ clean_excl_list();
+
synchronize_rcu();
}