Commit de0eab26 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.6

parent 37b4c9bd
VERSION = 1 VERSION = 1
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 5 SUBLEVEL = 6
all: Version zImage all: Version zImage
......
...@@ -201,9 +201,10 @@ static unsigned int d_link_debug = D_LINK_DEBUG; ...@@ -201,9 +201,10 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
/* /*
* Index to functions, as function prototypes. * Index to functions, as function prototypes.
*/ */
#if 0
/* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */ /* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */
static unsigned long d_link_rspace(struct sock *sk); static unsigned long d_link_rspace(struct sock *sk);
#endif
/* Routines used internally. (See "convenience macros") */ /* Routines used internally. (See "convenience macros") */
static int d_link_read_status(struct device *dev); static int d_link_read_status(struct device *dev);
...@@ -689,6 +690,10 @@ adapter_init(struct device *dev) ...@@ -689,6 +690,10 @@ adapter_init(struct device *dev)
sti(); sti();
} }
#if 0
/*
* The new router code (coming soon 8-) ) will fix this properly.
*/
#define D_LINK_MIN_WINDOW 1024 #define D_LINK_MIN_WINDOW 1024
#define D_LINK_MAX_WINDOW 2048 #define D_LINK_MAX_WINDOW 2048
#define D_LINK_TCP_WINDOW_DIFF 1024 #define D_LINK_TCP_WINDOW_DIFF 1024
...@@ -724,3 +729,6 @@ d_link_rspace(struct sock *sk) ...@@ -724,3 +729,6 @@ d_link_rspace(struct sock *sk)
} }
return(0); return(0);
} }
#endif
...@@ -644,32 +644,7 @@ depca_probe1(struct device *dev, short ioaddr) ...@@ -644,32 +644,7 @@ depca_probe1(struct device *dev, short ioaddr)
dev->mem_start = 0; dev->mem_start = 0;
/* Fill in the generic field of the device structure. */ /* Fill in the generic field of the device structure. */
for (i = 0; i < DEV_NUMBUFFS; i++) { ether_setup(dev);
dev->buffs[i] = NULL;
}
dev->hard_header = eth_header;
dev->add_arp = eth_add_arp;
dev->queue_xmit = dev_queue_xmit;
dev->rebuild_header = eth_rebuild_header;
dev->type_trans = eth_type_trans;
dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN;
dev->mtu = 1500; /* eth_mtu */
dev->addr_len = ETH_ALEN;
for (i = 0; i < dev->addr_len; i++) {
dev->broadcast[i]=0xff;
}
/* New-style flags. */
dev->flags = IFF_BROADCAST;
dev->family = AF_INET;
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
} }
} else { } else {
status = -ENXIO; status = -ENXIO;
...@@ -832,14 +807,6 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -832,14 +807,6 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
return 0; return 0;
} }
/* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb->data, dev)) {
skb->dev = dev;
arp_queue (skb);
return 0;
}
skb->arp=1;
if (skb->len <= 0) { if (skb->len <= 0) {
return 0; return 0;
} }
......
...@@ -1030,6 +1030,12 @@ int sl_set_mac_address(struct device *dev, void *addr) ...@@ -1030,6 +1030,12 @@ int sl_set_mac_address(struct device *dev, void *addr)
memcpy_fromfs(dev->dev_addr,addr,7); /* addr is an AX.25 shifted ASCII mac address */ memcpy_fromfs(dev->dev_addr,addr,7); /* addr is an AX.25 shifted ASCII mac address */
return 0; return 0;
} }
static int sl_set_dev_mac_address(struct device *dev, void *addr)
{
memcpy(dev->dev_addr,addr,7);
return 0;
}
#endif #endif
...@@ -1144,7 +1150,7 @@ slip_init(struct device *dev) ...@@ -1144,7 +1150,7 @@ slip_init(struct device *dev)
dev->get_stats = sl_get_stats; dev->get_stats = sl_get_stats;
#ifdef HAVE_SET_MAC_ADDR #ifdef HAVE_SET_MAC_ADDR
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
dev->set_mac_address = sl_set_mac_address; dev->set_mac_address = sl_set_dev_mac_address;
#endif #endif
#endif #endif
dev->hard_header_len = 0; dev->hard_header_len = 0;
......
...@@ -68,7 +68,7 @@ struct sk_buff { ...@@ -68,7 +68,7 @@ struct sk_buff {
used, used,
free, free,
arp; arp;
unsigned char tries,lock; unsigned char tries,lock,localroute;
unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
unsigned long padding[0]; unsigned long padding[0];
unsigned char data[0]; unsigned char data[0];
......
...@@ -42,6 +42,7 @@ struct linger { ...@@ -42,6 +42,7 @@ struct linger {
/* Flags we can use with send/ and recv. */ /* Flags we can use with send/ and recv. */
#define MSG_OOB 1 #define MSG_OOB 1
#define MSG_PEEK 2 #define MSG_PEEK 2
#define MSG_DONTROUTE 4
/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
#define SOL_SOCKET 1 #define SOL_SOCKET 1
......
...@@ -364,17 +364,6 @@ NORET_TYPE void do_exit(long code) ...@@ -364,17 +364,6 @@ NORET_TYPE void do_exit(long code)
sem_exit(); sem_exit();
if (current->shm) if (current->shm)
shm_exit(); shm_exit();
free_page_tables(current);
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
forget_original_parent(current);
iput(current->pwd);
current->pwd = NULL;
iput(current->root);
current->root = NULL;
iput(current->executable);
current->executable = NULL;
/* Release all of the old mmap stuff. */ /* Release all of the old mmap stuff. */
{ {
...@@ -390,17 +379,28 @@ NORET_TYPE void do_exit(long code) ...@@ -390,17 +379,28 @@ NORET_TYPE void do_exit(long code)
} }
} }
/* forget local segments */
__asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
: /* no outputs */
: "r" (0));
current->tss.ldt = 0;
if (current->ldt) { if (current->ldt) {
vfree(current->ldt); void * ldt = current->ldt;
current->ldt = NULL; current->ldt = NULL;
for (i=1 ; i<NR_TASKS ; i++) { vfree(ldt);
if (task[i] == current) {
set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, &default_ldt, 1);
load_ldt(i);
}
}
} }
free_page_tables(current);
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
forget_original_parent(current);
iput(current->pwd);
current->pwd = NULL;
iput(current->root);
current->root = NULL;
iput(current->executable);
current->executable = NULL;
/* /*
* Check to see if any process groups have become orphaned * Check to see if any process groups have become orphaned
* as a result of our exiting, and if they have any stopped * as a result of our exiting, and if they have any stopped
......
...@@ -549,7 +549,7 @@ void dev_transmit(void) ...@@ -549,7 +549,7 @@ void dev_transmit(void)
for (dev = dev_base; dev != NULL; dev = dev->next) for (dev = dev_base; dev != NULL; dev = dev->next)
{ {
if (!dev->tbusy) { if (dev->flags != 0 && !dev->tbusy) {
/* /*
* Kick the device * Kick the device
*/ */
......
...@@ -284,7 +284,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -284,7 +284,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
if (*dev == NULL) if (*dev == NULL)
{ {
rt = ip_rt_route(daddr, &optmem, &src); if(skb->localroute)
rt = ip_rt_local(daddr, &optmem, &src);
else
rt = ip_rt_route(daddr, &optmem, &src);
if (rt == NULL) if (rt == NULL)
{ {
ip_statistics.IpOutNoRoutes++; ip_statistics.IpOutNoRoutes++;
...@@ -308,7 +311,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -308,7 +311,10 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
/* /*
* We still need the address of the first hop. * We still need the address of the first hop.
*/ */
rt = ip_rt_route(daddr, &optmem, &src); if(skb->localroute)
rt = ip_rt_local(daddr, &optmem, &src);
else
rt = ip_rt_route(daddr, &optmem, &src);
/* /*
* If the frame is from us and going off machine it MUST MUST MUST * If the frame is from us and going off machine it MUST MUST MUST
* have the output device ip address and never the loopback * have the output device ip address and never the loopback
......
...@@ -503,6 +503,7 @@ static int ipx_create(struct socket *sock, int protocol) ...@@ -503,6 +503,7 @@ static int ipx_create(struct socket *sock, int protocol)
sk->type=sock->type; sk->type=sock->type;
sk->ipx_type=0; /* General user level IPX */ sk->ipx_type=0; /* General user level IPX */
sk->debug=0; sk->debug=0;
sk->localroute=0;
memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr)); memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr));
memset(&sk->ipx_source_addr,'\0',sizeof(sk->ipx_source_addr)); memset(&sk->ipx_source_addr,'\0',sizeof(sk->ipx_source_addr));
...@@ -836,7 +837,7 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, ...@@ -836,7 +837,7 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
int size; int size;
ipx_route *rt; ipx_route *rt;
if(flags) if(flags&~MSG_DONTROUTE)
return -EINVAL; return -EINVAL;
if(len<0) if(len<0)
return -EINVAL; return -EINVAL;
...@@ -882,7 +883,8 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, ...@@ -882,7 +883,8 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
/* Find out where this has to go */ /* Find out where this has to go */
rt=ipxrtr_get_dev(sipx.sipx_network); rt=ipxrtr_get_dev(sipx.sipx_network);
if(rt==NULL) /* No suitable route - no gateways when not routing */
if(rt==NULL || ((flags&IPX_RT_ROUTED)&& ((flags&MSG_DONTROUTE)||sk->localroute)))
{ {
return -ENETUNREACH; return -ENETUNREACH;
} }
...@@ -917,7 +919,7 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, ...@@ -917,7 +919,7 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
skb->dev=rt->dev; skb->dev=rt->dev;
dev->hard_header(skb->data,skb->dev, dev->hard_header(skb->data,skb->dev,
(rt->flags&IPX_RT_BLUEBOOK)?ntohs(ETH_P_IPX):ntohs(len+sizeof(ipx_packet)), (rt->flags&IPX_RT_BLUEBOOK)?ETH_P_IPX:ETH_P_802_3),
(rt->flags&IPX_RT_ROUTED)?rt->router_node:sipx.sipx_node, (rt->flags&IPX_RT_ROUTED)?rt->router_node:sipx.sipx_node,
NULL, NULL,
len+sizeof(ipx_packet), len+sizeof(ipx_packet),
......
...@@ -142,143 +142,162 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -142,143 +142,162 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return(0); return(0);
} }
/*
* Send a RAW IP packet.
*/
/* This will do terrible things if len + ipheader + devheader > dev->mtu */ static int raw_sendto(struct sock *sk, unsigned char *from,
static int int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len)
raw_sendto(struct sock *sk, unsigned char *from, int len,
int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct device *dev=NULL; struct device *dev=NULL;
struct sockaddr_in sin; struct sockaddr_in sin;
int tmp; int tmp;
int err; int err;
DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n" DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
" usin=%X, addr_len = %d)\n", sk, from, len, noblock, " usin=%X, addr_len = %d)\n", sk, from, len, noblock,
flags, usin, addr_len)); flags, usin, addr_len));
/* Check the flags. */ /*
if (flags) return(-EINVAL); * Check the flags. Only MSG_DONTROUTE is permitted.
if (len < 0) return(-EINVAL); */
err=verify_area(VERIFY_READ,from,len); if (flags&MSG_DONTROUTE)
if(err) return(-EINVAL);
return err; if (len < 0)
/* Get and verify the address. */ return(-EINVAL);
if (usin) {
if (addr_len < sizeof(sin)) return(-EINVAL); err=verify_area(VERIFY_READ,from,len);
err=verify_area (VERIFY_READ, usin, sizeof (sin));
if(err) if(err)
return err; return err;
memcpy_fromfs(&sin, usin, sizeof(sin)); /*
if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL); * Get and verify the address.
} else { */
if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
sin.sin_family = AF_INET; if (usin)
sin.sin_port = sk->protocol; {
sin.sin_addr.s_addr = sk->daddr; if (addr_len < sizeof(sin))
} return(-EINVAL);
if (sin.sin_port == 0) sin.sin_port = sk->protocol; err=verify_area (VERIFY_READ, usin, sizeof (sin));
if(err)
return err;
memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET)
return(-EINVAL);
}
else
{
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);
sin.sin_family = AF_INET;
sin.sin_port = sk->protocol;
sin.sin_addr.s_addr = sk->daddr;
}
if (sin.sin_port == 0)
sin.sin_port = sk->protocol;
if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; return -EACCES;
sk->inuse = 1; sk->inuse = 1;
skb = NULL; skb = NULL;
while (skb == NULL) { while (skb == NULL)
if(sk->err!=0) {
{ if(sk->err!=0)
err= -sk->err; {
sk->err=0; err= -sk->err;
release_sock(sk); sk->err=0;
return(err); release_sock(sk);
} return(err);
}
skb = sk->prot->wmalloc(sk, skb = sk->prot->wmalloc(sk,
len + sk->prot->max_header, len + sk->prot->max_header,
0, GFP_KERNEL); 0, GFP_KERNEL);
if (skb == NULL) { if (skb == NULL)
int tmp; {
int tmp;
DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
if (noblock) DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
return(-EAGAIN); if (noblock)
tmp = sk->wmem_alloc; return(-EAGAIN);
release_sock(sk); tmp = sk->wmem_alloc;
cli(); release_sock(sk);
if (tmp <= sk->wmem_alloc) { cli();
interruptible_sleep_on(sk->sleep); if (tmp <= sk->wmem_alloc) {
if (current->signal & ~current->blocked) { interruptible_sleep_on(sk->sleep);
sti(); if (current->signal & ~current->blocked) {
return(-ERESTARTSYS); sti();
return(-ERESTARTSYS);
}
} }
sk->inuse = 1;
sti();
} }
sk->inuse = 1;
sti();
} }
} skb->sk = sk;
skb->sk = sk; skb->free = 1;
skb->localroute = sk->localroute | (flags&MSG_DONTROUTE);
skb->free = 1; tmp = sk->prot->build_header(skb, sk->saddr,
tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev, sin.sin_addr.s_addr, &dev,
sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl); sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
if (tmp < 0) { if (tmp < 0)
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); {
kfree_skb(skb,FREE_WRITE); DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
release_sock(sk); kfree_skb(skb,FREE_WRITE);
return(tmp); release_sock(sk);
} return(tmp);
}
/* verify_area(VERIFY_WRITE, from, len);*/ memcpy_fromfs(skb->data + tmp, from, len);
memcpy_fromfs(skb->data + tmp, from, len);
/* If we are using IPPROTO_RAW, we need to fill in the source address in /*
the IP header */ * If we are using IPPROTO_RAW, we need to fill in the source address in
* the IP header
*/
if(sk->protocol==IPPROTO_RAW) { if(sk->protocol==IPPROTO_RAW)
unsigned char *buff; {
struct iphdr *iph; unsigned char *buff;
struct iphdr *iph;
buff = skb->data; buff = skb->data;
buff += tmp; buff += tmp;
iph = (struct iphdr *)buff;
iph->saddr = sk->saddr;
}
skb->len = tmp + len; iph = (struct iphdr *)buff;
iph->saddr = sk->saddr;
}
skb->len = tmp + len;
sk->prot->queue_xmit(sk, dev, skb, 1); sk->prot->queue_xmit(sk, dev, skb, 1);
release_sock(sk); release_sock(sk);
return(len); return(len);
} }
static int static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags) unsigned flags)
{ {
return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0)); return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
} }
static void static void raw_close(struct sock *sk, int timeout)
raw_close(struct sock *sk, int timeout)
{ {
sk->inuse = 1; sk->inuse = 1;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n", DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
((struct inet_protocol *)sk->pair)->protocol)); ((struct inet_protocol *)sk->pair)->protocol));
if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0) if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n")); DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n"));
kfree_s((void *)sk->pair, sizeof (struct inet_protocol)); kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
sk->pair = NULL; sk->pair = NULL;
release_sock(sk); release_sock(sk);
} }
......
...@@ -573,6 +573,42 @@ struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned l ...@@ -573,6 +573,42 @@ struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned l
return NULL; return NULL;
} }
struct rtable * ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr)
{
struct rtable *rt;
for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next)
{
/*
* No routed addressing.
*/
if (rt->rt_flags&RTF_GATEWAY)
continue;
if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
break;
/*
* broadcast addresses can be special cases..
*/
if ((rt->rt_dev->flags & IFF_BROADCAST) &&
rt->rt_dev->pa_brdaddr == daddr)
break;
}
if(src_addr!=NULL)
*src_addr= rt->rt_dev->pa_addr;
if (daddr == rt->rt_dev->pa_addr) {
if ((rt = rt_loopback) == NULL)
goto no_route;
}
rt->rt_use++;
return rt;
no_route:
return NULL;
}
/* /*
* Backwards compatibility * Backwards compatibility
*/ */
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* *
* Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Fixes:
* Alan Cox : Reformatted. Added ip_rt_local()
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -23,17 +25,18 @@ ...@@ -23,17 +25,18 @@
/* This is an entry in the IP routing table. */ /* This is an entry in the IP routing table. */
struct rtable { struct rtable
struct rtable *rt_next; {
unsigned long rt_dst; struct rtable *rt_next;
unsigned long rt_mask; unsigned long rt_dst;
unsigned long rt_gateway; unsigned long rt_mask;
unsigned char rt_flags; unsigned long rt_gateway;
unsigned char rt_metric; unsigned char rt_flags;
short rt_refcnt; unsigned char rt_metric;
unsigned long rt_use; short rt_refcnt;
unsigned short rt_mss, rt_mtu; unsigned long rt_use;
struct device *rt_dev; unsigned short rt_mss, rt_mtu;
struct device *rt_dev;
}; };
...@@ -41,6 +44,7 @@ extern void ip_rt_flush(struct device *dev); ...@@ -41,6 +44,7 @@ extern void ip_rt_flush(struct device *dev);
extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask, extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask,
unsigned long gw, struct device *dev); unsigned long gw, struct device *dev);
extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr); extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr);
extern struct rtable *ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr);
extern int rt_get_info(char * buffer, char **start, off_t offset, int length); extern int rt_get_info(char * buffer, char **start, off_t offset, int length);
extern int ip_rt_ioctl(unsigned int cmd, void *arg); extern int ip_rt_ioctl(unsigned int cmd, void *arg);
......
...@@ -489,7 +489,8 @@ int sock_setsockopt(struct sock *sk, int level, int optname, ...@@ -489,7 +489,8 @@ int sock_setsockopt(struct sock *sk, int level, int optname,
case SO_DEBUG: case SO_DEBUG:
sk->debug=val?1:0; sk->debug=val?1:0;
case SO_DONTROUTE: /* Still to be implemented */ case SO_DONTROUTE:
sk->localroute=val?1:0;
return(0); return(0);
case SO_BROADCAST: case SO_BROADCAST:
sk->broadcast=val?1:0; sk->broadcast=val?1:0;
...@@ -580,8 +581,8 @@ int sock_getsockopt(struct sock *sk, int level, int optname, ...@@ -580,8 +581,8 @@ int sock_getsockopt(struct sock *sk, int level, int optname,
val = sk->debug; val = sk->debug;
break; break;
case SO_DONTROUTE: /* One last option to implement */ case SO_DONTROUTE:
val = 0; val = sk->localroute;
break; break;
case SO_BROADCAST: case SO_BROADCAST:
...@@ -852,6 +853,7 @@ inet_create(struct socket *sock, int protocol) ...@@ -852,6 +853,7 @@ inet_create(struct socket *sock, int protocol)
sk->send_head = NULL; sk->send_head = NULL;
sk->timeout = 0; sk->timeout = 0;
sk->broadcast = 0; sk->broadcast = 0;
sk->localroute = 0;
sk->timer.data = (unsigned long)sk; sk->timer.data = (unsigned long)sk;
sk->timer.function = &net_timer; sk->timer.function = &net_timer;
skb_queue_head_init(&sk->back_log); skb_queue_head_init(&sk->back_log);
......
...@@ -132,6 +132,7 @@ struct sock { ...@@ -132,6 +132,7 @@ struct sock {
unsigned short rcvbuf; unsigned short rcvbuf;
unsigned short sndbuf; unsigned short sndbuf;
unsigned short type; unsigned short type;
unsigned char localroute; /* Route locally only */
#ifdef CONFIG_IPX #ifdef CONFIG_IPX
ipx_address ipx_source_addr,ipx_dest_addr; ipx_address ipx_source_addr,ipx_dest_addr;
unsigned short ipx_type; unsigned short ipx_type;
......
...@@ -662,81 +662,91 @@ tcp_send_ack(unsigned long sequence, unsigned long ack, ...@@ -662,81 +662,91 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
struct sock *sk, struct sock *sk,
struct tcphdr *th, unsigned long daddr) struct tcphdr *th, unsigned long daddr)
{ {
struct sk_buff *buff; struct sk_buff *buff;
struct tcphdr *t1; struct tcphdr *t1;
struct device *dev = NULL; struct device *dev = NULL;
int tmp; int tmp;
if(sk->zapped) if(sk->zapped)
return; /* We have been reset, we may not send again */ return; /* We have been reset, we may not send again */
/* /*
* We need to grab some memory, and put together an ack, * We need to grab some memory, and put together an ack,
* and then put it into the queue to be sent. * and then put it into the queue to be sent.
*/ */
buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) { buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
/* Force it to send an ack. */ if (buff == NULL)
sk->ack_backlog++; {
if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) { /* Force it to send an ack. */
reset_timer(sk, TIME_WRITE, 10); sk->ack_backlog++;
if (sk->timeout != TIME_WRITE && tcp_connected(sk->state))
{
reset_timer(sk, TIME_WRITE, 10);
}
if (inet_debug == DBG_SLIP)
printk("\rtcp_ack: malloc failed\n");
return;
} }
if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
return;
}
buff->len = sizeof(struct tcphdr); buff->len = sizeof(struct tcphdr);
buff->sk = sk; buff->sk = sk;
t1 =(struct tcphdr *) buff->data; buff->localroute = sk->localroute;
t1 =(struct tcphdr *) buff->data;
/* Put in the IP header and routing stuff. */ /* Put in the IP header and routing stuff. */
tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev, tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) { if (tmp < 0)
buff->free=1; {
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); buff->free=1;
if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n"); sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
return; if (inet_debug == DBG_SLIP)
} printk("\rtcp_ack: build_header failed\n");
buff->len += tmp; return;
t1 =(struct tcphdr *)((char *)t1 +tmp); }
buff->len += tmp;
t1 =(struct tcphdr *)((char *)t1 +tmp);
/* FIXME: */ /* FIXME: */
memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */ memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
/* swap the send and the receive. */ /*
t1->dest = th->source; * Swap the send and the receive.
t1->source = th->dest; */
t1->seq = ntohl(sequence); t1->dest = th->source;
t1->ack = 1; t1->source = th->dest;
sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ t1->seq = ntohl(sequence);
t1->window = ntohs(sk->window); t1->ack = 1;
t1->res1 = 0; sk->window = tcp_select_window(sk);
t1->res2 = 0; t1->window = ntohs(sk->window);
t1->rst = 0; t1->res1 = 0;
t1->urg = 0; t1->res2 = 0;
t1->syn = 0; t1->rst = 0;
t1->psh = 0; t1->urg = 0;
t1->fin = 0; t1->syn = 0;
if (ack == sk->acked_seq) { t1->psh = 0;
sk->ack_backlog = 0; t1->fin = 0;
sk->bytes_rcv = 0; if (ack == sk->acked_seq)
sk->ack_timed = 0;
if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL
&& sk->timeout == TIME_WRITE)
{ {
if(sk->keepopen) sk->ack_backlog = 0;
reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN); sk->bytes_rcv = 0;
else sk->ack_timed = 0;
delete_timer(sk); if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL
} && sk->timeout == TIME_WRITE)
} {
t1->ack_seq = ntohl(ack); if(sk->keepopen)
t1->doff = sizeof(*t1)/4; reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk); else
if (sk->debug) delete_timer(sk);
printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack); }
tcp_statistics.TcpOutSegs++; }
sk->prot->queue_xmit(sk, dev, buff, 1); t1->ack_seq = ntohl(ack);
t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
if (sk->debug)
printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
tcp_statistics.TcpOutSegs++;
sk->prot->queue_xmit(sk, dev, buff, 1);
} }
...@@ -766,138 +776,165 @@ tcp_build_header(struct tcphdr *th, struct sock *sk, int push) ...@@ -766,138 +776,165 @@ tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
* This routine copies from a user buffer into a socket, * This routine copies from a user buffer into a socket,
* and starts the transmit system. * and starts the transmit system.
*/ */
static int static int tcp_write(struct sock *sk, unsigned char *from,
tcp_write(struct sock *sk, unsigned char *from,
int len, int nonblock, unsigned flags) int len, int nonblock, unsigned flags)
{ {
int copied = 0; int copied = 0;
int copy; int copy;
int tmp; int tmp;
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff *send_tmp; struct sk_buff *send_tmp;
unsigned char *buff; unsigned char *buff;
struct proto *prot; struct proto *prot;
struct device *dev = NULL; struct device *dev = NULL;
DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n", DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, from, len, nonblock, flags)); sk, from, len, nonblock, flags));
sk->inuse=1; sk->inuse=1;
prot = sk->prot; prot = sk->prot;
while(len > 0) { while(len > 0)
if (sk->err) { /* Stop on an error */ {
release_sock(sk); if (sk->err)
if (copied) return(copied); { /* Stop on an error */
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
/* First thing we do is make sure that we are established. */
if (sk->shutdown & SEND_SHUTDOWN) {
release_sock(sk);
sk->err = EPIPE;
if (copied) return(copied);
sk->err = 0;
return(-EPIPE);
}
/* Wait for a connection to finish. */
while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) {
if (sk->err) {
release_sock(sk); release_sock(sk);
if (copied) return(copied); if (copied)
return(copied);
tmp = -sk->err; tmp = -sk->err;
sk->err = 0; sk->err = 0;
return(tmp); return(tmp);
} }
if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) { /*
* First thing we do is make sure that we are established.
*/
if (sk->shutdown & SEND_SHUTDOWN)
{
release_sock(sk); release_sock(sk);
DPRINTF((DBG_TCP, "tcp_write: return 1\n")); sk->err = EPIPE;
if (copied) return(copied); if (copied)
return(copied);
sk->err = 0;
return(-EPIPE);
}
if (sk->err) {
/*
* Wait for a connection to finish.
*/
while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
{
if (sk->err)
{
release_sock(sk);
if (copied)
return(copied);
tmp = -sk->err; tmp = -sk->err;
sk->err = 0; sk->err = 0;
return(tmp); return(tmp);
} }
if (sk->keepopen) { if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
send_sig(SIGPIPE, current, 0); {
release_sock(sk);
DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
if (copied)
return(copied);
if (sk->err)
{
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
if (sk->keepopen)
{
send_sig(SIGPIPE, current, 0);
}
return(-EPIPE);
} }
return(-EPIPE);
}
if (nonblock || copied) { if (nonblock || copied)
release_sock(sk); {
DPRINTF((DBG_TCP, "tcp_write: return 2\n")); release_sock(sk);
if (copied) return(copied); DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
return(-EAGAIN); if (copied)
} return(copied);
return(-EAGAIN);
}
release_sock(sk); release_sock(sk);
cli(); cli();
if (sk->state != TCP_ESTABLISHED &&
sk->state != TCP_CLOSE_WAIT && sk->err == 0) { if (sk->state != TCP_ESTABLISHED &&
interruptible_sleep_on(sk->sleep); sk->state != TCP_CLOSE_WAIT && sk->err == 0)
if (current->signal & ~current->blocked) { {
sti(); interruptible_sleep_on(sk->sleep);
DPRINTF((DBG_TCP, "tcp_write: return 3\n")); if (current->signal & ~current->blocked)
if (copied) return(copied); {
return(-ERESTARTSYS); sti();
DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
if (copied)
return(copied);
return(-ERESTARTSYS);
}
} }
sk->inuse = 1;
sti();
} }
sk->inuse = 1;
sti();
}
/* /*
* The following code can result in copy <= if sk->mss is ever * The following code can result in copy <= if sk->mss is ever
* decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window).
* sk->mtu is constant once SYN processing is finished. I.e. we * sk->mtu is constant once SYN processing is finished. I.e. we
* had better not get here until we've seen his SYN and at least one * had better not get here until we've seen his SYN and at least one
* valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.)
* But ESTABLISHED should guarantee that. sk->max_window is by definition * But ESTABLISHED should guarantee that. sk->max_window is by definition
* non-decreasing. Note that any ioctl to set user_mss must be done * non-decreasing. Note that any ioctl to set user_mss must be done
* before the exchange of SYN's. If the initial ack from the other * before the exchange of SYN's. If the initial ack from the other
* end has a window of 0, max_window and thus mss will both be 0. * end has a window of 0, max_window and thus mss will both be 0.
*/ */
/* Now we need to check if we have a half built packet. */ /*
if ((skb = tcp_dequeue_partial(sk)) != NULL) { * Now we need to check if we have a half built packet.
int hdrlen; */
/* IP header + TCP header */ if ((skb = tcp_dequeue_partial(sk)) != NULL)
hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data) {
+ sizeof(struct tcphdr); int hdrlen;
/* Add more stuff to the end of skb->len */ /* IP header + TCP header */
if (!(flags & MSG_OOB)) { hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
copy = min(sk->mss - (skb->len - hdrlen), len); + sizeof(struct tcphdr);
/* FIXME: this is really a bug. */
if (copy <= 0) { /* Add more stuff to the end of skb->len */
printk("TCP: **bug**: \"copy\" <= 0!!\n"); if (!(flags & MSG_OOB))
copy = 0; {
} copy = min(sk->mss - (skb->len - hdrlen), len);
/* FIXME: this is really a bug. */
if (copy <= 0)
{
printk("TCP: **bug**: \"copy\" <= 0!!\n");
copy = 0;
}
memcpy_fromfs(skb->data + skb->len, from, copy); memcpy_fromfs(skb->data + skb->len, from, copy);
skb->len += copy; skb->len += copy;
from += copy; from += copy;
copied += copy; copied += copy;
len -= copy; len -= copy;
sk->write_seq += copy; sk->write_seq += copy;
} }
if ((skb->len - hdrlen) >= sk->mss || if ((skb->len - hdrlen) >= sk->mss ||
(flags & MSG_OOB) || (flags & MSG_OOB) || !sk->packets_out)
!sk->packets_out) tcp_send_skb(sk, skb);
tcp_send_skb(sk, skb); else
else tcp_enqueue_partial(skb, sk);
tcp_enqueue_partial(skb, sk); continue;
continue; }
}
/* /*
* We also need to worry about the window. * We also need to worry about the window.
...@@ -911,112 +948,146 @@ tcp_write(struct sock *sk, unsigned char *from, ...@@ -911,112 +948,146 @@ tcp_write(struct sock *sk, unsigned char *from,
* be queued for later rather than sent. * be queued for later rather than sent.
*/ */
copy = sk->window_seq - sk->write_seq; copy = sk->window_seq - sk->write_seq;
if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss) if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)
copy = sk->mss; copy = sk->mss;
if (copy > len) if (copy > len)
copy = len; copy = len;
/* We should really check the window here also. */
send_tmp = NULL;
if (copy < sk->mss && !(flags & MSG_OOB)) {
/* We will release the socket incase we sleep here. */
release_sock(sk);
/* NB: following must be mtu, because mss can be increased.
* mss is always <= mtu */
skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL);
sk->inuse = 1;
send_tmp = skb;
} else {
/* We will release the socket incase we sleep here. */
release_sock(sk);
skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL);
sk->inuse = 1;
}
/* If we didn't get any memory, we need to sleep. */ /*
if (skb == NULL) { * We should really check the window here also.
if (nonblock /* || copied */) { */
send_tmp = NULL;
if (copy < sk->mss && !(flags & MSG_OOB))
{
/*
* We will release the socket incase we sleep here.
*/
release_sock(sk);
/*
* NB: following must be mtu, because mss can be increased.
* mss is always <= mtu
*/
skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL);
sk->inuse = 1;
send_tmp = skb;
}
else
{
/*
* We will release the socket incase we sleep here.
*/
release_sock(sk); release_sock(sk);
DPRINTF((DBG_TCP, "tcp_write: return 4\n")); skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL);
if (copied) return(copied); sk->inuse = 1;
return(-EAGAIN);
} }
/* FIXME: here is another race condition. */ /*
tmp = sk->wmem_alloc; * If we didn't get any memory, we need to sleep.
release_sock(sk); */
cli();
/* Again we will try to avoid it. */ if (skb == NULL)
if (tmp <= sk->wmem_alloc && {
(sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT) if (nonblock /* || copied */)
&& sk->err == 0) { {
interruptible_sleep_on(sk->sleep); release_sock(sk);
if (current->signal & ~current->blocked) { DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
sti(); if (copied)
DPRINTF((DBG_TCP, "tcp_write: return 5\n")); return(copied);
if (copied) return(copied); return(-EAGAIN);
return(-ERESTARTSYS);
} }
}
sk->inuse = 1;
sti();
continue;
}
skb->len = 0; /*
skb->sk = sk; * FIXME: here is another race condition.
skb->free = 0; */
buff = skb->data; tmp = sk->wmem_alloc;
release_sock(sk);
cli();
/*
* Again we will try to avoid it.
*/
if (tmp <= sk->wmem_alloc &&
(sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
&& sk->err == 0)
{
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked)
{
sti();
DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
if (copied)
return(copied);
return(-ERESTARTSYS);
}
}
sk->inuse = 1;
sti();
continue;
}
/* skb->len = 0;
* FIXME: we need to optimize this. skb->sk = sk;
* Perhaps some hints here would be good. skb->free = 0;
*/ skb->localroute = sk->localroute|(flags&MSG_DONTROUTE);
tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
buff = skb->data;
/*
* FIXME: we need to optimize this.
* Perhaps some hints here would be good.
*/
tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl); IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
if (tmp < 0 ) { if (tmp < 0 )
prot->wfree(sk, skb->mem_addr, skb->mem_len); {
release_sock(sk); prot->wfree(sk, skb->mem_addr, skb->mem_len);
DPRINTF((DBG_TCP, "tcp_write: return 6\n")); release_sock(sk);
if (copied) return(copied); DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
return(tmp); if (copied)
} return(copied);
skb->len += tmp; return(tmp);
skb->dev = dev; }
buff += tmp; skb->len += tmp;
skb->h.th =(struct tcphdr *) buff; skb->dev = dev;
tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy); buff += tmp;
if (tmp < 0) { skb->h.th =(struct tcphdr *) buff;
prot->wfree(sk, skb->mem_addr, skb->mem_len); tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
release_sock(sk); if (tmp < 0)
DPRINTF((DBG_TCP, "tcp_write: return 7\n")); {
if (copied) return(copied); prot->wfree(sk, skb->mem_addr, skb->mem_len);
return(tmp); release_sock(sk);
} DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
if (copied)
if (flags & MSG_OOB) { return(copied);
((struct tcphdr *)buff)->urg = 1; return(tmp);
((struct tcphdr *)buff)->urg_ptr = ntohs(copy); }
}
skb->len += tmp;
memcpy_fromfs(buff+tmp, from, copy);
from += copy;
copied += copy;
len -= copy;
skb->len += copy;
skb->free = 0;
sk->write_seq += copy;
if (send_tmp != NULL && sk->packets_out) { if (flags & MSG_OOB)
tcp_enqueue_partial(send_tmp, sk); {
continue; ((struct tcphdr *)buff)->urg = 1;
((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
}
skb->len += tmp;
memcpy_fromfs(buff+tmp, from, copy);
from += copy;
copied += copy;
len -= copy;
skb->len += copy;
skb->free = 0;
sk->write_seq += copy;
if (send_tmp != NULL && sk->packets_out)
{
tcp_enqueue_partial(send_tmp, sk);
continue;
}
tcp_send_skb(sk, skb);
} }
tcp_send_skb(sk, skb); sk->err = 0;
}
sk->err = 0;
/* /*
* Nagles rule. Turn Nagle off with TCP_NODELAY for highly * Nagles rule. Turn Nagle off with TCP_NODELAY for highly
...@@ -1025,181 +1096,204 @@ tcp_write(struct sock *sk, unsigned char *from, ...@@ -1025,181 +1096,204 @@ tcp_write(struct sock *sk, unsigned char *from,
* on my slow slip link - Alan * on my slow slip link - Alan
*/ */
/* Avoid possible race on send_tmp - c/o Johannes Stille */ /*
if(sk->partial && * Avoid possible race on send_tmp - c/o Johannes Stille
((!sk->packets_out) */
if(sk->partial && ((!sk->packets_out)
/* If not nagling we can send on the before case too.. */ /* If not nagling we can send on the before case too.. */
|| (sk->nonagle && before(sk->write_seq , sk->window_seq)) || (sk->nonagle && before(sk->write_seq , sk->window_seq))
)) ))
tcp_send_partial(sk); tcp_send_partial(sk);
/* -- */
release_sock(sk); release_sock(sk);
DPRINTF((DBG_TCP, "tcp_write: return 8\n")); DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
return(copied); return(copied);
} }
static int static int tcp_sendto(struct sock *sk, unsigned char *from,
tcp_sendto(struct sock *sk, unsigned char *from,
int len, int nonblock, unsigned flags, int len, int nonblock, unsigned flags,
struct sockaddr_in *addr, int addr_len) struct sockaddr_in *addr, int addr_len)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
if (addr_len < sizeof(sin)) return(-EINVAL); if (flags & ~(MSG_OOB|MSG_DONTROUTE))
memcpy_fromfs(&sin, addr, sizeof(sin)); return -EINVAL;
if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL); if (addr_len < sizeof(sin))
if (sin.sin_port != sk->dummy_th.dest) return(-EINVAL); return(-EINVAL);
if (sin.sin_addr.s_addr != sk->daddr) return(-EINVAL); memcpy_fromfs(&sin, addr, sizeof(sin));
return(tcp_write(sk, from, len, nonblock, flags)); if (sin.sin_family && sin.sin_family != AF_INET)
return(-EINVAL);
if (sin.sin_port != sk->dummy_th.dest)
return(-EINVAL);
if (sin.sin_addr.s_addr != sk->daddr)
return(-EINVAL);
return(tcp_write(sk, from, len, nonblock, flags));
} }
static void static void
tcp_read_wakeup(struct sock *sk) tcp_read_wakeup(struct sock *sk)
{ {
int tmp; int tmp;
struct device *dev = NULL; struct device *dev = NULL;
struct tcphdr *t1; struct tcphdr *t1;
struct sk_buff *buff; struct sk_buff *buff;
DPRINTF((DBG_TCP, "in tcp read wakeup\n")); DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
if (!sk->ack_backlog) return; if (!sk->ack_backlog)
return;
/* /*
* FIXME: we need to put code here to prevent this routine from * FIXME: we need to put code here to prevent this routine from
* being called. Being called once in a while is ok, so only check * being called. Being called once in a while is ok, so only check
* if this is the second time in a row. * if this is the second time in a row.
*/ */
/* /*
* We need to grab some memory, and put together an ack, * We need to grab some memory, and put together an ack,
* and then put it into the queue to be sent. * and then put it into the queue to be sent.
*/ */
buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
if (buff == NULL) {
/* Try again real soon. */
reset_timer(sk, TIME_WRITE, 10);
return;
}
buff->len = sizeof(struct tcphdr); buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
buff->sk = sk; if (buff == NULL)
{
/* Try again real soon. */
reset_timer(sk, TIME_WRITE, 10);
return;
}
/* Put in the IP header and routing stuff. */ buff->len = sizeof(struct tcphdr);
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, buff->sk = sk;
IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); buff->localroute = sk->localroute;
if (tmp < 0) {
buff->free=1; /*
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); * Put in the IP header and routing stuff.
return; */
}
buff->len += tmp; tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
t1 =(struct tcphdr *)(buff->data +tmp); IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0)
{
buff->free=1;
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
return;
}
memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); buff->len += tmp;
t1->seq = htonl(sk->sent_seq); t1 =(struct tcphdr *)(buff->data +tmp);
t1->ack = 1;
t1->res1 = 0; memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
t1->res2 = 0; t1->seq = htonl(sk->sent_seq);
t1->rst = 0; t1->ack = 1;
t1->urg = 0; t1->res1 = 0;
t1->syn = 0; t1->res2 = 0;
t1->psh = 0; t1->rst = 0;
sk->ack_backlog = 0; t1->urg = 0;
sk->bytes_rcv = 0; t1->syn = 0;
sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ t1->psh = 0;
t1->window = ntohs(sk->window); sk->ack_backlog = 0;
t1->ack_seq = ntohl(sk->acked_seq); sk->bytes_rcv = 0;
t1->doff = sizeof(*t1)/4; sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/
tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); t1->window = ntohs(sk->window);
sk->prot->queue_xmit(sk, dev, buff, 1); t1->ack_seq = ntohl(sk->acked_seq);
tcp_statistics.TcpOutSegs++; t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
sk->prot->queue_xmit(sk, dev, buff, 1);
tcp_statistics.TcpOutSegs++;
} }
/* /*
* FIXME: * FIXME:
* This routine frees used buffers. * This routine frees used buffers.
* It should consider sending an ACK to let the * It should consider sending an ACK to let the
* other end know we now have a bigger window. * other end know we now have a bigger window.
*/ */
static void
cleanup_rbuf(struct sock *sk) static void cleanup_rbuf(struct sock *sk)
{ {
unsigned long flags; unsigned long flags;
int left; int left;
struct sk_buff *skb; struct sk_buff *skb;
if(sk->debug) if(sk->debug)
printk("cleaning rbuf for sk=%p\n", sk); printk("cleaning rbuf for sk=%p\n", sk);
save_flags(flags); save_flags(flags);
cli(); cli();
left = sk->prot->rspace(sk); left = sk->prot->rspace(sk);
/* /*
* We have to loop through all the buffer headers, * We have to loop through all the buffer headers,
* and try to free up all the space we can. * and try to free up all the space we can.
*/ */
while((skb=skb_peek(&sk->receive_queue)) != NULL)
{
if (!skb->used)
break;
skb_unlink(skb);
skb->sk = sk;
kfree_skb(skb, FREE_READ);
}
restore_flags(flags); while((skb=skb_peek(&sk->receive_queue)) != NULL)
{
if (!skb->used)
break;
skb_unlink(skb);
skb->sk = sk;
kfree_skb(skb, FREE_READ);
}
/* restore_flags(flags);
* FIXME:
* At this point we should send an ack if the difference /*
* in the window, and the amount of space is bigger than * FIXME:
* TCP_WINDOW_DIFF. * At this point we should send an ack if the difference
*/ * in the window, and the amount of space is bigger than
DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n", * TCP_WINDOW_DIFF.
*/
DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk))); sk->window - sk->bytes_rcv, sk->prot->rspace(sk)));
if(sk->debug) if(sk->debug)
printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk), printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),
left); left);
if (sk->prot->rspace(sk) != left) if (sk->prot->rspace(sk) != left)
{ {
/*
* This area has caused the most trouble. The current strategy
* is to simply do nothing if the other end has room to send at
* least 3 full packets, because the ack from those will auto-
* matically update the window. If the other end doesn't think
* we have much space left, but we have room for atleast 1 more
* complete packet than it thinks we do, we will send an ack
* immediatedly. Otherwise we will wait up to .5 seconds in case
* the user reads some more.
*/
sk->ack_backlog++;
/* /*
* This area has caused the most trouble. The current strategy * It's unclear whether to use sk->mtu or sk->mss here. They differ only
* is to simply do nothing if the other end has room to send at * if the other end is offering a window smaller than the agreed on MSS
* least 3 full packets, because the ack from those will auto- * (called sk->mtu here). In theory there's no connection between send
* matically update the window. If the other end doesn't think * and receive, and so no reason to think that they're going to send
* we have much space left, but we have room for atleast 1 more * small packets. For the moment I'm using the hack of reducing the mss
* complete packet than it thinks we do, we will send an ack * only on the send side, so I'm putting mtu here.
* immediatedly. Otherwise we will wait up to .5 seconds in case
* the user reads some more.
*/ */
sk->ack_backlog++;
/* if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu)))
* It's unclear whether to use sk->mtu or sk->mss here. They differ only {
* if the other end is offering a window smaller than the agreed on MSS /* Send an ack right now. */
* (called sk->mtu here). In theory there's no connection between send tcp_read_wakeup(sk);
* and receive, and so no reason to think that they're going to send }
* small packets. For the moment I'm using the hack of reducing the mss else
* only on the send side, so I'm putting mtu here. {
*/ /* Force it to send an ack soon. */
if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) { int was_active = del_timer(&sk->timer);
/* Send an ack right now. */ if (!was_active || TCP_ACK_TIME < sk->timer.expires)
tcp_read_wakeup(sk); {
} else { reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
/* Force it to send an ack soon. */ }
int was_active = del_timer(&sk->timer); else
if (!was_active || TCP_ACK_TIME < sk->timer.expires) { add_timer(&sk->timer);
reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); }
} else
add_timer(&sk->timer);
} }
}
} }
...@@ -1407,95 +1501,119 @@ static int tcp_read(struct sock *sk, unsigned char *to, ...@@ -1407,95 +1501,119 @@ static int tcp_read(struct sock *sk, unsigned char *to,
* Send a FIN without closing the connection. * Send a FIN without closing the connection.
* Not called at interrupt time. * Not called at interrupt time.
*/ */
void
tcp_shutdown(struct sock *sk, int how) void tcp_shutdown(struct sock *sk, int how)
{ {
struct sk_buff *buff; struct sk_buff *buff;
struct tcphdr *t1, *th; struct tcphdr *t1, *th;
struct proto *prot; struct proto *prot;
int tmp; int tmp;
struct device *dev = NULL; struct device *dev = NULL;
/* /*
* We need to grab some memory, and put together a FIN, * We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent. * and then put it into the queue to be sent.
* FIXME: * FIXME:
* Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92. * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
* Most of this is guesswork, so maybe it will work... * Most of this is guesswork, so maybe it will work...
*/ */
/* If we've already sent a FIN, return. */
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) return; /*
if (!(how & SEND_SHUTDOWN)) return; * If we've already sent a FIN, return.
sk->inuse = 1; */
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2)
return;
if (!(how & SEND_SHUTDOWN))
return;
sk->inuse = 1;
/* Clear out any half completed packets. */ /*
if (sk->partial) * Clear out any half completed packets.
tcp_send_partial(sk); */
prot =(struct proto *)sk->prot; if (sk->partial)
th =(struct tcphdr *)&sk->dummy_th; tcp_send_partial(sk);
release_sock(sk); /* incase the malloc sleeps. */
buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
if (buff == NULL) return;
sk->inuse = 1;
DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff)); prot =(struct proto *)sk->prot;
buff->sk = sk; th =(struct tcphdr *)&sk->dummy_th;
buff->len = sizeof(*t1); release_sock(sk); /* incase the malloc sleeps. */
t1 =(struct tcphdr *) buff->data; buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
if (buff == NULL)
return;
sk->inuse = 1;
/* Put in the IP header and routing stuff. */ DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, buff->sk = sk;
buff->len = sizeof(*t1);
buff->localroute = sk->localroute;
t1 =(struct tcphdr *) buff->data;
/*
* Put in the IP header and routing stuff.
*/
tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, IPPROTO_TCP, sk->opt,
sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0) { if (tmp < 0)
/* Finish anyway, treat this as a send that got lost. */ {
buff->free=1; /*
prot->wfree(sk,buff->mem_addr, buff->mem_len); * Finish anyway, treat this as a send that got lost.
if(sk->state==TCP_ESTABLISHED) */
sk->state=TCP_FIN_WAIT1; buff->free=1;
else prot->wfree(sk,buff->mem_addr, buff->mem_len);
sk->state=TCP_FIN_WAIT2; if(sk->state==TCP_ESTABLISHED)
release_sock(sk); sk->state=TCP_FIN_WAIT1;
DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); else
return; sk->state=TCP_FIN_WAIT2;
} release_sock(sk);
DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
return;
}
t1 =(struct tcphdr *)((char *)t1 +tmp); t1 =(struct tcphdr *)((char *)t1 +tmp);
buff->len += tmp; buff->len += tmp;
buff->dev = dev; buff->dev = dev;
memcpy(t1, th, sizeof(*t1)); memcpy(t1, th, sizeof(*t1));
t1->seq = ntohl(sk->write_seq); t1->seq = ntohl(sk->write_seq);
sk->write_seq++; sk->write_seq++;
buff->h.seq = sk->write_seq; buff->h.seq = sk->write_seq;
t1->ack = 1; t1->ack = 1;
t1->ack_seq = ntohl(sk->acked_seq); t1->ack_seq = ntohl(sk->acked_seq);
t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
t1->fin = 1; t1->fin = 1;
t1->rst = 0; t1->rst = 0;
t1->doff = sizeof(*t1)/4; t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
/* /*
* Can't just queue this up. * Can't just queue this up.
* It should go at the end of the write queue. * It should go at the end of the write queue.
*/ */
if (skb_peek(&sk->write_queue) != NULL) {
buff->free=0; if (skb_peek(&sk->write_queue) != NULL)
if (buff->next != NULL) { {
printk("tcp_shutdown: next != NULL\n"); buff->free=0;
skb_unlink(buff); if (buff->next != NULL)
{
printk("tcp_shutdown: next != NULL\n");
skb_unlink(buff);
}
skb_queue_tail(&sk->write_queue, buff);
}
else
{
sk->sent_seq = sk->write_seq;
sk->prot->queue_xmit(sk, dev, buff, 0);
} }
skb_queue_tail(&sk->write_queue, buff);
} else {
sk->sent_seq = sk->write_seq;
sk->prot->queue_xmit(sk, dev, buff, 0);
}
if (sk->state == TCP_ESTABLISHED) sk->state = TCP_FIN_WAIT1; if (sk->state == TCP_ESTABLISHED)
else sk->state = TCP_FIN_WAIT2; sk->state = TCP_FIN_WAIT1;
else
sk->state = TCP_FIN_WAIT2;
release_sock(sk); release_sock(sk);
} }
...@@ -1536,73 +1654,85 @@ tcp_recvfrom(struct sock *sk, unsigned char *to, ...@@ -1536,73 +1654,85 @@ tcp_recvfrom(struct sock *sk, unsigned char *to,
} }
/* This routine will send an RST to the other tcp. */ /*
static void * This routine will send an RST to the other tcp.
tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th, */
static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl) struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl)
{ {
struct sk_buff *buff; struct sk_buff *buff;
struct tcphdr *t1; struct tcphdr *t1;
int tmp; int tmp;
struct device *ndev=NULL; struct device *ndev=NULL;
/* /*
* We need to grab some memory, and put together an RST, * We need to grab some memory, and put together an RST,
* and then put it into the queue to be sent. * and then put it into the queue to be sent.
*/ */
buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
if (buff == NULL)
return;
DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff)); buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
buff->len = sizeof(*t1); if (buff == NULL)
buff->sk = NULL; return;
buff->dev = dev;
t1 =(struct tcphdr *) buff->data; DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
buff->len = sizeof(*t1);
buff->sk = NULL;
buff->dev = dev;
buff->localroute = 0;
/* Put in the IP header and routing stuff. */ t1 =(struct tcphdr *) buff->data;
tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt,
/*
* Put in the IP header and routing stuff.
*/
tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt,
sizeof(struct tcphdr),tos,ttl); sizeof(struct tcphdr),tos,ttl);
if (tmp < 0) { if (tmp < 0)
buff->free = 1; {
prot->wfree(NULL, buff->mem_addr, buff->mem_len); buff->free = 1;
return; prot->wfree(NULL, buff->mem_addr, buff->mem_len);
} return;
t1 =(struct tcphdr *)((char *)t1 +tmp); }
buff->len += tmp;
memcpy(t1, th, sizeof(*t1));
/* Swap the send and the receive. */ t1 =(struct tcphdr *)((char *)t1 +tmp);
t1->dest = th->source; buff->len += tmp;
t1->source = th->dest; memcpy(t1, th, sizeof(*t1));
t1->rst = 1;
t1->window = 0; /*
* Swap the send and the receive.
*/
t1->dest = th->source;
t1->source = th->dest;
t1->rst = 1;
t1->window = 0;
if(th->ack) if(th->ack)
{ {
t1->ack = 0; t1->ack = 0;
t1->seq = th->ack_seq; t1->seq = th->ack_seq;
t1->ack_seq = 0; t1->ack_seq = 0;
} }
else else
{ {
t1->ack = 1; t1->ack = 1;
if(!th->syn) if(!th->syn)
t1->ack_seq=htonl(th->seq); t1->ack_seq=htonl(th->seq);
else else
t1->ack_seq=htonl(th->seq+1); t1->ack_seq=htonl(th->seq+1);
t1->seq=0; t1->seq=0;
} }
t1->syn = 0; t1->syn = 0;
t1->urg = 0; t1->urg = 0;
t1->fin = 0; t1->fin = 0;
t1->psh = 0; t1->psh = 0;
t1->doff = sizeof(*t1)/4; t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL); tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
prot->queue_xmit(NULL, dev, buff, 1); prot->queue_xmit(NULL, dev, buff, 1);
tcp_statistics.TcpOutSegs++; tcp_statistics.TcpOutSegs++;
} }
...@@ -1755,6 +1885,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -1755,6 +1885,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->pair = NULL; newsk->pair = NULL;
newsk->wmem_alloc = 0; newsk->wmem_alloc = 0;
newsk->rmem_alloc = 0; newsk->rmem_alloc = 0;
newsk->localroute = sk->localroute;
newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF; newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
...@@ -1830,7 +1961,8 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -1830,7 +1961,8 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
buff->len = sizeof(struct tcphdr)+4; buff->len = sizeof(struct tcphdr)+4;
buff->sk = newsk; buff->sk = newsk;
buff->localroute = newsk->localroute;
t1 =(struct tcphdr *) buff->data; t1 =(struct tcphdr *) buff->data;
/* Put in the IP header and routing stuff. */ /* Put in the IP header and routing stuff. */
...@@ -1896,155 +2028,180 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -1896,155 +2028,180 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
} }
static void static void tcp_close(struct sock *sk, int timeout)
tcp_close(struct sock *sk, int timeout)
{ {
struct sk_buff *buff; struct sk_buff *buff;
int need_reset = 0; int need_reset = 0;
struct tcphdr *t1, *th; struct tcphdr *t1, *th;
struct proto *prot; struct proto *prot;
struct device *dev=NULL; struct device *dev=NULL;
int tmp; int tmp;
/* /*
* We need to grab some memory, and put together a FIN, * We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent. * and then put it into the queue to be sent.
*/ */
DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout)); DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
sk->inuse = 1; sk->inuse = 1;
sk->keepopen = 1; sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) if (!sk->dead)
sk->state_change(sk); sk->state_change(sk);
/* We need to flush the recv. buffs. */ /*
if (skb_peek(&sk->receive_queue) != NULL) * We need to flush the recv. buffs.
{ */
struct sk_buff *skb;
if(sk->debug) if (skb_peek(&sk->receive_queue) != NULL)
printk("Clean rcv queue\n");
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{ {
if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq)) struct sk_buff *skb;
if(sk->debug)
printk("Clean rcv queue\n");
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{
if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
need_reset = 1; need_reset = 1;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
}
if(sk->debug)
printk("Cleaned.\n");
} }
if(sk->debug)
printk("Cleaned.\n");
}
/* Get rid off any half-completed packets. */ /*
if (sk->partial) { * Get rid off any half-completed packets.
tcp_send_partial(sk); */
}
if (sk->partial)
{
tcp_send_partial(sk);
}
switch(sk->state) { switch(sk->state)
case TCP_FIN_WAIT1: {
case TCP_FIN_WAIT2: case TCP_FIN_WAIT1:
case TCP_LAST_ACK: case TCP_FIN_WAIT2:
/* start a timer. */ case TCP_LAST_ACK:
/* original code was 4 * sk->rtt. In converting to the /*
* new rtt representation, we can't quite use that. * Start a timer.
* it seems to make most sense to use the backed off value * original code was 4 * sk->rtt. In converting to the
*/ * new rtt representation, we can't quite use that.
reset_timer(sk, TIME_CLOSE, 4 * sk->rto); * it seems to make most sense to use the backed off value
if (timeout) tcp_time_wait(sk); */
release_sock(sk); reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
return; /* break causes a double release - messy */ if (timeout)
case TCP_TIME_WAIT: tcp_time_wait(sk);
if (timeout) { release_sock(sk);
sk->state = TCP_CLOSE; return; /* break causes a double release - messy */
} case TCP_TIME_WAIT:
release_sock(sk); if (timeout)
return; {
case TCP_LISTEN: sk->state = TCP_CLOSE;
sk->state = TCP_CLOSE; }
release_sock(sk);
return;
case TCP_CLOSE:
release_sock(sk);
return;
case TCP_CLOSE_WAIT:
case TCP_ESTABLISHED:
case TCP_SYN_SENT:
case TCP_SYN_RECV:
prot =(struct proto *)sk->prot;
th =(struct tcphdr *)&sk->dummy_th;
buff = prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) {
/* This will force it to try again later. */
/* Or it would have if someone released the socket
first. Anyway it might work now */
release_sock(sk); release_sock(sk);
if (sk->state != TCP_CLOSE_WAIT)
sk->state = TCP_ESTABLISHED;
reset_timer(sk, TIME_CLOSE, 100);
return; return;
} case TCP_LISTEN:
buff->sk = sk; sk->state = TCP_CLOSE;
buff->free = 1; release_sock(sk);
buff->len = sizeof(*t1); return;
t1 =(struct tcphdr *) buff->data; case TCP_CLOSE:
release_sock(sk);
/* Put in the IP header and routing stuff. */ return;
tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, case TCP_CLOSE_WAIT:
case TCP_ESTABLISHED:
case TCP_SYN_SENT:
case TCP_SYN_RECV:
prot =(struct proto *)sk->prot;
th =(struct tcphdr *)&sk->dummy_th;
buff = prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
if (buff == NULL)
{
/* This will force it to try again later. */
/* Or it would have if someone released the socket
first. Anyway it might work now */
release_sock(sk);
if (sk->state != TCP_CLOSE_WAIT)
sk->state = TCP_ESTABLISHED;
reset_timer(sk, TIME_CLOSE, 100);
return;
}
buff->sk = sk;
buff->free = 1;
buff->len = sizeof(*t1);
buff->localroute = sk->localroute;
t1 =(struct tcphdr *) buff->data;
/*
* Put in the IP header and routing stuff.
*/
tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, IPPROTO_TCP, sk->opt,
sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0) { if (tmp < 0)
kfree_skb(buff,FREE_WRITE); {
if(sk->state==TCP_ESTABLISHED) kfree_skb(buff,FREE_WRITE);
sk->state=TCP_FIN_WAIT1; if(sk->state==TCP_ESTABLISHED)
else sk->state=TCP_FIN_WAIT1;
sk->state=TCP_FIN_WAIT2; else
reset_timer(sk, TIME_CLOSE,4*sk->rto); sk->state=TCP_FIN_WAIT2;
if(timeout) reset_timer(sk, TIME_CLOSE,4*sk->rto);
tcp_time_wait(sk); if(timeout)
tcp_time_wait(sk);
DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
release_sock(sk);
return;
}
DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); t1 =(struct tcphdr *)((char *)t1 +tmp);
release_sock(sk); buff->len += tmp;
return; buff->dev = dev;
} memcpy(t1, th, sizeof(*t1));
t1->seq = ntohl(sk->write_seq);
sk->write_seq++;
buff->h.seq = sk->write_seq;
t1->ack = 1;
/*
* Ack everything immediately from now on.
*/
t1 =(struct tcphdr *)((char *)t1 +tmp); sk->delay_acks = 0;
buff->len += tmp; t1->ack_seq = ntohl(sk->acked_seq);
buff->dev = dev; t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
memcpy(t1, th, sizeof(*t1)); t1->fin = 1;
t1->seq = ntohl(sk->write_seq); t1->rst = need_reset;
sk->write_seq++; t1->doff = sizeof(*t1)/4;
buff->h.seq = sk->write_seq; tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
t1->ack = 1;
tcp_statistics.TcpOutSegs++;
/* Ack everything immediately from now on. */
sk->delay_acks = 0; if (skb_peek(&sk->write_queue) == NULL)
t1->ack_seq = ntohl(sk->acked_seq); {
t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); sk->sent_seq = sk->write_seq;
t1->fin = 1; prot->queue_xmit(sk, dev, buff, 0);
t1->rst = need_reset; }
t1->doff = sizeof(*t1)/4; else
tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); {
reset_timer(sk, TIME_WRITE, sk->rto);
tcp_statistics.TcpOutSegs++; if (buff->next != NULL)
{
if (skb_peek(&sk->write_queue) == NULL) { printk("tcp_close: next != NULL\n");
sk->sent_seq = sk->write_seq; skb_unlink(buff);
prot->queue_xmit(sk, dev, buff, 0); }
} else { skb_queue_tail(&sk->write_queue, buff);
reset_timer(sk, TIME_WRITE, sk->rto);
if (buff->next != NULL) {
printk("tcp_close: next != NULL\n");
skb_unlink(buff);
} }
skb_queue_tail(&sk->write_queue, buff);
}
if (sk->state == TCP_CLOSE_WAIT) { if (sk->state == TCP_CLOSE_WAIT)
sk->state = TCP_FIN_WAIT2; {
} else { sk->state = TCP_FIN_WAIT2;
sk->state = TCP_FIN_WAIT1; }
else
{
sk->state = TCP_FIN_WAIT1;
}
} }
} release_sock(sk);
release_sock(sk);
} }
...@@ -2762,51 +2919,56 @@ static inline int tcp_urg(struct sock *sk, struct tcphdr *th, ...@@ -2762,51 +2919,56 @@ static inline int tcp_urg(struct sock *sk, struct tcphdr *th,
} }
/* This deals with incoming fins. 'Linus at 9 O'clock' 8-) */ /*
static int * This deals with incoming fins. 'Linus at 9 O'clock' 8-)
tcp_fin(struct sock *sk, struct tcphdr *th, */
static int tcp_fin(struct sock *sk, struct tcphdr *th,
unsigned long saddr, struct device *dev) unsigned long saddr, struct device *dev)
{ {
DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n", DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
sk, th, saddr, dev)); sk, th, saddr, dev));
if (!sk->dead) { if (!sk->dead)
sk->state_change(sk); {
} sk->state_change(sk);
}
switch(sk->state) {
case TCP_SYN_RECV:
case TCP_SYN_SENT:
case TCP_ESTABLISHED:
/* Contains the one that needs to be acked */
reset_timer(sk, TIME_CLOSE, TCP_TIMEOUT_LEN);
sk->fin_seq = th->seq+1;
tcp_statistics.TcpCurrEstab--;
sk->state = TCP_CLOSE_WAIT;
if (th->rst) sk->shutdown = SHUTDOWN_MASK;
break;
case TCP_CLOSE_WAIT: switch(sk->state)
case TCP_FIN_WAIT2: {
break; /* we got a retransmit of the fin. */ case TCP_SYN_RECV:
case TCP_SYN_SENT:
case TCP_ESTABLISHED:
/* Contains the one that needs to be acked */
reset_timer(sk, TIME_CLOSE, TCP_TIMEOUT_LEN);
sk->fin_seq = th->seq+1;
tcp_statistics.TcpCurrEstab--;
sk->state = TCP_CLOSE_WAIT;
if (th->rst)
sk->shutdown = SHUTDOWN_MASK;
break;
case TCP_FIN_WAIT1: case TCP_CLOSE_WAIT:
/* Contains the one that needs to be acked */ case TCP_FIN_WAIT2:
sk->fin_seq = th->seq+1; break; /* we got a retransmit of the fin. */
sk->state = TCP_FIN_WAIT2;
break;
default: case TCP_FIN_WAIT1:
case TCP_TIME_WAIT: /* Contains the one that needs to be acked */
sk->state = TCP_LAST_ACK; sk->fin_seq = th->seq+1;
sk->state = TCP_FIN_WAIT2;
break;
/* Start the timers. */ default:
reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); case TCP_TIME_WAIT:
return(0); sk->state = TCP_LAST_ACK;
}
sk->ack_backlog++; /* Start the timers. */
reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
return(0);
}
sk->ack_backlog++;
return(0); return(0);
} }
...@@ -2861,124 +3023,164 @@ tcp_accept(struct sock *sk, int flags) ...@@ -2861,124 +3023,164 @@ tcp_accept(struct sock *sk, int flags)
} }
/* This will initiate an outgoing connection. */ /*
static int * This will initiate an outgoing connection.
tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) */
static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{ {
struct sk_buff *buff; struct sk_buff *buff;
struct sockaddr_in sin; struct sockaddr_in sin;
struct device *dev=NULL; struct device *dev=NULL;
unsigned char *ptr; unsigned char *ptr;
int tmp; int tmp;
struct tcphdr *t1; struct tcphdr *t1;
int err; int err;
if (sk->state != TCP_CLOSE) return(-EISCONN); if (sk->state != TCP_CLOSE)
if (addr_len < 8) return(-EINVAL); return(-EISCONN);
if (addr_len < 8)
return(-EINVAL);
err=verify_area(VERIFY_READ, usin, addr_len); err=verify_area(VERIFY_READ, usin, addr_len);
if(err) if(err)
return err; return err;
memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len)); memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT); if (sin.sin_family && sin.sin_family != AF_INET)
return(-EAFNOSUPPORT);
DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr))); DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr)));
/* Don't want a TCP connection going to a broadcast address */ /*
if (ip_chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) { * connect() to INADDR_ANY means loopback (BSD'ism).
DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n")); */
return(-ENETUNREACH);
} if(sin.sin_addr.s_addr==INADDR_ANY)
sin.sin_addr.s_addr=ip_my_addr();
/*
* Don't want a TCP connection going to a broadcast address
*/
if (ip_chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST)
{
DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
return(-ENETUNREACH);
}
/* Connect back to the same socket: Blows up so disallow it */ /*
if(sk->saddr == sin.sin_addr.s_addr && sk->num==ntohs(sin.sin_port)) * Connect back to the same socket: Blows up so disallow it
return -EBUSY; */
sk->inuse = 1; if(sk->saddr == sin.sin_addr.s_addr && sk->num==ntohs(sin.sin_port))
sk->daddr = sin.sin_addr.s_addr; return -EBUSY;
sk->write_seq = jiffies * SEQ_TICK - seq_offset;
sk->window_seq = sk->write_seq;
sk->rcv_ack_seq = sk->write_seq -1;
sk->err = 0;
sk->dummy_th.dest = sin.sin_port;
release_sock(sk);
buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); sk->inuse = 1;
if (buff == NULL) { sk->daddr = sin.sin_addr.s_addr;
return(-ENOMEM); sk->write_seq = jiffies * SEQ_TICK - seq_offset;
} sk->window_seq = sk->write_seq;
sk->inuse = 1; sk->rcv_ack_seq = sk->write_seq -1;
buff->len = 24; sk->err = 0;
buff->sk = sk; sk->dummy_th.dest = sin.sin_port;
buff->free = 1; release_sock(sk);
t1 = (struct tcphdr *) buff->data;
/* Put in the IP header and routing stuff. */ buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
/* We need to build the routing stuff fromt the things saved in skb. */ if (buff == NULL)
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, {
return(-ENOMEM);
}
sk->inuse = 1;
buff->len = 24;
buff->sk = sk;
buff->free = 1;
buff->localroute = sk->localroute;
t1 = (struct tcphdr *) buff->data;
/*
* Put in the IP header and routing stuff.
*/
/*
* We need to build the routing stuff fromt the things saved in skb.
*/
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl); IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) { if (tmp < 0)
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); {
release_sock(sk); sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
return(-ENETUNREACH); release_sock(sk);
} return(-ENETUNREACH);
buff->len += tmp; }
t1 = (struct tcphdr *)((char *)t1 +tmp);
memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
t1->seq = ntohl(sk->write_seq++);
sk->sent_seq = sk->write_seq;
buff->h.seq = sk->write_seq;
t1->ack = 0;
t1->window = 2;
t1->res1=0;
t1->res2=0;
t1->rst = 0;
t1->urg = 0;
t1->psh = 0;
t1->syn = 1;
t1->urg_ptr = 0;
t1->doff = 6;
/* use 512 or whatever user asked for */ buff->len += tmp;
if (sk->user_mss) t1 = (struct tcphdr *)((char *)t1 +tmp);
sk->mtu = sk->user_mss;
else { memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
t1->seq = ntohl(sk->write_seq++);
sk->sent_seq = sk->write_seq;
buff->h.seq = sk->write_seq;
t1->ack = 0;
t1->window = 2;
t1->res1=0;
t1->res2=0;
t1->rst = 0;
t1->urg = 0;
t1->psh = 0;
t1->syn = 1;
t1->urg_ptr = 0;
t1->doff = 6;
/* use 512 or whatever user asked for */
if (sk->user_mss)
sk->mtu = sk->user_mss;
else
{
#ifdef SUBNETSARELOCAL #ifdef SUBNETSARELOCAL
if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr)) if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr))
#else #else
if ((sk->saddr ^ sk->daddr) & dev->pa_mask) if ((sk->saddr ^ sk->daddr) & dev->pa_mask)
#endif #endif
sk->mtu = 576 - HEADER_SIZE; sk->mtu = 576 - HEADER_SIZE;
else else
sk->mtu = MAX_WINDOW; sk->mtu = MAX_WINDOW;
} }
/* but not bigger than device MTU */ /*
sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE); * but not bigger than device MTU
*/
/* Put in the TCP options to say MTU. */ sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
ptr = (unsigned char *)(t1+1);
ptr[0] = 2; /*
ptr[1] = 4; * Put in the TCP options to say MTU.
ptr[2] = (sk->mtu) >> 8; */
ptr[3] = (sk->mtu) & 0xff;
tcp_send_check(t1, sk->saddr, sk->daddr, ptr = (unsigned char *)(t1+1);
ptr[0] = 2;
ptr[1] = 4;
ptr[2] = (sk->mtu) >> 8;
ptr[3] = (sk->mtu) & 0xff;
tcp_send_check(t1, sk->saddr, sk->daddr,
sizeof(struct tcphdr) + 4, sk); sizeof(struct tcphdr) + 4, sk);
/* This must go first otherwise a really quick response will get reset. */ /*
sk->state = TCP_SYN_SENT; * This must go first otherwise a really quick response will get reset.
sk->rtt = TCP_CONNECT_TIME; */
reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
sk->prot->queue_xmit(sk, dev, buff, 0); sk->state = TCP_SYN_SENT;
tcp_statistics.TcpActiveOpens++; sk->rtt = TCP_CONNECT_TIME;
tcp_statistics.TcpOutSegs++; reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
sk->prot->queue_xmit(sk, dev, buff, 0);
tcp_statistics.TcpActiveOpens++;
tcp_statistics.TcpOutSegs++;
release_sock(sk); release_sock(sk);
return(0); return(0);
} }
...@@ -3451,69 +3653,73 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n"); ...@@ -3451,69 +3653,73 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
/* /*
* This routine sends a packet with an out of date sequence * This routine sends a packet with an out of date sequence
* number. It assumes the other end will try to ack it. * number. It assumes the other end will try to ack it.
*/ */
static void
tcp_write_wakeup(struct sock *sk) static void tcp_write_wakeup(struct sock *sk)
{ {
struct sk_buff *buff; struct sk_buff *buff;
struct tcphdr *t1; struct tcphdr *t1;
struct device *dev=NULL; struct device *dev=NULL;
int tmp; int tmp;
if (sk->zapped) if (sk->zapped)
return; /* Afer a valid reset we can send no more */ return; /* Afer a valid reset we can send no more */
if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2) sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2)
return; return;
buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
if (buff == NULL) return; if (buff == NULL)
return;
buff->len = sizeof(struct tcphdr); buff->len = sizeof(struct tcphdr);
buff->free = 1; buff->free = 1;
buff->sk = sk; buff->sk = sk;
DPRINTF((DBG_TCP, "in tcp_write_wakeup\n")); buff->localroute = sk->localroute;
t1 = (struct tcphdr *) buff->data;
/* Put in the IP header and routing stuff. */ DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, t1 = (struct tcphdr *) buff->data;
/* Put in the IP header and routing stuff. */
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) { if (tmp < 0)
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); {
return; sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
} return;
}
buff->len += tmp; buff->len += tmp;
t1 = (struct tcphdr *)((char *)t1 +tmp); t1 = (struct tcphdr *)((char *)t1 +tmp);
memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
/* /*
* Use a previous sequence. * Use a previous sequence.
* This should cause the other end to send an ack. * This should cause the other end to send an ack.
*/ */
t1->seq = htonl(sk->sent_seq-1); t1->seq = htonl(sk->sent_seq-1);
t1->ack = 1; t1->ack = 1;
t1->res1= 0; t1->res1= 0;
t1->res2= 0; t1->res2= 0;
t1->rst = 0; t1->rst = 0;
t1->urg = 0; t1->urg = 0;
t1->psh = 0; t1->psh = 0;
t1->fin = 0; t1->fin = 0;
t1->syn = 0; t1->syn = 0;
t1->ack_seq = ntohl(sk->acked_seq); t1->ack_seq = ntohl(sk->acked_seq);
t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/); t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
t1->doff = sizeof(*t1)/4; t1->doff = sizeof(*t1)/4;
tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
/* Send it and free it. /* Send it and free it.
* This will prevent the timer from automatically being restarted. * This will prevent the timer from automatically being restarted.
*/ */
sk->prot->queue_xmit(sk, dev, buff, 1); sk->prot->queue_xmit(sk, dev, buff, 1);
tcp_statistics.TcpOutSegs++; tcp_statistics.TcpOutSegs++;
} }
void void
......
...@@ -250,7 +250,7 @@ static void udp_send_check(struct udphdr *uh, unsigned long saddr, ...@@ -250,7 +250,7 @@ static void udp_send_check(struct udphdr *uh, unsigned long saddr,
static int udp_send(struct sock *sk, struct sockaddr_in *sin, static int udp_send(struct sock *sk, struct sockaddr_in *sin,
unsigned char *from, int len) unsigned char *from, int len, int rt)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct device *dev; struct device *dev;
...@@ -281,6 +281,7 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin, ...@@ -281,6 +281,7 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
skb->sk = NULL; /* to avoid changing sk->saddr */ skb->sk = NULL; /* to avoid changing sk->saddr */
skb->free = 1; skb->free = 1;
skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
/* /*
* Now build the IP and MAC header. * Now build the IP and MAC header.
...@@ -357,7 +358,7 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock ...@@ -357,7 +358,7 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
/* /*
* Check the flags. We support no flags for UDP sending * Check the flags. We support no flags for UDP sending
*/ */
if (flags) if (flags&~MSG_DONTROUTE)
return(-EINVAL); return(-EINVAL);
if (len < 0) if (len < 0)
return(-EINVAL); return(-EINVAL);
...@@ -400,7 +401,7 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock ...@@ -400,7 +401,7 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
sk->inuse = 1; sk->inuse = 1;
/* Send the packet. */ /* Send the packet. */
tmp = udp_send(sk, &sin, from, len); tmp = udp_send(sk, &sin, from, len, flags);
/* The datagram has been sent off. Release the socket. */ /* The datagram has been sent off. Release the socket. */
release_sock(sk); release_sock(sk);
...@@ -601,27 +602,29 @@ int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock, ...@@ -601,27 +602,29 @@ int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
int int
udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
int er; int er;
if (addr_len < sizeof(sin)) if (addr_len < sizeof(sin))
return(-EINVAL); return(-EINVAL);
er=verify_area(VERIFY_READ, usin, sizeof(sin)); er=verify_area(VERIFY_READ, usin, sizeof(sin));
if(er) if(er)
return er; return er;
memcpy_fromfs(&sin, usin, sizeof(sin)); memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET) if (sin.sin_family && sin.sin_family != AF_INET)
return(-EAFNOSUPPORT); return(-EAFNOSUPPORT);
if (sin.sin_addr.s_addr==INADDR_ANY)
sin.sin_addr.s_addr=ip_my_addr();
if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */ return -EACCES; /* Must turn broadcast on first */
sk->daddr = sin.sin_addr.s_addr; sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port; sk->dummy_th.dest = sin.sin_port;
sk->state = TCP_ESTABLISHED; sk->state = TCP_ESTABLISHED;
return(0); return(0);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment