summaryrefslogtreecommitdiffstats
path: root/net/core/sock.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
commit78c388aed2b7184182c08428db1de6c872d815f5 (patch)
tree4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /net/core/sock.c
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'net/core/sock.c')
-rw-r--r--net/core/sock.c111
1 files changed, 69 insertions, 42 deletions
diff --git a/net/core/sock.c b/net/core/sock.c
index e9e293ec9..caaaa21e6 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.70 1998/08/26 12:03:07 davem Exp $
+ * Version: $Id: sock.c,v 1.75 1998/11/07 10:54:38 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -138,8 +138,7 @@ __u32 sysctl_rmem_max = SK_RMEM_MAX;
__u32 sysctl_wmem_default = SK_WMEM_MAX;
__u32 sysctl_rmem_default = SK_RMEM_MAX;
-int sysctl_core_destroy_delay = SOCK_DESTROY_TIME;
-/* Maximal space eaten by iovec (still not made (2.1.88)!) plus some space */
+/* Maximal space eaten by iovec or ancilliary data plus some space */
int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
/*
@@ -155,7 +154,6 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
int valbool;
int err;
struct linger ling;
- struct ifreq req;
int ret = 0;
#ifdef CONFIG_FILTER
@@ -293,31 +291,41 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
#ifdef CONFIG_NETDEVICES
case SO_BINDTODEVICE:
+ {
+ char devname[IFNAMSIZ];
+
+ /* Sorry... */
+ if (!capable(CAP_NET_RAW))
+ return -EPERM;
+
/* Bind this socket to a particular device like "eth0",
- * as specified in an ifreq structure. If the device
- * is "", socket is NOT bound to a device.
- */
+ * as specified in the passed interface name. If the
+ * name is "" or the option length is zero the socket
+ * is not bound.
+ */
if (!valbool) {
sk->bound_dev_if = 0;
- }
- else {
- if (copy_from_user(&req, optval, sizeof(req)))
- return -EFAULT;
-
+ } else {
+ if (optlen > IFNAMSIZ)
+ optlen = IFNAMSIZ;
+ if (copy_from_user(devname, optval, optlen))
+ return -EFAULT;
+
/* Remove any cached route for this socket. */
dst_release(xchg(&sk->dst_cache, NULL));
- if (req.ifr_ifrn.ifrn_name[0] == '\0') {
+ if (devname[0] == '\0') {
sk->bound_dev_if = 0;
} else {
- struct device *dev = dev_get(req.ifr_ifrn.ifrn_name);
+ struct device *dev = dev_get(devname);
if (!dev)
return -EINVAL;
sk->bound_dev_if = dev->ifindex;
}
+ return 0;
}
- return 0;
+ }
#endif
@@ -483,7 +491,8 @@ struct sock *sk_alloc(int family, int priority, int zero_it)
struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
if(sk) {
- if (zero_it) memset(sk, 0, sizeof(struct sock));
+ if (zero_it)
+ memset(sk, 0, sizeof(struct sock));
sk->family = family;
}
@@ -498,7 +507,7 @@ void sk_free(struct sock *sk)
kmem_cache_free(sk_cachep, sk);
}
-__initfunc(void sk_init(void))
+void __init sk_init(void)
{
sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
SLAB_HWCACHE_ALIGN, 0, 0);
@@ -508,35 +517,34 @@ __initfunc(void sk_init(void))
/*
* Simple resource managers for sockets.
*/
-
+
+
+/*
+ * Write buffer destructor automatically called from kfree_skb.
+ */
void sock_wfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
-#if 1
- if (!sk) {
- printk(KERN_DEBUG "sock_wfree: sk==NULL\n");
- return;
- }
-#endif
+
/* In case it might be waiting for more memory. */
atomic_sub(skb->truesize, &sk->wmem_alloc);
sk->write_space(sk);
}
-
+/*
+ * Read buffer destructor automatically called from kfree_skb.
+ */
void sock_rfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
-#if 1
- if (!sk) {
- printk(KERN_DEBUG "sock_rfree: sk==NULL\n");
- return;
- }
-#endif
+
atomic_sub(skb->truesize, &sk->rmem_alloc);
}
+/*
+ * Allocate a skb from the socket's send buffer.
+ */
struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
{
if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
@@ -551,6 +559,9 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int
return NULL;
}
+/*
+ * Allocate a skb from the socket's receive buffer.
+ */
struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
{
if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) {
@@ -565,6 +576,9 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
return NULL;
}
+/*
+ * Allocate a memory block from the socket's option memory buffer.
+ */
void *sock_kmalloc(struct sock *sk, int size, int priority)
{
if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
@@ -581,6 +595,9 @@ void *sock_kmalloc(struct sock *sk, int size, int priority)
return NULL;
}
+/*
+ * Free an option memory block.
+ */
void sock_kfree_s(struct sock *sk, void *mem, int size)
{
kfree_s(mem, size);
@@ -813,7 +830,7 @@ void sklist_destroy_socket(struct sock **list,struct sock *sk)
* Someone is using our buffers still.. defer
*/
init_timer(&sk->timer);
- sk->timer.expires=jiffies+sysctl_core_destroy_delay;
+ sk->timer.expires=jiffies+SOCK_DESTROY_TIME;
sk->timer.function=sklist_destroy_timer;
sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer);
@@ -944,16 +961,23 @@ int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int flags,
* Default Socket Callbacks
*/
-void sock_def_callback1(struct sock *sk)
+void sock_def_wakeup(struct sock *sk)
{
if(!sk->dead)
wake_up_interruptible(sk->sleep);
}
-void sock_def_callback2(struct sock *sk, int len)
+void sock_def_error_report(struct sock *sk)
{
- if(!sk->dead)
- {
+ if (!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket,0);
+ }
+}
+
+void sock_def_readable(struct sock *sk, int len)
+{
+ if(!sk->dead) {
wake_up_interruptible(sk->sleep);
sock_wake_async(sk->socket,1);
}
@@ -961,11 +985,14 @@ void sock_def_callback2(struct sock *sk, int len)
void sock_def_write_space(struct sock *sk)
{
- if(!sk->dead)
- {
+ /* Do not wake up a writer until he can make "significant"
+ * progress. --DaveM
+ */
+ if(!sk->dead &&
+ ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) {
wake_up_interruptible(sk->sleep);
- /* Should agree with poll, otherwise some programs break */
+ /* Should agree with poll, otherwise some programs break */
if (sock_writeable(sk))
sock_wake_async(sk->socket, 2);
}
@@ -1000,10 +1027,10 @@ void sock_init_data(struct socket *sock, struct sock *sk)
sock->sk = sk;
}
- sk->state_change = sock_def_callback1;
- sk->data_ready = sock_def_callback2;
+ sk->state_change = sock_def_wakeup;
+ sk->data_ready = sock_def_readable;
sk->write_space = sock_def_write_space;
- sk->error_report = sock_def_callback1;
+ sk->error_report = sock_def_error_report;
sk->destruct = sock_def_destruct;
sk->peercred.pid = 0;