summaryrefslogtreecommitdiffstats
path: root/net/ipv4/af_inet.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/af_inet.c')
-rw-r--r--net/ipv4/af_inet.c546
1 files changed, 232 insertions, 314 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 15b26fa1c..526dd4dd6 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -5,7 +5,7 @@
*
* PF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.93 1999/07/02 11:26:24 davem Exp $
+ * Version: $Id: af_inet.c,v 1.97 1999/09/08 03:46:46 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -80,16 +80,17 @@
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/poll.h>
+#include <linux/netfilter_ipv4.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/arp.h>
-#include <net/rarp.h>
#include <net/route.h>
#include <net/tcp.h>
#include <net/udp.h>
@@ -99,13 +100,9 @@
#include <net/icmp.h>
#include <net/ipip.h>
#include <net/inet_common.h>
-#include <linux/ip_fw.h>
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
-#ifdef CONFIG_IP_MASQUERADE
-#include <net/ip_masq.h>
-#endif
#ifdef CONFIG_BRIDGE
#include <net/br.h>
#endif
@@ -120,6 +117,8 @@
struct linux_mib net_statistics;
+atomic_t inet_sock_nr;
+
extern int raw_get_info(char *, char **, off_t, int, int);
extern int snmp_get_info(char *, char **, off_t, int, int);
extern int netstat_get_info(char *, char **, off_t, int, int);
@@ -136,90 +135,78 @@ extern int dlci_ioctl(unsigned int, void*);
int (*dlci_ioctl_hook)(unsigned int, void *) = NULL;
#endif
-int (*rarp_ioctl_hook)(unsigned int,void*) = NULL;
+/* New destruction routine */
-/*
- * Destroy an AF_INET socket
- */
-
-static __inline__ void kill_sk_queues(struct sock *sk)
+void inet_sock_destruct(struct sock *sk)
{
- struct sk_buff *skb;
+ __skb_queue_purge(&sk->receive_queue);
+ __skb_queue_purge(&sk->error_queue);
- /* First the read buffer. */
- while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
- kfree_skb(skb);
+ if (sk->type == SOCK_STREAM && sk->state != TCP_CLOSE) {
+ printk("Attempt to release TCP socket in state %d %p\n",
+ sk->state,
+ sk);
+ return;
+ }
+ if (!sk->dead) {
+ printk("Attempt to release alive inet socket %p\n", sk);
+ return;
+ }
- /* Next, the error queue. */
- while((skb = skb_dequeue(&sk->error_queue)) != NULL)
- kfree_skb(skb);
+ BUG_TRAP(atomic_read(&sk->rmem_alloc) == 0);
+ BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0);
- /* It is _impossible_ for the backlog to contain anything
- * when we get here. All user references to this socket
- * have gone away, only the net layer knows can touch it.
- */
+ if (sk->protinfo.af_inet.opt)
+ kfree(sk->protinfo.af_inet.opt);
+ dst_release(sk->dst_cache);
+ atomic_dec(&inet_sock_nr);
+#ifdef INET_REFCNT_DEBUG
+ printk(KERN_DEBUG "INET socket %p released, %d are still alive\n", sk, atomic_read(&inet_sock_nr));
+#endif
}
-static __inline__ void kill_sk_now(struct sock *sk)
+void inet_sock_release(struct sock *sk)
{
- /* Remove from protocol hash chains. */
- sk->prot->unhash(sk);
+ if (sk->prot->destroy)
+ sk->prot->destroy(sk);
- if(sk->opt)
- kfree(sk->opt);
- dst_release(sk->dst_cache);
- sk_free(sk);
-}
+ /* Observation: when inet_sock_release is called, processes have
+ no access to socket. But net still has.
+ Step one, detach it from networking:
-static __inline__ void kill_sk_later(struct sock *sk)
-{
- /* this should never happen. */
- /* actually it can if an ack has just been sent. */
- /*
- * It's more normal than that...
- * It can happen because a skb is still in the device queues
- * [PR]
+ A. Remove from hash tables.
*/
-
- NETDEBUG(printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n",
- atomic_read(&sk->rmem_alloc),
- atomic_read(&sk->wmem_alloc)));
-
- sk->destroy = 1;
- sk->ack_backlog = 0;
- bh_unlock_sock(sk);
- net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
-}
-/* Callers must hold the BH spinlock.
- *
- * At this point, there should be no process reference to this
- * socket, and thus no user references at all. Therefore we
- * can assume the socket waitqueue is inactive and nobody will
- * try to jump onto it.
- */
-void destroy_sock(struct sock *sk)
-{
- /* Now we can no longer get new packets or once the
- * timers are killed, send them.
- */
- net_delete_timer(sk);
+ sk->prot->unhash(sk);
- if (sk->prot->destroy)
- sk->prot->destroy(sk);
+ /* In this point socket cannot receive new packets,
+ but it is possible that some packets are in flight
+ because some CPU runs receiver and did hash table lookup
+ before we unhashed socket. They will achieve receive queue
+ and will be purged by socket destructor.
+
+ Also we still have packets pending on receive
+ queue and probably, our own packets waiting in device queues.
+ sock_destroy will drain receive queue, but transmitted
+ packets will delay socket destruction until the last reference
+ will be released.
+ */
- kill_sk_queues(sk);
+ write_lock_irq(&sk->callback_lock);
+ sk->dead=1;
+ sk->socket = NULL;
+ sk->sleep = NULL;
+ write_unlock_irq(&sk->callback_lock);
- /* Now if everything is gone we can free the socket
- * structure, otherwise we need to keep it around until
- * everything is gone.
- */
- if (atomic_read(&sk->rmem_alloc) == 0 && atomic_read(&sk->wmem_alloc) == 0)
- kill_sk_now(sk);
- else
- kill_sk_later(sk);
+#ifdef INET_REFCNT_DEBUG
+ if (atomic_read(&sk->refcnt) != 1) {
+ printk(KERN_DEBUG "Destruction inet %p delayed, c=%d\n", sk, atomic_read(&sk->refcnt));
+ }
+#endif
+ sock_put(sk);
}
+
/*
* The routines beyond this point handle the behaviour of an AF_INET
* socket object. Mostly it punts to the subprotocols of IP to do
@@ -264,12 +251,16 @@ int inet_getsockopt(struct socket *sock, int level, int optname,
static int inet_autobind(struct sock *sk)
{
/* We may need to bind the socket. */
+ lock_sock(sk);
if (sk->num == 0) {
- if (sk->prot->get_port(sk, 0) != 0)
+ if (sk->prot->get_port(sk, 0) != 0) {
+ release_sock(sk);
return -EAGAIN;
+ }
sk->sport = htons(sk->num);
sk->prot->hash(sk);
}
+ release_sock(sk);
return 0;
}
@@ -289,37 +280,47 @@ int inet_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
unsigned char old_state;
+ int err;
if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
return -EINVAL;
- if ((unsigned) backlog == 0) /* BSDism */
- backlog = 1;
- if ((unsigned) backlog > SOMAXCONN)
- backlog = SOMAXCONN;
- sk->max_ack_backlog = backlog;
+ lock_sock(sk);
+ old_state = sk->state;
+ err = -EINVAL;
+ if (!((1<<old_state)&(TCPF_CLOSE|TCPF_LISTEN)))
+ goto out;
/* Really, if the socket is already in listen state
* we can only allow the backlog to be adjusted.
*/
- old_state = sk->state;
if (old_state != TCP_LISTEN) {
sk->state = TCP_LISTEN;
sk->ack_backlog = 0;
if (sk->num == 0) {
if (sk->prot->get_port(sk, 0) != 0) {
sk->state = old_state;
- return -EAGAIN;
+ err = -EAGAIN;
+ goto out;
}
sk->sport = htons(sk->num);
+ } else {
+ /* Not nice, but the simplest solution however */
+ if (sk->prev)
+ ((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0;
}
- dst_release(xchg(&sk->dst_cache, NULL));
+ sk_dst_reset(sk);
sk->prot->hash(sk);
sk->socket->flags |= SO_ACCEPTCON;
sk->write_space = inet_listen_write_space;
}
- return 0;
+ sk->max_ack_backlog = backlog;
+ err = 0;
+
+out:
+ release_sock(sk);
+ return err;
}
/*
@@ -334,24 +335,6 @@ static int inet_create(struct socket *sock, int protocol)
struct sock *sk;
struct proto *prot;
- /* Compatibility */
- if (sock->type == SOCK_PACKET) {
- static int warned;
- if (net_families[PF_PACKET]==NULL)
- {
-#if defined(CONFIG_KMOD) && defined(CONFIG_PACKET_MODULE)
- char module_name[30];
- sprintf(module_name,"net-pf-%d", PF_PACKET);
- request_module(module_name);
- if (net_families[PF_PACKET] == NULL)
-#endif
- return -ESOCKTNOSUPPORT;
- }
- if (!warned++)
- printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
- return net_families[PF_PACKET]->create(sock, protocol);
- }
-
sock->state = SS_UNCONNECTED;
sk = sk_alloc(PF_INET, GFP_KERNEL, 1);
if (sk == NULL)
@@ -363,9 +346,9 @@ static int inet_create(struct socket *sock, int protocol)
goto free_and_noproto;
protocol = IPPROTO_TCP;
if (ipv4_config.no_pmtu_disc)
- sk->ip_pmtudisc = IP_PMTUDISC_DONT;
+ sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
else
- sk->ip_pmtudisc = IP_PMTUDISC_WANT;
+ sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_WANT;
prot = &tcp_prot;
sock->ops = &inet_stream_ops;
break;
@@ -376,7 +359,7 @@ static int inet_create(struct socket *sock, int protocol)
goto free_and_noproto;
protocol = IPPROTO_UDP;
sk->no_check = UDP_CSUM_DEFAULT;
- sk->ip_pmtudisc = IP_PMTUDISC_DONT;
+ sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
prot=&udp_prot;
sock->ops = &inet_dgram_ops;
break;
@@ -387,19 +370,19 @@ static int inet_create(struct socket *sock, int protocol)
goto free_and_noproto;
prot = &raw_prot;
sk->reuse = 1;
- sk->ip_pmtudisc = IP_PMTUDISC_DONT;
+ sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
sk->num = protocol;
sock->ops = &inet_dgram_ops;
if (protocol == IPPROTO_RAW)
- sk->ip_hdrincl = 1;
+ sk->protinfo.af_inet.hdrincl = 1;
break;
default:
goto free_and_badtype;
}
sock_init_data(sock,sk);
-
- sk->destruct = NULL;
+
+ sk->destruct = inet_sock_destruct;
sk->zapped=0;
#ifdef CONFIG_TCP_NAGLE_OFF
@@ -412,15 +395,17 @@ static int inet_create(struct socket *sock, int protocol)
sk->backlog_rcv = prot->backlog_rcv;
sk->timer.data = (unsigned long)sk;
- sk->timer.function = &net_timer;
+ sk->timer.function = &tcp_keepalive_timer;
- sk->ip_ttl=ip_statistics.IpDefaultTTL;
+ sk->protinfo.af_inet.ttl=ip_statistics.IpDefaultTTL;
+
+ sk->protinfo.af_inet.mc_loop=1;
+ sk->protinfo.af_inet.mc_ttl=1;
+ sk->protinfo.af_inet.mc_index=0;
+ sk->protinfo.af_inet.mc_list=NULL;
+
+ atomic_inc(&inet_sock_nr);
- sk->ip_mc_loop=1;
- sk->ip_mc_ttl=1;
- sk->ip_mc_index=0;
- sk->ip_mc_list=NULL;
-
if (sk->num) {
/* It assumes that any protocol which allows
* the user to assign a number at socket
@@ -436,7 +421,8 @@ static int inet_create(struct socket *sock, int protocol)
if (sk->prot->init) {
int err = sk->prot->init(sk);
if (err != 0) {
- destroy_sock(sk);
+ sk->dead = 1;
+ inet_sock_release(sk);
return(err);
}
}
@@ -465,18 +451,13 @@ do_oom:
* should refer to it.
*/
-int inet_release(struct socket *sock, struct socket *peersock)
+int inet_release(struct socket *sock)
{
struct sock *sk = sock->sk;
if (sk) {
long timeout;
- /* Begin closedown and wake up sleepers. */
- if (sock->state != SS_UNCONNECTED)
- sock->state = SS_DISCONNECTING;
- sk->state_change(sk);
-
/* Applications forget to leave groups before exiting */
ip_mc_drop_socket(sk);
@@ -494,7 +475,6 @@ int inet_release(struct socket *sock, struct socket *peersock)
timeout = MAX_SCHEDULE_TIMEOUT;
}
sock->sk = NULL;
- sk->socket = NULL;
sk->prot->close(sk, timeout);
}
return(0);
@@ -506,27 +486,25 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk=sock->sk;
unsigned short snum;
int chk_addr_ret;
+ int err;
/* If the socket has its own bind function then use it. (RAW) */
if(sk->prot->bind)
return sk->prot->bind(sk, uaddr, addr_len);
-
- /* Check these errors (active socket, bad address length, double bind). */
- if ((sk->state != TCP_CLOSE) ||
- (addr_len < sizeof(struct sockaddr_in)) ||
- (sk->num != 0))
+
+ if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
if (addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) {
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
- /* Superuser may bind to any address to allow transparent proxying. */
- if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN))
-#endif
- return -EADDRNOTAVAIL; /* Source address MUST be ours! */
+ return -EADDRNOTAVAIL; /* Source address MUST be ours! */
}
+ snum = ntohs(addr->sin_port);
+ if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+ return -EACCES;
+
/* We keep a pair of addresses. rcv_saddr is the one
* used by hash lookups, and saddr is used for transmit.
*
@@ -534,63 +512,67 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
* would be illegal to use them (multicast/broadcast) in
* which case the sending device address is used.
*/
+ lock_sock(sk);
+
+ /* Check these errors (active socket, double bind). */
+ err = -EINVAL;
+ if ((sk->state != TCP_CLOSE) ||
+ (sk->num != 0))
+ goto out;
+
sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
- if(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
+ if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
sk->saddr = 0; /* Use device */
- snum = ntohs(addr->sin_port);
-#ifdef CONFIG_IP_MASQUERADE
- /* The kernel masquerader needs some ports. */
- if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END))
- return -EADDRINUSE;
-#endif
- if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
- return -EACCES;
-
/* Make sure we are allowed to bind here. */
- if (sk->prot->get_port(sk, snum) != 0)
- return -EADDRINUSE;
+ if (sk->prot->get_port(sk, snum) != 0) {
+ sk->saddr = sk->rcv_saddr = 0;
+ err = -EADDRINUSE;
+ goto out;
+ }
sk->sport = htons(sk->num);
sk->daddr = 0;
sk->dport = 0;
sk->prot->hash(sk);
- dst_release(sk->dst_cache);
- sk->dst_cache=NULL;
- return(0);
+ sk_dst_reset(sk);
+ err = 0;
+out:
+ release_sock(sk);
+ return err;
}
int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
int addr_len, int flags)
{
struct sock *sk=sock->sk;
- int err;
- if (inet_autobind(sk) != 0)
+ if (uaddr->sa_family == AF_UNSPEC)
+ return sk->prot->disconnect(sk, flags);
+
+ if (sk->num==0 && inet_autobind(sk) != 0)
return -EAGAIN;
- if (sk->prot->connect == NULL)
- return -EOPNOTSUPP;
- err = sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
- if (err < 0)
- return err;
- return(0);
+ return sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
}
static void inet_wait_for_connect(struct sock *sk)
{
DECLARE_WAITQUEUE(wait, current);
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(sk->sleep, &wait);
- current->state = TASK_INTERRUPTIBLE;
- while (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
+
+ while ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
if (signal_pending(current))
break;
if (sk->err)
break;
+ release_sock(sk);
schedule();
- current->state = TASK_INTERRUPTIBLE;
+ lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
}
@@ -605,68 +587,71 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
struct sock *sk=sock->sk;
int err;
- if(sock->state != SS_UNCONNECTED && sock->state != SS_CONNECTING) {
- if(sock->state == SS_CONNECTED)
- return -EISCONN;
- return -EINVAL;
+ if (uaddr->sa_family == AF_UNSPEC) {
+ lock_sock(sk);
+ err = sk->prot->disconnect(sk, flags);
+ sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
+ release_sock(sk);
+ return err;
}
- if(sock->state == SS_CONNECTING) {
- /* Note: tcp_connected contains SYN_RECV, which may cause
- bogus results here. -AK */
- if(tcp_connected(sk->state)) {
+ lock_sock(sk);
+ switch (sock->state) {
+ default:
+ err = -EINVAL;
+ goto out;
+ case SS_CONNECTED:
+ err = -EISCONN;
+ goto out;
+ case SS_CONNECTING:
+ if (tcp_established(sk->state)) {
sock->state = SS_CONNECTED;
- return 0;
+ err = 0;
+ goto out;
}
- if (sk->zapped || sk->err)
+ if (sk->err)
goto sock_error;
+ err = -EALREADY;
if (flags & O_NONBLOCK)
- return -EALREADY;
- } else {
- if (sk->prot->connect == NULL)
- return -EOPNOTSUPP;
-
- /* We may need to bind the socket. */
- if (inet_autobind(sk) != 0)
- return -EAGAIN;
-
+ goto out;
+ break;
+ case SS_UNCONNECTED:
err = sk->prot->connect(sk, uaddr, addr_len);
- /* Note: there is a theoretical race here when an wake up
- occurred before inet_wait_for_connect is entered. In 2.3
- the wait queue setup should be moved before the low level
- connect call. -AK*/
if (err < 0)
- return err;
+ goto out;
sock->state = SS_CONNECTING;
}
-
- if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING)
+
+ if (sk->state > TCP_FIN_WAIT2)
goto sock_error;
- if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
- return -EINPROGRESS;
+ err = -EINPROGRESS;
+ if (!tcp_established(sk->state) && (flags & O_NONBLOCK))
+ goto out;
- if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
+ if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
inet_wait_for_connect(sk);
+ err = -ERESTARTSYS;
if (signal_pending(current))
- return -ERESTARTSYS;
+ goto out;
}
- sock->state = SS_CONNECTED;
- if ((sk->state != TCP_ESTABLISHED) && sk->err)
+ if (sk->err && !tcp_established(sk->state))
goto sock_error;
- return 0;
+ sock->state = SS_CONNECTED;
+ err = 0;
+out:
+ release_sock(sk);
+ return err;
-sock_error:
- /* This is ugly but needed to fix a race in the ICMP error handler */
- if (sk->zapped && sk->state != TCP_CLOSE) {
- lock_sock(sk);
- tcp_set_state(sk, TCP_CLOSE);
- release_sock(sk);
- sk->zapped = 0;
- }
+sock_error:
+ err = sock_error(sk) ? : -ECONNABORTED;
sock->state = SS_UNCONNECTED;
- return sock_error(sk);
+ if (sk->prot->disconnect(sk, O_NONBLOCK))
+ sock->state = SS_DISCONNECTING;
+ release_sock(sk);
+
+ return err;
}
/*
@@ -675,62 +660,27 @@ sock_error:
int inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
- struct sock *sk1 = sock->sk, *sk2;
- struct sock *newsk = newsock->sk;
+ struct sock *sk1 = sock->sk;
+ struct sock *sk2;
int err = -EINVAL;
- if (sock->state != SS_UNCONNECTED || !(sock->flags & SO_ACCEPTCON))
+ if((sk2 = sk1->prot->accept(sk1,flags,&err)) == NULL)
goto do_err;
- err = -EOPNOTSUPP;
- if (sk1->prot->accept == NULL)
- goto do_err;
-
- if((sk2 = sk1->prot->accept(sk1,flags)) == NULL)
- goto do_sk1_err;
+ lock_sock(sk2);
- /*
- * We've been passed an extra socket.
- * We need to free it up because the tcp module creates
- * its own when it accepts one.
- */
- sk2->sleep = newsk->sleep;
+ BUG_TRAP((1<<sk2->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE));
+ write_lock_irq(&sk2->callback_lock);
+ sk2->sleep = &newsock->wait;
newsock->sk = sk2;
sk2->socket = newsock;
- newsk->socket = NULL;
-
- if (flags & O_NONBLOCK)
- goto do_half_success;
-
- if(sk2->state == TCP_ESTABLISHED)
- goto do_full_success;
- if(sk2->err > 0)
- goto do_connect_err;
- err = -ECONNABORTED;
- if (sk2->state == TCP_CLOSE)
- goto do_bad_connection;
-do_full_success:
- destroy_sock(newsk);
+ write_unlock_irq(&sk2->callback_lock);
+
newsock->state = SS_CONNECTED;
+ release_sock(sk2);
return 0;
-do_half_success:
- destroy_sock(newsk);
- return(0);
-
-do_connect_err:
- err = sock_error(sk2);
-do_bad_connection:
- sk2->sleep = NULL;
- sk2->socket = NULL;
- destroy_sock(sk2);
- newsock->sk = newsk;
- newsk->socket = newsock;
- return err;
-
-do_sk1_err:
- err = sock_error(sk1);
do_err:
return err;
}
@@ -748,7 +698,7 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin_family = AF_INET;
if (peer) {
- if (!tcp_connected(sk->state))
+ if (!sk->dport)
return -ENOTCONN;
sin->sin_port = sk->dport;
sin->sin_addr.s_addr = sk->daddr;
@@ -772,12 +722,9 @@ int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int addr_len = 0;
int err;
- if (sock->flags & SO_ACCEPTCON)
- return -EINVAL;
- if (sk->prot->recvmsg == NULL)
- return -EOPNOTSUPP;
/* We may need to bind the socket. */
- if (inet_autobind(sk) != 0)
+ /* It is pretty strange. I would return error in this case --ANK */
+ if (sk->num==0 && inet_autobind(sk) != 0)
return -EAGAIN;
err = sk->prot->recvmsg(sk, msg, size, flags&MSG_DONTWAIT,
flags&~MSG_DONTWAIT, &addr_len);
@@ -792,27 +739,17 @@ int inet_sendmsg(struct socket *sock, struct msghdr *msg, int size,
{
struct sock *sk = sock->sk;
- if (sk->shutdown & SEND_SHUTDOWN) {
- if (!(msg->msg_flags&MSG_NOSIGNAL))
- send_sig(SIGPIPE, current, 1);
- return -EPIPE;
- }
- if (sk->prot->sendmsg == NULL)
- return -EOPNOTSUPP;
- if(sk->err)
- return sock_error(sk);
-
/* We may need to bind the socket. */
- if (inet_autobind(sk) != 0)
+ if (sk->num==0 && inet_autobind(sk) != 0)
return -EAGAIN;
return sk->prot->sendmsg(sk, msg, size);
}
-
int inet_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
+ int err;
/* This should really check to make sure
* the socket is a TCP socket. (WHY AC...)
@@ -824,19 +761,24 @@ int inet_shutdown(struct socket *sock, int how)
return -EINVAL;
if (!sk)
return -ENOTCONN;
- if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
+
+ lock_sock(sk);
+ if (sock->state == SS_CONNECTING && tcp_established(sk->state))
sock->state = SS_CONNECTED;
- if (!tcp_connected(sk->state))
- return -ENOTCONN;
+ err = -ENOTCONN;
+ if (!tcp_connected(sk->state))
+ goto out;
sk->shutdown |= how;
if (sk->prot->shutdown)
sk->prot->shutdown(sk, how);
/* Wake up anyone sleeping in poll. */
sk->state_change(sk);
- return(0);
+ err = 0;
+out:
+ release_sock(sk);
+ return err;
}
-
unsigned int inet_poll(struct file * file, struct socket *sock, poll_table *wait)
{
struct sock *sk = sock->sk;
@@ -892,15 +834,6 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGARP:
case SIOCSARP:
return(arp_ioctl(cmd,(void *) arg));
- case SIOCDRARP:
- case SIOCGRARP:
- case SIOCSRARP:
-#ifdef CONFIG_KMOD
- if (rarp_ioctl_hook == NULL)
- request_module("rarp");
-#endif
- if (rarp_ioctl_hook != NULL)
- return(rarp_ioctl_hook(cmd,(void *) arg));
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFBRDADDR:
@@ -915,8 +848,11 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return(devinet_ioctl(cmd,(void *) arg));
case SIOCGIFBR:
case SIOCSIFBR:
-#ifdef CONFIG_BRIDGE
- return(br_ioctl(cmd,(void *) arg));
+#ifdef CONFIG_BRIDGE
+ lock_kernel();
+ err = br_ioctl(cmd,(void *) arg);
+ unlock_kernel();
+ return err;
#else
return -ENOPKG;
#endif
@@ -924,7 +860,10 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCADDDLCI:
case SIOCDELDLCI:
#ifdef CONFIG_DLCI
- return(dlci_ioctl(cmd, (void *) arg));
+ lock_kernel();
+ err = dlci_ioctl(cmd, (void *) arg);
+ unlock_kernel();
+ return err;
#endif
#ifdef CONFIG_DLCI_MODULE
@@ -934,8 +873,12 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
request_module("dlci");
#endif
- if (dlci_ioctl_hook)
- return((*dlci_ioctl_hook)(cmd, (void *) arg));
+ if (dlci_ioctl_hook) {
+ lock_kernel();
+ err = (*dlci_ioctl_hook)(cmd, (void *) arg);
+ unlock_kernel();
+ return err;
+ }
#endif
return -ENOPKG;
@@ -960,7 +903,6 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct proto_ops inet_stream_ops = {
PF_INET,
- sock_no_dup,
inet_release,
inet_bind,
inet_stream_connect,
@@ -975,13 +917,13 @@ struct proto_ops inet_stream_ops = {
inet_getsockopt,
sock_no_fcntl,
inet_sendmsg,
- inet_recvmsg
+ inet_recvmsg,
+ sock_no_mmap
};
struct proto_ops inet_dgram_ops = {
PF_INET,
- sock_no_dup,
inet_release,
inet_bind,
inet_dgram_connect,
@@ -996,7 +938,8 @@ struct proto_ops inet_dgram_ops = {
inet_getsockopt,
sock_no_fcntl,
inet_sendmsg,
- inet_recvmsg
+ inet_recvmsg,
+ sock_no_mmap
};
struct net_proto_family inet_family_ops = {
@@ -1006,14 +949,6 @@ struct net_proto_family inet_family_ops = {
#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_INET_RARP
-static struct proc_dir_entry proc_net_rarp = {
- PROC_NET_RARP, 4, "rarp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rarp_get_info
-};
-#endif /* RARP */
static struct proc_dir_entry proc_net_raw = {
PROC_NET_RAW, 3, "raw",
S_IFREG | S_IRUGO, 1, 0, 0,
@@ -1060,7 +995,7 @@ extern void tcp_v4_init(struct net_proto_family *);
* Called by socket.c on kernel startup.
*/
-__initfunc(void inet_proto_init(struct net_proto *pro))
+void __init inet_proto_init(struct net_proto *pro)
{
struct sk_buff *dummy_skb;
struct inet_protocol *p;
@@ -1127,34 +1062,17 @@ __initfunc(void inet_proto_init(struct net_proto *pro))
#endif
/*
- * Set the firewalling up
- */
-#if defined(CONFIG_IP_FIREWALL)
- ip_fw_init();
-#endif
-
-#ifdef CONFIG_IP_MASQUERADE
- ip_masq_init();
-#endif
-
- /*
* Initialise the multicast router
*/
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
-#ifdef CONFIG_INET_RARP
- rarp_ioctl_hook = rarp_ioctl;
-#endif
/*
* Create all the /proc entries.
*/
#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_INET_RARP
- proc_net_register(&proc_net_rarp);
-#endif /* RARP */
proc_net_register(&proc_net_raw);
proc_net_register(&proc_net_snmp);
proc_net_register(&proc_net_netstat);