int netdev_fastroute_obstacles;
#endif
+#ifdef CONFIG_SYSFS
extern int netdev_sysfs_init(void);
extern int netdev_register_sysfs(struct net_device *);
-extern int netdev_unregister_sysfs(struct net_device *);
+extern void netdev_unregister_sysfs(struct net_device *);
+#else
+#define netdev_sysfs_init() (0)
+#define netdev_register_sysfs(dev) (0)
+#define netdev_unregister_sysfs(dev) do { } while(0)
+#endif
/*******************************************************************************
/**
* dev_change_name - change name of a device
* @dev: device
- * @name: name (or format string) must be at least IFNAMSIZ
+ * @newname: name (or format string) must be at least IFNAMSIZ
*
* Change name of a device, can pass format strings "eth%d".
* for wildcarding.
*/
int dev_change_name(struct net_device *dev, char *newname)
{
+ int err = 0;
+
ASSERT_RTNL();
if (dev->flags & IFF_UP)
return -EINVAL;
if (strchr(newname, '%')) {
- int err = dev_alloc_name(dev, newname);
+ err = dev_alloc_name(dev, newname);
if (err < 0)
return err;
strcpy(newname, dev->name);
else
strlcpy(dev->name, newname, IFNAMSIZ);
- hlist_del(&dev->name_hlist);
- hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
+ err = class_device_rename(&dev->class_dev, dev->name);
+ if (!err) {
+ hlist_del(&dev->name_hlist);
+ hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+ }
- class_device_rename(&dev->class_dev, dev->name);
- notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
- return 0;
+ return err;
}
/**
rcu_read_unlock();
}
-/* Calculate csum in the case, when packet is misrouted.
- * If it failed by some reason, ignore and send skb with wrong
- * checksum.
+/*
+ * Invalidate hardware checksum when packet is to be mangled, and
+ * complete checksum manually on outgoing path.
*/
-struct sk_buff *skb_checksum_help(struct sk_buff *skb)
+int skb_checksum_help(struct sk_buff **pskb, int inward)
{
unsigned int csum;
- int offset = skb->h.raw - skb->data;
+ int ret = 0, offset = (*pskb)->h.raw - (*pskb)->data;
+
+ if (inward) {
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+ goto out;
+ }
+
+ if (skb_shared(*pskb) || skb_cloned(*pskb)) {
+ struct sk_buff *newskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!newskb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if ((*pskb)->sk)
+ skb_set_owner_w(newskb, (*pskb)->sk);
+ kfree_skb(*pskb);
+ *pskb = newskb;
+ }
- if (offset > (int)skb->len)
+ if (offset > (int)(*pskb)->len)
BUG();
- csum = skb_checksum(skb, offset, skb->len-offset, 0);
+ csum = skb_checksum(*pskb, offset, (*pskb)->len-offset, 0);
- offset = skb->tail - skb->h.raw;
+ offset = (*pskb)->tail - (*pskb)->h.raw;
if (offset <= 0)
BUG();
- if (skb->csum + 2 > offset)
+ if ((*pskb)->csum + 2 > offset)
BUG();
- *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
- skb->ip_summed = CHECKSUM_NONE;
- return skb;
+ *(u16*)((*pskb)->h.raw + (*pskb)->csum) = csum_fold(csum);
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+out:
+ return ret;
}
#ifdef CONFIG_HIGHMEM
if (skb->ip_summed == CHECKSUM_HW &&
(!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
(!(dev->features & NETIF_F_IP_CSUM) ||
- skb->protocol != htons(ETH_P_IP)))) {
- if ((skb = skb_checksum_help(skb)) == NULL)
- goto out;
- }
+ skb->protocol != htons(ETH_P_IP))))
+ if (skb_checksum_help(&skb, 0))
+ goto out_kfree_skb;
/* Grab device queue */
spin_lock_bh(&dev->queue_lock);
{
struct ifconf ifc;
struct net_device *dev;
- char *pos;
+ char __user *pos;
int len;
int total;
int i;
cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG ||
cmd == SIOCSMIIREG ||
+ cmd == SIOCBRADDIF ||
+ cmd == SIOCBRDELIF ||
cmd == SIOCWANDEV) {
err = -EOPNOTSUPP;
if (dev->do_ioctl) {
case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY:
case SIOCBONDCHANGEACTIVE:
+ case SIOCBRADDIF:
+ case SIOCBRDELIF:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
void netdev_run_todo(void)
{
struct list_head list = LIST_HEAD_INIT(list);
+ int err;
- /* Safe outside mutex since we only care about entries that
- * this cpu put into queue while under RTNL.
- */
- if (list_empty(&net_todo_list))
- return;
/* Need to guard against multiple cpu's getting out of order. */
down(&net_todo_run_mutex);
+ /* Not safe to do outside the semaphore. We must not return
+ * until all unregister events invoked by the local processor
+ * have been completed (either by this todo run, or one on
+ * another cpu).
+ */
+ if (list_empty(&net_todo_list))
+ goto out;
+
/* Snapshot list, allow later requests */
spin_lock(&net_todo_list_lock);
list_splice_init(&net_todo_list, &list);
switch(dev->reg_state) {
case NETREG_REGISTERING:
- netdev_register_sysfs(dev);
+ err = netdev_register_sysfs(dev);
+ if (err)
+ printk(KERN_ERR "%s: failed sysfs registration (%d)\n",
+ dev->name, err);
dev->reg_state = NETREG_REGISTERED;
break;
}
}
+out:
up(&net_todo_run_mutex);
}
*/
void free_netdev(struct net_device *dev)
{
+#ifdef CONFIG_SYSFS
/* Compatiablity with error handling in drivers */
if (dev->reg_state == NETREG_UNINITIALIZED) {
kfree((char *)dev - dev->padded);
/* will free via class release */
class_device_put(&dev->class_dev);
+#else
+ kfree((char *)dev - dev->padded);
+#endif
}
/* Synchronize with packet receive processing. */