patch-1.3.36 linux/net/ipv4/af_inet.c
Next file: linux/net/ipv4/icmp.c
Previous file: linux/net/ipv4/Makefile
Back to the patch index
Back to the overall index
- Lines: 368
- Date:
Mon Oct 23 13:52:27 1995
- Orig file:
v1.3.35/linux/net/ipv4/af_inet.c
- Orig date:
Tue Oct 10 18:46:39 1995
diff -u --recursive --new-file v1.3.35/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
@@ -31,7 +31,7 @@
* Alan Cox : bind() shouldn't abort existing but dead
* sockets. Stops FTP netin:.. I hope.
* Alan Cox : bind() works correctly for RAW sockets. Note
- * that FreeBSD at least is broken in this respect
+ * that FreeBSD at least was broken in this respect
* so be careful with compatibility tests...
* Alan Cox : routing cache support
* Alan Cox : memzero the socket structure for compactness.
@@ -44,6 +44,7 @@
* Alan Cox : BSD rather than common sense interpretation of
* listen.
* Germano Caronni : Assorted small races.
+ * Alan Cox : sendmsg/recvmsg basic support.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -141,7 +142,10 @@
base += PROT_SOCK+(start % 1024);
}
- /* Now look through the entire array and try to find an empty ptr. */
+ /*
+ * Now look through the entire array and try to find an empty ptr.
+ */
+
for(i=0; i < SOCK_ARRAY_SIZE; i++)
{
j = 0;
@@ -178,8 +182,7 @@
void put_sock(unsigned short num, struct sock *sk)
{
- struct sock *sk1;
- struct sock *sk2;
+ struct sock **skp, *tmp;
int mask;
unsigned long flags;
@@ -190,7 +193,10 @@
sk->next = NULL;
num = num &(SOCK_ARRAY_SIZE -1);
- /* We can't have an interrupt re-enter here. */
+ /*
+ * We can't have an interrupt re-enter here.
+ */
+
save_flags(flags);
cli();
@@ -204,40 +210,29 @@
restore_flags(flags);
return;
}
+
restore_flags(flags);
for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask)
{
- if ((mask & sk->saddr) &&
- (mask & sk->saddr) != (mask & 0xffffffff))
+ if ((mask & sk->rcv_saddr) &&
+ (mask & sk->rcv_saddr) != (mask & 0xffffffff))
{
mask = mask << 8;
break;
}
}
+
+ /*
+ * add the socket to the sock_array[]..
+ */
+ skp = sk->prot->sock_array + num;
cli();
- sk1 = sk->prot->sock_array[num];
- for(sk2 = sk1; sk2 != NULL; sk2=sk2->next)
- {
- if (!(sk2->saddr & mask))
- {
- if (sk2 == sk1)
- {
- sk->next = sk->prot->sock_array[num];
- sk->prot->sock_array[num] = sk;
- sti();
- return;
- }
- sk->next = sk2;
- sk1->next= sk;
- sti();
- return;
- }
- sk1 = sk2;
+ while ((tmp = *skp) != NULL) {
+ if (!(tmp->rcv_saddr & mask))
+ break;
}
-
- /* Goes at the end. */
- sk->next = NULL;
- sk1->next = sk;
+ sk->next = tmp;
+ *skp = sk;
sti();
}
@@ -288,23 +283,37 @@
sk->inuse = 1; /* just to be safe. */
- /* In case it's sleeping somewhere. */
+ /*
+ * In case it's sleeping somewhere.
+ */
+
if (!sk->dead)
sk->write_space(sk);
remove_sock(sk);
- /* Now we can no longer get new packets. */
+ /*
+ * Now we can no longer get new packets or once the
+ * timers are killed, send them.
+ */
+
delete_timer(sk);
- /* Nor send them */
del_timer(&sk->retransmit_timer);
- while ((skb = tcp_dequeue_partial(sk)) != NULL) {
+ /*
+ * Drain any partial frames
+ */
+
+ while ((skb = tcp_dequeue_partial(sk)) != NULL)
+ {
IS_SKB(skb);
kfree_skb(skb, FREE_WRITE);
}
- /* Cleanup up the write buffer. */
+ /*
+ * Cleanup up the write buffer.
+ */
+
while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
IS_SKB(skb);
kfree_skb(skb, FREE_WRITE);
@@ -334,7 +343,10 @@
}
}
- /* Now we need to clean up the send head. */
+ /*
+ * Now we need to clean up the send head.
+ */
+
cli();
for(skb = sk->send_head; skb != NULL; )
{
@@ -344,8 +356,8 @@
* We need to remove skb from the transmit queue,
* or maybe the arp queue.
*/
- if (skb->next && skb->prev) {
-/* printk("destroy_sock: unlinked skb\n");*/
+ if (skb->next && skb->prev)
+ {
IS_SKB(skb);
skb_unlink(skb);
}
@@ -357,15 +369,20 @@
sk->send_head = NULL;
sti();
- /* And now the backlog. */
+ /*
+ * Now the backlog.
+ */
+
while((skb=skb_dequeue(&sk->back_log))!=NULL)
{
/* this should [almost] never happen. */
-/* printk("cleaning back_log\n");*/
kfree_skb(skb, FREE_READ);
}
- /* Now if it has a half accepted/ closed socket. */
+ /*
+ * Now if it has a half accepted/ closed socket.
+ */
+
if (sk->pair)
{
sk->pair->dead = 1;
@@ -681,7 +698,8 @@
sk->inuse = 0;
sk->delay_acks = 0;
sk->daddr = 0;
- sk->saddr = 0 /* ip_my_addr() */;
+ sk->saddr = 0;
+ sk->rcv_saddr = 0;
sk->err = 0;
sk->next = NULL;
sk->pair = NULL;
@@ -778,7 +796,7 @@
}
/*
- * Return 1 if we still have things to send in our buffers.
+ * Return 1 if we still have things to send in our buffers.
*/
static inline int closing(struct sock * sk)
@@ -903,12 +921,25 @@
}
chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
- if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST)
+ if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST)
return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
-
+
if (chk_addr_ret || addr->sin_addr.s_addr == 0)
- sk->saddr = addr->sin_addr.s_addr;
-
+ {
+ /*
+ * We keep a pair of addresses. rcv_saddr is the one
+ * used by get_sock_*(), and saddr is used for transmit.
+ *
+ * In the BSD API these are the same except where it
+ * would be illegal to use (multicast/broadcast) in
+ * which case the sending device address is used.
+ */
+ sk->rcv_saddr = addr->sin_addr.s_addr;
+ if(chk_addr_ret==IS_MULTICAST||chk_addr_ret==IS_BROADCAST)
+ sk->saddr = 0; /* Use device */
+ else
+ sk->saddr = addr->sin_addr.s_addr;
+ }
if(sock->type != SOCK_RAW)
{
/* Make sure we are allowed to bind here. */
@@ -927,7 +958,7 @@
if (sk2->num != snum)
continue; /* more than one */
- if (sk2->saddr != sk->saddr)
+ if (sk2->rcv_saddr != sk->rcv_saddr)
continue; /* socket per slot ! -FB */
if (!sk2->reuse || sk2->state==TCP_LISTEN)
{
@@ -1148,11 +1179,14 @@
}
else
{
+ __u32 addr = sk->rcv_saddr;
+ if (!addr) {
+ addr = sk->saddr;
+ if (!addr)
+ addr = ip_my_addr();
+ }
sin->sin_port = sk->dummy_th.source;
- if (sk->saddr == 0)
- sin->sin_addr.s_addr = ip_my_addr();
- else
- sin->sin_addr.s_addr = sk->saddr;
+ sin->sin_addr.s_addr = addr;
}
*uaddr_len = sizeof(*sin);
return(0);
@@ -1179,6 +1213,21 @@
(struct sockaddr_in*)sin, addr_len));
}
+static int inet_recvmsg(struct socket *sock, struct msghdr *ubuf, int size, int noblock,
+ int flags, int *addr_len )
+{
+ struct sock *sk = (struct sock *) sock->data;
+
+ if (sk->prot->recvmsg == NULL)
+ return(-EOPNOTSUPP);
+ if(sk->err)
+ return inet_error(sk);
+ /* We may need to bind the socket. */
+ if(inet_autobind(sk)!=0)
+ return(-EAGAIN);
+ return(sk->prot->recvmsg(sk, ubuf, size, noblock, flags,addr_len));
+}
+
static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock,
unsigned flags)
@@ -1241,6 +1290,26 @@
(struct sockaddr_in *)sin, addr_len));
}
+static int inet_sendmsg(struct socket *sock, struct msghdr *msg, int size, int noblock,
+ int flags)
+{
+ struct sock *sk = (struct sock *) sock->data;
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ if (sk->prot->sendmsg == NULL)
+ return(-EOPNOTSUPP);
+ if(sk->err)
+ return inet_error(sk);
+ /* We may need to bind the socket. */
+ if(inet_autobind(sk)!=0)
+ return -EAGAIN;
+ return(sk->prot->sendmsg(sk, msg, size, noblock, flags));
+
+}
+
static int inet_shutdown(struct socket *sock, int how)
{
@@ -1414,8 +1483,8 @@
if(s->dead && (s->state == TCP_CLOSE))
continue;
/* local address matches? */
- if (s->saddr) {
- if (s->saddr != laddr)
+ if (s->rcv_saddr) {
+ if (s->rcv_saddr != laddr)
continue;
score++;
}
@@ -1464,7 +1533,7 @@
continue;
if(s->daddr && s->daddr!=raddr)
continue;
- if(s->saddr && s->saddr!=laddr)
+ if(s->rcv_saddr && s->rcv_saddr != laddr)
continue;
return(s);
}
@@ -1507,7 +1576,7 @@
continue;
if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
continue;
- if(s->saddr && s->saddr!=laddr)
+ if(s->rcv_saddr && s->rcv_saddr != laddr)
continue;
return(s);
}
@@ -1540,6 +1609,8 @@
inet_setsockopt,
inet_getsockopt,
inet_fcntl,
+ inet_sendmsg,
+ inet_recvmsg
};
extern unsigned long seq_offset;
@@ -1554,7 +1625,7 @@
int i;
- printk("Swansea University Computer Society TCP/IP for NET3.031 (Snapshot #4)\n");
+ printk("Swansea University Computer Society TCP/IP for NET3.032\n");
/*
* Tell SOCKET that we are alive...
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this