summaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/datagram.c2
-rw-r--r--net/core/dev.c89
-rw-r--r--net/core/scm.c8
-rw-r--r--net/core/sock.c4
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);