diff options
Diffstat (limited to 'drivers/ipoe/ipoe.c')
-rw-r--r-- | drivers/ipoe/ipoe.c | 80 |
1 files changed, 51 insertions, 29 deletions
diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index 4a1a798..eb8f8de 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -38,6 +38,7 @@ #define HASH_BITS 0xff #define IPOE_MAGIC 0x55aa +#define IPOE_MAGIC2 0x67f8bc32 #define IPOE_QUEUE_LEN 100 #define IPOE_RATE_U 3000 //3s @@ -102,10 +103,11 @@ struct ipoe_entry_u { }; struct vlan_dev { + unsigned int magic; + int ifindex; struct rcu_head rcu_head; struct list_head entry; - int ifindex; spinlock_t lock; unsigned long vid[4096/8/sizeof(long)]; }; @@ -855,22 +857,19 @@ static int vlan_pt_recv(struct sk_buff *skb, struct net_device *dev, struct pack struct vlan_notify *n; int vid; + if (!dev->ml_priv) + goto out; + + d = dev->ml_priv; + if (d->magic != IPOE_MAGIC2 || d->ifindex != dev->ifindex) + goto out; + if (!vlan_tx_tag_present(skb)) goto out; vid = skb->vlan_tci & VLAN_VID_MASK; //pr_info("vid %i\n", vid); - rcu_read_lock(); - list_for_each_entry_rcu(d, &vlan_devices, entry) { - if (d->ifindex == dev->ifindex) - goto found; - } - rcu_read_unlock(); - goto out; - -found: - //pr_info("found %i\n", d->ifindex); if (d->vid[vid / (8*sizeof(long))] & (1lu << (vid % (8*sizeof(long))))) vid = -1; else { @@ -1629,15 +1628,23 @@ static int ipoe_nl_cmd_add_vlan_mon(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; + if (dev->ml_priv) { + dev_put(dev); + return -EBUSY; + } + d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) { dev_put(dev); return -ENOMEM; } + d->magic = IPOE_MAGIC2; d->ifindex = ifindex; spin_lock_init(&d->lock); + dev->ml_priv = d; + if (info->attrs[IPOE_ATTR_VLAN_MASK]) { memcpy(d->vid, nla_data(info->attrs[IPOE_ATTR_VLAN_MASK]), min((int)nla_len(info->attrs[IPOE_ATTR_VLAN_MASK]), (int)sizeof(d->vid))); @@ -1691,23 +1698,23 @@ static int ipoe_nl_cmd_add_vlan_mon_vid(struct sk_buff *skb, struct genl_info *i if (!dev) return -ENODEV; - down(&ipoe_wlock); - list_for_each_entry(d, &vlan_devices, entry) { - if (d->ifindex == ifindex) { - spin_lock_irqsave(&d->lock, flags); - d->vid[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); - spin_unlock_irqrestore(&d->lock, flags); + if (!dev->ml_priv) { + dev_put(dev); + return -EINVAL; + } + + d = dev->ml_priv; + + spin_lock_irqsave(&d->lock, flags); + d->vid[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); + spin_unlock_irqrestore(&d->lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) - if (dev->features & NETIF_F_HW_VLAN_FILTER) - dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); + if (dev->features & NETIF_F_HW_VLAN_FILTER) + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); #else - if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) - dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), vid); + if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), vid); #endif - break; - } - } - up(&ipoe_wlock); dev_put(dev); @@ -1721,16 +1728,31 @@ static int ipoe_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *info) int ifindex; unsigned long flags; struct list_head *pos, *n; + struct net_device *dev; if (info->attrs[IPOE_ATTR_IFINDEX]) ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); else ifindex = -1; - rcu_read_lock(); - list_for_each_entry_rcu(d, &vlan_devices, entry) { + down(&ipoe_wlock); + list_for_each_entry(d, &vlan_devices, entry) { if (ifindex == -1 || d->ifindex == ifindex) { //pr_info("del net %08x/%08x\n", n->addr, n->mask); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + rtnl_lock(); + dev = __dev_get_by_index(&init_net, d->ifindex); + rtnl_unlock(); +#else + dev = dev_get_by_index(&init_net, d->ifindex); +#endif + + if (dev) { + if (dev->ml_priv == d) + dev->ml_priv = NULL; + dev_put(dev); + } + list_del_rcu(&d->entry); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) kfree_rcu(d, rcu_head); @@ -1739,7 +1761,7 @@ static int ipoe_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *info) #endif } } - rcu_read_unlock(); + up(&ipoe_wlock); spin_lock_irqsave(&vlan_lock, flags); list_for_each_safe(pos, n, &vlan_notifies) { @@ -1902,7 +1924,7 @@ static int __init ipoe_init(void) { int err, i; - printk("IPoE session driver v1.8.0\n"); + printk("IPoE session driver v1.8.0.1\n"); /*err = register_pernet_device(&ipoe_net_ops); if (err < 0) |