diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/datagram.c | 2 | ||||
-rw-r--r-- | net/core/dev.c | 89 | ||||
-rw-r--r-- | net/core/scm.c | 8 | ||||
-rw-r--r-- | net/core/sock.c | 4 |
4 files changed, 93 insertions, 10 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index 7f85645f0..0b865f6b9 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -66,7 +66,7 @@ static int wait_for_packet(struct sock * sk, int *err, long *timeo_p) DECLARE_WAITQUEUE(wait, current); - __set_current_state(TASK_INTERRUPTIBLE|TASK_EXCLUSIVE); + __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue_exclusive(sk->sleep, &wait); /* Socket errors? */ diff --git a/net/core/dev.c b/net/core/dev.c index 17fae7a1e..1e5b59c3d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -93,6 +93,7 @@ #include <net/profile.h> #include <linux/init.h> #include <linux/kmod.h> +#include <linux/module.h> #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ @@ -666,9 +667,15 @@ int dev_open(struct net_device *dev) /* * Call device private open method */ - - if (dev->open) - ret = dev->open(dev); + if (try_inc_mod_count(dev->owner)) { + if (dev->open) { + ret = dev->open(dev); + if (ret != 0 && dev->owner) + __MOD_DEC_USE_COUNT(dev->owner); + } + } else { + ret = -ENODEV; + } /* * If it went open OK then: @@ -784,6 +791,12 @@ int dev_close(struct net_device *dev) */ notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + /* + * Drop the module refcount + */ + if (dev->owner) + __MOD_DEC_USE_COUNT(dev->owner); + return(0); } @@ -2056,8 +2069,9 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) */ default: - if (cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15) { + if ((cmd >= SIOCDEVPRIVATE && + cmd <= SIOCDEVPRIVATE + 15) || + cmd == SIOCETHTOOL) { if (dev->do_ioctl) { if (!netif_device_present(dev)) return -ENODEV; @@ -2178,6 +2192,7 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCSIFHWBROADCAST: case SIOCSIFTXQLEN: case SIOCSIFNAME: + case SIOCETHTOOL: if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); @@ -2688,3 +2703,67 @@ int __init net_dev_init(void) return 0; } + +#ifdef CONFIG_HOTPLUG + +/* Notify userspace when a netdevice event occurs, + * by running '/sbin/hotplug net' with certain + * environment variables set. + * + * Currently reported events are listed in netdev_event_names[]. + */ + +/* /sbin/hotplug ONLY executes for events named here */ +static char *netdev_event_names[] = { + [NETDEV_REGISTER] = "register", + [NETDEV_UNREGISTER] = "unregister", +}; + +static int run_sbin_hotplug(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = (struct net_device *) ptr; + char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32]; + int i; + + if ((event >= ARRAY_SIZE(netdev_event_names)) || + !netdev_event_names[event]) + return NOTIFY_DONE; + + sprintf(ifname, "INTERFACE=%s", dev->name); + sprintf(action, "ACTION=%s", netdev_event_names[event]); + + i = 0; + argv[i++] = hotplug_path; + argv[i++] = "net"; + argv[i] = 0; + + i = 0; + /* minimal command environment */ + envp [i++] = "HOME=/"; + envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + envp [i++] = ifname; + envp [i++] = action; + envp [i] = 0; + + call_usermodehelper (argv [0], argv, envp); + + return NOTIFY_DONE; +} + +static struct notifier_block sbin_hotplug = { + notifier_call: run_sbin_hotplug, +}; + +/* + * called from init/main.c, -after- all the initcalls are complete. + * Registers a hook that calls /sbin/hotplug on every netdev + * addition and removal. + */ +void __init net_notifier_init (void) +{ + if (register_netdevice_notifier(&sbin_hotplug)) + printk (KERN_WARNING "unable to register netdev notifier\n" + KERN_WARNING "/sbin/hotplug will not be run.\n"); +} +#endif diff --git a/net/core/scm.c b/net/core/scm.c index a29c21a8a..0bd1b4004 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -204,12 +204,16 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) { struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control; - int fdmax = (msg->msg_controllen - sizeof(struct cmsghdr))/sizeof(int); + int fdmax = 0; int fdnum = scm->fp->count; struct file **fp = scm->fp->fp; int *cmfptr; int err = 0, i; + if (msg->msg_controllen > sizeof(struct cmsghdr)) + fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr)) + / sizeof(int)); + if (fdnum < fdmax) fdmax = fdnum; @@ -245,7 +249,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) msg->msg_controllen -= cmlen; } } - if (i < fdnum) + if (i < fdnum || (fdnum && fdmax <= 0)) msg->msg_flags |= MSG_CTRUNC; /* diff --git a/net/core/sock.c b/net/core/sock.c index 8503e364f..7b9484437 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.100 2000/09/18 05:59:48 davem Exp $ + * Version: $Id: sock.c,v 1.101 2000/11/10 04:02:04 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -819,7 +819,7 @@ void __lock_sock(struct sock *sk) add_wait_queue_exclusive(&sk->lock.wq, &wait); for(;;) { - current->state = TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE; + current->state = TASK_UNINTERRUPTIBLE; spin_unlock_bh(&sk->lock.slock); schedule(); spin_lock_bh(&sk->lock.slock); |