diff -u --new-file --recursive v1.1.5/linux/Makefile linux/Makefile --- v1.1.5/linux/Makefile Tue Apr 19 10:54:16 1994 +++ linux/Makefile Tue Apr 19 07:41:55 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 5 +SUBLEVEL = 6 all: Version zImage diff -u --new-file --recursive v1.1.5/linux/drivers/net/d_link.c linux/drivers/net/d_link.c --- v1.1.5/linux/drivers/net/d_link.c Tue Apr 19 10:53:43 1994 +++ linux/drivers/net/d_link.c Tue Apr 19 07:26:02 1994 @@ -201,9 +201,10 @@ /* * Index to functions, as function prototypes. */ - +#if 0 /* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */ static unsigned long d_link_rspace(struct sock *sk); +#endif /* Routines used internally. (See "convenience macros") */ static int d_link_read_status(struct device *dev); @@ -689,6 +690,10 @@ sti(); } +#if 0 +/* + * The new router code (coming soon 8-) ) will fix this properly. + */ #define D_LINK_MIN_WINDOW 1024 #define D_LINK_MAX_WINDOW 2048 #define D_LINK_TCP_WINDOW_DIFF 1024 @@ -724,3 +729,6 @@ } return(0); } + + +#endif diff -u --new-file --recursive v1.1.5/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v1.1.5/linux/drivers/net/depca.c Tue Apr 19 10:53:43 1994 +++ linux/drivers/net/depca.c Tue Apr 19 07:25:29 1994 @@ -644,32 +644,7 @@ dev->mem_start = 0; /* Fill in the generic field of the device structure. */ - for (i = 0; i < DEV_NUMBUFFS; i++) { - 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); + ether_setup(dev); } } else { status = -ENXIO; @@ -831,14 +806,6 @@ dev_tint(dev); 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) { return 0; diff -u --new-file --recursive v1.1.5/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.1.5/linux/drivers/net/slip.c Tue Apr 19 10:53:46 1994 +++ linux/drivers/net/slip.c Tue Apr 19 07:23:27 1994 @@ -1030,6 +1030,12 @@ memcpy_fromfs(dev->dev_addr,addr,7); /* addr is an AX.25 shifted ASCII mac address */ return 0; } + +static int sl_set_dev_mac_address(struct device *dev, void *addr) +{ + memcpy(dev->dev_addr,addr,7); + return 0; +} #endif @@ -1144,7 +1150,7 @@ dev->get_stats = sl_get_stats; #ifdef HAVE_SET_MAC_ADDR #ifdef CONFIG_AX25 - dev->set_mac_address = sl_set_mac_address; + dev->set_mac_address = sl_set_dev_mac_address; #endif #endif dev->hard_header_len = 0; diff -u --new-file --recursive v1.1.5/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.1.5/linux/include/linux/skbuff.h Tue Apr 19 10:53:50 1994 +++ linux/include/linux/skbuff.h Tue Apr 19 07:25:05 1994 @@ -68,7 +68,7 @@ used, free, 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 long padding[0]; unsigned char data[0]; diff -u --new-file --recursive v1.1.5/linux/include/linux/socket.h linux/include/linux/socket.h --- v1.1.5/linux/include/linux/socket.h Mon Jan 24 14:39:20 1994 +++ linux/include/linux/socket.h Tue Apr 19 07:25:13 1994 @@ -42,6 +42,7 @@ /* Flags we can use with send/ and recv. */ #define MSG_OOB 1 #define MSG_PEEK 2 +#define MSG_DONTROUTE 4 /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ #define SOL_SOCKET 1 diff -u --new-file --recursive v1.1.5/linux/kernel/exit.c linux/kernel/exit.c --- v1.1.5/linux/kernel/exit.c Wed Mar 30 08:43:58 1994 +++ linux/kernel/exit.c Tue Apr 19 10:58:57 1994 @@ -364,17 +364,6 @@ sem_exit(); if (current->shm) shm_exit(); - free_page_tables(current); - for (i=0 ; ifilp[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. */ { @@ -390,17 +379,28 @@ } } + /* forget local segments */ + __asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0" + : /* no outputs */ + : "r" (0)); + current->tss.ldt = 0; if (current->ldt) { - vfree(current->ldt); + void * ldt = current->ldt; current->ldt = NULL; - for (i=1 ; ifilp[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 * as a result of our exiting, and if they have any stopped diff -u --new-file --recursive v1.1.5/linux/net/inet/dev.c linux/net/inet/dev.c --- v1.1.5/linux/net/inet/dev.c Tue Apr 19 10:54:18 1994 +++ linux/net/inet/dev.c Tue Apr 19 10:39:08 1994 @@ -549,7 +549,7 @@ for (dev = dev_base; dev != NULL; dev = dev->next) { - if (!dev->tbusy) { + if (dev->flags != 0 && !dev->tbusy) { /* * Kick the device */ diff -u --new-file --recursive v1.1.5/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.5/linux/net/inet/ip.c Tue Apr 19 10:53:58 1994 +++ linux/net/inet/ip.c Tue Apr 19 07:24:01 1994 @@ -284,7 +284,10 @@ 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) { ip_statistics.IpOutNoRoutes++; @@ -308,7 +311,10 @@ /* * 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 * have the output device ip address and never the loopback diff -u --new-file --recursive v1.1.5/linux/net/inet/ipx.c linux/net/inet/ipx.c --- v1.1.5/linux/net/inet/ipx.c Tue Apr 19 10:53:59 1994 +++ linux/net/inet/ipx.c Tue Apr 19 07:25:47 1994 @@ -503,6 +503,7 @@ sk->type=sock->type; sk->ipx_type=0; /* General user level IPX */ sk->debug=0; + sk->localroute=0; memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr)); memset(&sk->ipx_source_addr,'\0',sizeof(sk->ipx_source_addr)); @@ -836,7 +837,7 @@ int size; ipx_route *rt; - if(flags) + if(flags&~MSG_DONTROUTE) return -EINVAL; if(len<0) return -EINVAL; @@ -882,7 +883,8 @@ /* Find out where this has to go */ 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; } @@ -917,7 +919,7 @@ skb->dev=rt->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, NULL, len+sizeof(ipx_packet), diff -u --new-file --recursive v1.1.5/linux/net/inet/raw.c linux/net/inet/raw.c --- v1.1.5/linux/net/inet/raw.c Tue Apr 19 10:54:01 1994 +++ linux/net/inet/raw.c Tue Apr 19 07:24:14 1994 @@ -142,143 +142,162 @@ 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, int len, - int noblock, - unsigned flags, struct sockaddr_in *usin, int addr_len) +static int 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 device *dev=NULL; - struct sockaddr_in sin; - int tmp; - int err; - - 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, - flags, usin, addr_len)); - - /* Check the flags. */ - if (flags) return(-EINVAL); - if (len < 0) return(-EINVAL); - - err=verify_area(VERIFY_READ,from,len); - if(err) - return err; - /* Get and verify the address. */ - if (usin) { - if (addr_len < sizeof(sin)) return(-EINVAL); - err=verify_area (VERIFY_READ, usin, sizeof (sin)); + struct sk_buff *skb; + struct device *dev=NULL; + struct sockaddr_in sin; + int tmp; + int err; + + 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, + flags, usin, addr_len)); + + /* + * Check the flags. Only MSG_DONTROUTE is permitted. + */ + + if (flags&MSG_DONTROUTE) + return(-EINVAL); + if (len < 0) + return(-EINVAL); + + err=verify_area(VERIFY_READ,from,len); 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; + /* + * Get and verify the address. + */ + + if (usin) + { + if (addr_len < sizeof(sin)) + return(-EINVAL); + 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) - return -EACCES; + if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + return -EACCES; - sk->inuse = 1; - skb = NULL; - while (skb == NULL) { - if(sk->err!=0) - { - err= -sk->err; - sk->err=0; - release_sock(sk); - return(err); - } + sk->inuse = 1; + skb = NULL; + while (skb == NULL) + { + if(sk->err!=0) + { + err= -sk->err; + sk->err=0; + release_sock(sk); + return(err); + } - skb = sk->prot->wmalloc(sk, - len + sk->prot->max_header, - 0, GFP_KERNEL); - if (skb == NULL) { - int tmp; - - DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n")); - if (noblock) - return(-EAGAIN); - tmp = sk->wmem_alloc; - release_sock(sk); - cli(); - if (tmp <= sk->wmem_alloc) { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) { - sti(); - return(-ERESTARTSYS); + skb = sk->prot->wmalloc(sk, + len + sk->prot->max_header, + 0, GFP_KERNEL); + if (skb == NULL) + { + int tmp; + + DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n")); + if (noblock) + return(-EAGAIN); + tmp = sk->wmem_alloc; + release_sock(sk); + cli(); + if (tmp <= sk->wmem_alloc) { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + return(-ERESTARTSYS); + } } + sk->inuse = 1; + sti(); } - sk->inuse = 1; - sti(); } - } - skb->sk = sk; - - skb->free = 1; + skb->sk = sk; + skb->free = 1; + skb->localroute = sk->localroute | (flags&MSG_DONTROUTE); - tmp = sk->prot->build_header(skb, sk->saddr, + tmp = sk->prot->build_header(skb, sk->saddr, sin.sin_addr.s_addr, &dev, sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl); - if (tmp < 0) { - DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); - kfree_skb(skb,FREE_WRITE); - release_sock(sk); - return(tmp); - } + if (tmp < 0) + { + DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); + kfree_skb(skb,FREE_WRITE); + release_sock(sk); + return(tmp); + } + + memcpy_fromfs(skb->data + tmp, from, len); - /* verify_area(VERIFY_WRITE, 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(sk->protocol==IPPROTO_RAW) + { + unsigned char *buff; + struct iphdr *iph; - /* If we are using IPPROTO_RAW, we need to fill in the source address in - the IP header */ + buff = skb->data; + buff += tmp; - if(sk->protocol==IPPROTO_RAW) { - unsigned char *buff; - struct iphdr *iph; - - buff = skb->data; - buff += tmp; - iph = (struct iphdr *)buff; - iph->saddr = sk->saddr; - } + iph = (struct iphdr *)buff; + iph->saddr = sk->saddr; + } - skb->len = tmp + len; + skb->len = tmp + len; - sk->prot->queue_xmit(sk, dev, skb, 1); - release_sock(sk); - return(len); + sk->prot->queue_xmit(sk, dev, skb, 1); + release_sock(sk); + return(len); } -static int -raw_write(struct sock *sk, unsigned char *buff, int len, int noblock, +static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock, unsigned flags) { - return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0)); + return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0)); } -static void -raw_close(struct sock *sk, int timeout) +static void raw_close(struct sock *sk, int timeout) { - sk->inuse = 1; - sk->state = TCP_CLOSE; + sk->inuse = 1; + 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)); - 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")); - kfree_s((void *)sk->pair, sizeof (struct inet_protocol)); - sk->pair = NULL; - release_sock(sk); + kfree_s((void *)sk->pair, sizeof (struct inet_protocol)); + sk->pair = NULL; + release_sock(sk); } diff -u --new-file --recursive v1.1.5/linux/net/inet/route.c linux/net/inet/route.c --- v1.1.5/linux/net/inet/route.c Tue Apr 19 10:54:02 1994 +++ linux/net/inet/route.c Tue Apr 19 07:24:19 1994 @@ -573,6 +573,42 @@ 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 */ diff -u --new-file --recursive v1.1.5/linux/net/inet/route.h linux/net/inet/route.h --- v1.1.5/linux/net/inet/route.h Tue Apr 19 10:54:02 1994 +++ linux/net/inet/route.h Tue Apr 19 07:24:26 1994 @@ -9,6 +9,8 @@ * * Authors: Ross Biro, * Fred N. van Kempen, + * Fixes: + * Alan Cox : Reformatted. Added ip_rt_local() * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,17 +25,18 @@ /* This is an entry in the IP routing table. */ -struct rtable { - struct rtable *rt_next; - unsigned long rt_dst; - unsigned long rt_mask; - unsigned long rt_gateway; - unsigned char rt_flags; - unsigned char rt_metric; - short rt_refcnt; - unsigned long rt_use; - unsigned short rt_mss, rt_mtu; - struct device *rt_dev; +struct rtable +{ + struct rtable *rt_next; + unsigned long rt_dst; + unsigned long rt_mask; + unsigned long rt_gateway; + unsigned char rt_flags; + unsigned char rt_metric; + short rt_refcnt; + unsigned long rt_use; + unsigned short rt_mss, rt_mtu; + struct device *rt_dev; }; @@ -41,6 +44,7 @@ extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask, 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_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 ip_rt_ioctl(unsigned int cmd, void *arg); diff -u --new-file --recursive v1.1.5/linux/net/inet/sock.c linux/net/inet/sock.c --- v1.1.5/linux/net/inet/sock.c Tue Apr 19 10:54:04 1994 +++ linux/net/inet/sock.c Tue Apr 19 07:24:33 1994 @@ -489,7 +489,8 @@ case SO_DEBUG: sk->debug=val?1:0; - case SO_DONTROUTE: /* Still to be implemented */ + case SO_DONTROUTE: + sk->localroute=val?1:0; return(0); case SO_BROADCAST: sk->broadcast=val?1:0; @@ -580,8 +581,8 @@ val = sk->debug; break; - case SO_DONTROUTE: /* One last option to implement */ - val = 0; + case SO_DONTROUTE: + val = sk->localroute; break; case SO_BROADCAST: @@ -852,6 +853,7 @@ sk->send_head = NULL; sk->timeout = 0; sk->broadcast = 0; + sk->localroute = 0; sk->timer.data = (unsigned long)sk; sk->timer.function = &net_timer; skb_queue_head_init(&sk->back_log); diff -u --new-file --recursive v1.1.5/linux/net/inet/sock.h linux/net/inet/sock.h --- v1.1.5/linux/net/inet/sock.h Tue Apr 19 10:54:04 1994 +++ linux/net/inet/sock.h Tue Apr 19 07:24:39 1994 @@ -132,6 +132,7 @@ unsigned short rcvbuf; unsigned short sndbuf; unsigned short type; + unsigned char localroute; /* Route locally only */ #ifdef CONFIG_IPX ipx_address ipx_source_addr,ipx_dest_addr; unsigned short ipx_type; diff -u --new-file --recursive v1.1.5/linux/net/inet/tcp.c linux/net/inet/tcp.c --- v1.1.5/linux/net/inet/tcp.c Tue Apr 19 10:54:06 1994 +++ linux/net/inet/tcp.c Tue Apr 19 07:24:48 1994 @@ -662,81 +662,91 @@ struct sock *sk, struct tcphdr *th, unsigned long daddr) { - struct sk_buff *buff; - struct tcphdr *t1; - struct device *dev = NULL; - int tmp; + struct sk_buff *buff; + struct tcphdr *t1; + struct device *dev = NULL; + int tmp; - if(sk->zapped) - return; /* We have been reset, we may not send again */ - /* - * We need to grab some memory, and put together an ack, - * and then put it into the queue to be sent. - */ - buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC); - if (buff == NULL) { - /* Force it to send an ack. */ - sk->ack_backlog++; - if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) { - reset_timer(sk, TIME_WRITE, 10); + if(sk->zapped) + return; /* We have been reset, we may not send again */ + /* + * We need to grab some memory, and put together an ack, + * and then put it into the queue to be sent. + */ + + buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC); + if (buff == NULL) + { + /* Force it to send an ack. */ + 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->sk = sk; - t1 =(struct tcphdr *) buff->data; + buff->len = sizeof(struct tcphdr); + buff->sk = sk; + buff->localroute = sk->localroute; + t1 =(struct tcphdr *) buff->data; - /* Put in the IP header and routing stuff. */ - tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev, + /* Put in the IP header and routing stuff. */ + tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev, 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); - if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n"); - return; - } - buff->len += tmp; - t1 =(struct tcphdr *)((char *)t1 +tmp); + if (tmp < 0) + { + buff->free=1; + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + if (inet_debug == DBG_SLIP) + printk("\rtcp_ack: build_header failed\n"); + return; + } + buff->len += tmp; + t1 =(struct tcphdr *)((char *)t1 +tmp); - /* FIXME: */ - memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */ + /* FIXME: */ + memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */ - /* swap the send and the receive. */ - t1->dest = th->source; - t1->source = th->dest; - t1->seq = ntohl(sequence); - t1->ack = 1; - sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ - t1->window = ntohs(sk->window); - t1->res1 = 0; - t1->res2 = 0; - t1->rst = 0; - t1->urg = 0; - t1->syn = 0; - t1->psh = 0; - t1->fin = 0; - if (ack == sk->acked_seq) { - sk->ack_backlog = 0; - sk->bytes_rcv = 0; - sk->ack_timed = 0; - if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL - && sk->timeout == TIME_WRITE) + /* + * Swap the send and the receive. + */ + t1->dest = th->source; + t1->source = th->dest; + t1->seq = ntohl(sequence); + t1->ack = 1; + sk->window = tcp_select_window(sk); + t1->window = ntohs(sk->window); + t1->res1 = 0; + t1->res2 = 0; + t1->rst = 0; + t1->urg = 0; + t1->syn = 0; + t1->psh = 0; + t1->fin = 0; + if (ack == sk->acked_seq) { - if(sk->keepopen) - reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN); - else - delete_timer(sk); - } - } - 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); + sk->ack_backlog = 0; + sk->bytes_rcv = 0; + sk->ack_timed = 0; + if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL + && sk->timeout == TIME_WRITE) + { + if(sk->keepopen) + reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN); + else + delete_timer(sk); + } + } + 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 @@ * This routine copies from a user buffer into a socket, * and starts the transmit system. */ -static int -tcp_write(struct sock *sk, unsigned char *from, +static int tcp_write(struct sock *sk, unsigned char *from, int len, int nonblock, unsigned flags) { - int copied = 0; - int copy; - int tmp; - struct sk_buff *skb; - struct sk_buff *send_tmp; - unsigned char *buff; - struct proto *prot; - struct device *dev = NULL; + int copied = 0; + int copy; + int tmp; + struct sk_buff *skb; + struct sk_buff *send_tmp; + unsigned char *buff; + struct proto *prot; + 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->inuse=1; - prot = sk->prot; - while(len > 0) { - if (sk->err) { /* Stop on an error */ - release_sock(sk); - if (copied) return(copied); - 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) { + sk->inuse=1; + prot = sk->prot; + while(len > 0) + { + if (sk->err) + { /* Stop on an error */ release_sock(sk); - if (copied) return(copied); + if (copied) + return(copied); tmp = -sk->err; sk->err = 0; 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); - DPRINTF((DBG_TCP, "tcp_write: return 1\n")); - if (copied) return(copied); + sk->err = EPIPE; + 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; sk->err = 0; return(tmp); } - if (sk->keepopen) { - send_sig(SIGPIPE, current, 0); + if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) + { + 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); + } + + if (nonblock || copied) + { + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 2\n")); + if (copied) + return(copied); + return(-EAGAIN); } - return(-EPIPE); - } - if (nonblock || copied) { release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 2\n")); - if (copied) return(copied); - return(-EAGAIN); - } - - release_sock(sk); - cli(); - if (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 3\n")); - if (copied) return(copied); - return(-ERESTARTSYS); + cli(); + + if (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 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 - * 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 - * 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.) - * But ESTABLISHED should guarantee that. sk->max_window is by definition - * 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 - * end has a window of 0, max_window and thus mss will both be 0. - */ + /* + * 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). + * 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 + * 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 + * 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 + * 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) { - int hdrlen; - - /* IP header + TCP header */ - hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data) - + sizeof(struct tcphdr); - - /* Add more stuff to the end of skb->len */ - if (!(flags & MSG_OOB)) { - 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; - } + /* + * Now we need to check if we have a half built packet. + */ + + if ((skb = tcp_dequeue_partial(sk)) != NULL) + { + int hdrlen; + + /* IP header + TCP header */ + hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data) + + sizeof(struct tcphdr); + + /* Add more stuff to the end of skb->len */ + if (!(flags & MSG_OOB)) + { + 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); - skb->len += copy; - from += copy; - copied += copy; - len -= copy; - sk->write_seq += copy; - } - if ((skb->len - hdrlen) >= sk->mss || - (flags & MSG_OOB) || - !sk->packets_out) - tcp_send_skb(sk, skb); - else - tcp_enqueue_partial(skb, sk); - continue; - } + memcpy_fromfs(skb->data + skb->len, from, copy); + skb->len += copy; + from += copy; + copied += copy; + len -= copy; + sk->write_seq += copy; + } + if ((skb->len - hdrlen) >= sk->mss || + (flags & MSG_OOB) || !sk->packets_out) + tcp_send_skb(sk, skb); + else + tcp_enqueue_partial(skb, sk); + continue; + } /* * We also need to worry about the window. @@ -911,112 +948,146 @@ * be queued for later rather than sent. */ - copy = sk->window_seq - sk->write_seq; - if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss) - copy = sk->mss; - if (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; - } + copy = sk->window_seq - sk->write_seq; + if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss) + copy = sk->mss; + if (copy > len) + copy = len; - /* If we didn't get any memory, we need to sleep. */ - if (skb == NULL) { - if (nonblock /* || copied */) { + /* + * 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); - DPRINTF((DBG_TCP, "tcp_write: return 4\n")); - if (copied) return(copied); - return(-EAGAIN); + skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL); + sk->inuse = 1; } - /* FIXME: here is another race condition. */ - 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); + /* + * If we didn't get any memory, we need to sleep. + */ + + if (skb == NULL) + { + if (nonblock /* || copied */) + { + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 4\n")); + if (copied) + return(copied); + return(-EAGAIN); } - } - sk->inuse = 1; - sti(); - continue; - } - skb->len = 0; - skb->sk = sk; - skb->free = 0; + /* + * FIXME: here is another race condition. + */ - 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; + } - /* - * FIXME: we need to optimize this. - * Perhaps some hints here would be good. - */ - tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev, + skb->len = 0; + skb->sk = sk; + skb->free = 0; + skb->localroute = sk->localroute|(flags&MSG_DONTROUTE); + + 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); - if (tmp < 0 ) { - prot->wfree(sk, skb->mem_addr, skb->mem_len); - release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 6\n")); - if (copied) return(copied); - return(tmp); - } - skb->len += tmp; - skb->dev = dev; - buff += tmp; - skb->h.th =(struct tcphdr *) buff; - tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy); - if (tmp < 0) { - prot->wfree(sk, skb->mem_addr, skb->mem_len); - release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 7\n")); - if (copied) return(copied); - return(tmp); - } - - if (flags & MSG_OOB) { - ((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 (tmp < 0 ) + { + prot->wfree(sk, skb->mem_addr, skb->mem_len); + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 6\n")); + if (copied) + return(copied); + return(tmp); + } + skb->len += tmp; + skb->dev = dev; + buff += tmp; + skb->h.th =(struct tcphdr *) buff; + tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy); + if (tmp < 0) + { + prot->wfree(sk, skb->mem_addr, skb->mem_len); + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 7\n")); + if (copied) + return(copied); + return(tmp); + } - if (send_tmp != NULL && sk->packets_out) { - tcp_enqueue_partial(send_tmp, sk); - continue; + if (flags & MSG_OOB) + { + ((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 @@ -1025,181 +1096,204 @@ * on my slow slip link - Alan */ - /* Avoid possible race on send_tmp - c/o Johannes Stille */ - if(sk->partial && - ((!sk->packets_out) +/* + * Avoid possible race on send_tmp - c/o Johannes Stille + */ + + if(sk->partial && ((!sk->packets_out) /* If not nagling we can send on the before case too.. */ - || (sk->nonagle && before(sk->write_seq , sk->window_seq)) - )) - tcp_send_partial(sk); - /* -- */ - release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 8\n")); - return(copied); + || (sk->nonagle && before(sk->write_seq , sk->window_seq)) + )) + tcp_send_partial(sk); + + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 8\n")); + return(copied); } -static int -tcp_sendto(struct sock *sk, unsigned char *from, +static int tcp_sendto(struct sock *sk, unsigned char *from, int len, int nonblock, unsigned flags, struct sockaddr_in *addr, int addr_len) { - struct sockaddr_in sin; + struct sockaddr_in sin; - if (addr_len < sizeof(sin)) return(-EINVAL); - memcpy_fromfs(&sin, addr, sizeof(sin)); - 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)); + if (flags & ~(MSG_OOB|MSG_DONTROUTE)) + return -EINVAL; + if (addr_len < sizeof(sin)) + return(-EINVAL); + memcpy_fromfs(&sin, addr, sizeof(sin)); + 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 tcp_read_wakeup(struct sock *sk) { - int tmp; - struct device *dev = NULL; - struct tcphdr *t1; - struct sk_buff *buff; + int tmp; + struct device *dev = NULL; + struct tcphdr *t1; + struct sk_buff *buff; - DPRINTF((DBG_TCP, "in tcp read wakeup\n")); - if (!sk->ack_backlog) return; + DPRINTF((DBG_TCP, "in tcp read wakeup\n")); + if (!sk->ack_backlog) + return; - /* - * 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 - * if this is the second time in a row. - */ + /* + * 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 + * if this is the second time in a row. + */ - /* - * We need to grab some memory, and put together an ack, - * 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; - } + /* + * We need to grab some memory, and put together an ack, + * and then put it into the queue to be sent. + */ - buff->len = sizeof(struct tcphdr); - buff->sk = sk; + 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; + } - /* Put in the IP header and routing stuff. */ - tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, + buff->len = sizeof(struct tcphdr); + buff->sk = sk; + buff->localroute = sk->localroute; + + /* + * 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); - if (tmp < 0) { - buff->free=1; - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - return; - } + if (tmp < 0) + { + buff->free=1; + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + return; + } - buff->len += tmp; - t1 =(struct tcphdr *)(buff->data +tmp); + buff->len += tmp; + t1 =(struct tcphdr *)(buff->data +tmp); - memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); - t1->seq = htonl(sk->sent_seq); - t1->ack = 1; - t1->res1 = 0; - t1->res2 = 0; - t1->rst = 0; - t1->urg = 0; - t1->syn = 0; - t1->psh = 0; - sk->ack_backlog = 0; - sk->bytes_rcv = 0; - sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ - t1->window = ntohs(sk->window); - t1->ack_seq = ntohl(sk->acked_seq); - 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++; + memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); + t1->seq = htonl(sk->sent_seq); + t1->ack = 1; + t1->res1 = 0; + t1->res2 = 0; + t1->rst = 0; + t1->urg = 0; + t1->syn = 0; + t1->psh = 0; + sk->ack_backlog = 0; + sk->bytes_rcv = 0; + sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ + t1->window = ntohs(sk->window); + t1->ack_seq = ntohl(sk->acked_seq); + 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: - * This routine frees used buffers. - * It should consider sending an ACK to let the - * other end know we now have a bigger window. + * FIXME: + * This routine frees used buffers. + * It should consider sending an ACK to let the + * 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; - int left; - struct sk_buff *skb; + unsigned long flags; + int left; + struct sk_buff *skb; - if(sk->debug) - printk("cleaning rbuf for sk=%p\n", sk); + if(sk->debug) + printk("cleaning rbuf for sk=%p\n", sk); - save_flags(flags); - cli(); + save_flags(flags); + cli(); - left = sk->prot->rspace(sk); + left = sk->prot->rspace(sk); - /* - * We have to loop through all the buffer headers, - * 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); - } + /* + * We have to loop through all the buffer headers, + * 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); + 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 - * TCP_WINDOW_DIFF. - */ - DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n", + /* + * FIXME: + * At this point we should send an ack if the difference + * in the window, and the amount of space is bigger than + * 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))); - if(sk->debug) - printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk), + if(sk->debug) + printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk), 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 - * 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. + * 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 + * (called sk->mtu here). In theory there's no connection between send + * 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 + * only on the send side, so I'm putting mtu here. */ - sk->ack_backlog++; -/* - * 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 - * (called sk->mtu here). In theory there's no connection between send - * 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 - * only on the send side, so I'm putting mtu here. - */ - if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) { - /* Send an ack right now. */ - tcp_read_wakeup(sk); - } else { - /* Force it to send an ack soon. */ - int was_active = del_timer(&sk->timer); - if (!was_active || TCP_ACK_TIME < sk->timer.expires) { - reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); - } else - add_timer(&sk->timer); + + if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) + { + /* Send an ack right now. */ + tcp_read_wakeup(sk); + } + else + { + /* Force it to send an ack soon. */ + int was_active = del_timer(&sk->timer); + if (!was_active || TCP_ACK_TIME < sk->timer.expires) + { + reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); + } + else + add_timer(&sk->timer); + } } - } } @@ -1407,95 +1501,119 @@ * Send a FIN without closing the connection. * 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 tcphdr *t1, *th; - struct proto *prot; - int tmp; - struct device *dev = NULL; + struct sk_buff *buff; + struct tcphdr *t1, *th; + struct proto *prot; + int tmp; + struct device *dev = NULL; - /* - * We need to grab some memory, and put together a FIN, - * and then put it into the queue to be sent. - * FIXME: - * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92. - * 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; - sk->inuse = 1; + /* + * We need to grab some memory, and put together a FIN, + * and then put it into the queue to be sent. + * FIXME: + * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92. + * 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; + sk->inuse = 1; - /* Clear out any half completed packets. */ - if (sk->partial) - tcp_send_partial(sk); + /* + * Clear out any half completed packets. + */ - prot =(struct proto *)sk->prot; - th =(struct tcphdr *)&sk->dummy_th; - release_sock(sk); /* incase the malloc sleeps. */ - buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL); - if (buff == NULL) return; - sk->inuse = 1; + if (sk->partial) + tcp_send_partial(sk); - DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff)); - buff->sk = sk; - buff->len = sizeof(*t1); - t1 =(struct tcphdr *) buff->data; + prot =(struct proto *)sk->prot; + th =(struct tcphdr *)&sk->dummy_th; + release_sock(sk); /* incase the malloc sleeps. */ + 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. */ - tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, + DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff)); + 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, sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); - 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); - if(sk->state==TCP_ESTABLISHED) - sk->state=TCP_FIN_WAIT1; - else - sk->state=TCP_FIN_WAIT2; - release_sock(sk); - DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); - return; - } + 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); + if(sk->state==TCP_ESTABLISHED) + sk->state=TCP_FIN_WAIT1; + else + 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); - buff->len += tmp; - 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; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); - t1->fin = 1; - t1->rst = 0; - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + t1 =(struct tcphdr *)((char *)t1 +tmp); + buff->len += tmp; + 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; + t1->ack_seq = ntohl(sk->acked_seq); + t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->fin = 1; + t1->rst = 0; + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); - /* - * Can't just queue this up. - * It should go at the end of the write queue. - */ - if (skb_peek(&sk->write_queue) != NULL) { - buff->free=0; - if (buff->next != NULL) { - printk("tcp_shutdown: next != NULL\n"); - skb_unlink(buff); + /* + * Can't just queue this up. + * It should go at the end of the write queue. + */ + + if (skb_peek(&sk->write_queue) != NULL) + { + buff->free=0; + 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; - else sk->state = TCP_FIN_WAIT2; + if (sk->state == TCP_ESTABLISHED) + sk->state = TCP_FIN_WAIT1; + else + sk->state = TCP_FIN_WAIT2; - release_sock(sk); + release_sock(sk); } @@ -1536,73 +1654,85 @@ } -/* This routine will send an RST to the other tcp. */ -static void -tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th, +/* + * This routine will send an RST to the other tcp. + */ + +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 sk_buff *buff; - struct tcphdr *t1; - int tmp; - struct device *ndev=NULL; + struct sk_buff *buff; + struct tcphdr *t1; + int tmp; + struct device *ndev=NULL; - /* - * We need to grab some memory, and put together an RST, - * 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->len = sizeof(*t1); - buff->sk = NULL; - buff->dev = dev; +/* + * We need to grab some memory, and put together an RST, + * and then put it into the queue to be sent. + */ - t1 =(struct tcphdr *) buff->data; + buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC); + if (buff == NULL) + return; + + 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. */ - tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt, + t1 =(struct tcphdr *) buff->data; + + /* + * Put in the IP header and routing stuff. + */ + + tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt, sizeof(struct tcphdr),tos,ttl); - if (tmp < 0) { - buff->free = 1; - prot->wfree(NULL, buff->mem_addr, buff->mem_len); - return; - } - t1 =(struct tcphdr *)((char *)t1 +tmp); - buff->len += tmp; - memcpy(t1, th, sizeof(*t1)); + if (tmp < 0) + { + buff->free = 1; + prot->wfree(NULL, buff->mem_addr, buff->mem_len); + return; + } - /* Swap the send and the receive. */ - t1->dest = th->source; - t1->source = th->dest; - t1->rst = 1; - t1->window = 0; - - if(th->ack) - { - t1->ack = 0; - t1->seq = th->ack_seq; - t1->ack_seq = 0; - } - else - { - t1->ack = 1; - if(!th->syn) - t1->ack_seq=htonl(th->seq); - else - t1->ack_seq=htonl(th->seq+1); - t1->seq=0; - } + t1 =(struct tcphdr *)((char *)t1 +tmp); + buff->len += tmp; + memcpy(t1, th, sizeof(*t1)); - t1->syn = 0; - t1->urg = 0; - t1->fin = 0; - t1->psh = 0; - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL); - prot->queue_xmit(NULL, dev, buff, 1); - tcp_statistics.TcpOutSegs++; + /* + * Swap the send and the receive. + */ + + t1->dest = th->source; + t1->source = th->dest; + t1->rst = 1; + t1->window = 0; + + if(th->ack) + { + t1->ack = 0; + t1->seq = th->ack_seq; + t1->ack_seq = 0; + } + else + { + t1->ack = 1; + if(!th->syn) + t1->ack_seq=htonl(th->seq); + else + t1->ack_seq=htonl(th->seq+1); + t1->seq=0; + } + + t1->syn = 0; + t1->urg = 0; + t1->fin = 0; + t1->psh = 0; + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL); + prot->queue_xmit(NULL, dev, buff, 1); + tcp_statistics.TcpOutSegs++; } @@ -1755,6 +1885,7 @@ newsk->pair = NULL; newsk->wmem_alloc = 0; newsk->rmem_alloc = 0; + newsk->localroute = sk->localroute; newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF; @@ -1830,7 +1961,8 @@ buff->len = sizeof(struct tcphdr)+4; buff->sk = newsk; - + buff->localroute = newsk->localroute; + t1 =(struct tcphdr *) buff->data; /* Put in the IP header and routing stuff. */ @@ -1896,155 +2028,180 @@ } -static void -tcp_close(struct sock *sk, int timeout) +static void tcp_close(struct sock *sk, int timeout) { - struct sk_buff *buff; - int need_reset = 0; - struct tcphdr *t1, *th; - struct proto *prot; - struct device *dev=NULL; - int tmp; + struct sk_buff *buff; + int need_reset = 0; + struct tcphdr *t1, *th; + struct proto *prot; + struct device *dev=NULL; + int tmp; - /* - * We need to grab some memory, and put together a FIN, - * and then put it into the queue to be sent. - */ - DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout)); - sk->inuse = 1; - sk->keepopen = 1; - sk->shutdown = SHUTDOWN_MASK; + /* + * We need to grab some memory, and put together a FIN, + * and then put it into the queue to be sent. + */ + DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout)); + sk->inuse = 1; + sk->keepopen = 1; + sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); + if (!sk->dead) + sk->state_change(sk); - /* We need to flush the recv. buffs. */ - if (skb_peek(&sk->receive_queue) != NULL) - { - struct sk_buff *skb; - if(sk->debug) - printk("Clean rcv queue\n"); - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) + /* + * We need to flush the recv. buffs. + */ + + if (skb_peek(&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; - 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) { - tcp_send_partial(sk); - } + /* + * Get rid off any half-completed packets. + */ + + if (sk->partial) + { + tcp_send_partial(sk); + } - switch(sk->state) { - case TCP_FIN_WAIT1: - case TCP_FIN_WAIT2: - case TCP_LAST_ACK: - /* start a timer. */ - /* original code was 4 * sk->rtt. In converting to the - * new rtt representation, we can't quite use that. - * it seems to make most sense to use the backed off value - */ - reset_timer(sk, TIME_CLOSE, 4 * sk->rto); - if (timeout) tcp_time_wait(sk); - release_sock(sk); - return; /* break causes a double release - messy */ - case TCP_TIME_WAIT: - if (timeout) { - sk->state = TCP_CLOSE; - } - release_sock(sk); - return; - case TCP_LISTEN: - 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 */ + switch(sk->state) + { + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + case TCP_LAST_ACK: + /* + * Start a timer. + * original code was 4 * sk->rtt. In converting to the + * new rtt representation, we can't quite use that. + * it seems to make most sense to use the backed off value + */ + reset_timer(sk, TIME_CLOSE, 4 * sk->rto); + if (timeout) + tcp_time_wait(sk); release_sock(sk); - if (sk->state != TCP_CLOSE_WAIT) - sk->state = TCP_ESTABLISHED; - reset_timer(sk, TIME_CLOSE, 100); + return; /* break causes a double release - messy */ + case TCP_TIME_WAIT: + if (timeout) + { + sk->state = TCP_CLOSE; + } + release_sock(sk); return; - } - buff->sk = sk; - buff->free = 1; - buff->len = sizeof(*t1); - t1 =(struct tcphdr *) buff->data; - - /* Put in the IP header and routing stuff. */ - tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, + case TCP_LISTEN: + 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); + 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, sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); - if (tmp < 0) { - kfree_skb(buff,FREE_WRITE); - if(sk->state==TCP_ESTABLISHED) - sk->state=TCP_FIN_WAIT1; - else - sk->state=TCP_FIN_WAIT2; - reset_timer(sk, TIME_CLOSE,4*sk->rto); - if(timeout) - tcp_time_wait(sk); + if (tmp < 0) + { + kfree_skb(buff,FREE_WRITE); + if(sk->state==TCP_ESTABLISHED) + sk->state=TCP_FIN_WAIT1; + else + sk->state=TCP_FIN_WAIT2; + reset_timer(sk, TIME_CLOSE,4*sk->rto); + 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")); + release_sock(sk); + return; + } - t1 =(struct tcphdr *)((char *)t1 +tmp); - buff->len += tmp; - 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. */ - sk->delay_acks = 0; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); - t1->fin = 1; - t1->rst = need_reset; - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + t1 =(struct tcphdr *)((char *)t1 +tmp); + buff->len += tmp; + 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. + */ - tcp_statistics.TcpOutSegs++; - - if (skb_peek(&sk->write_queue) == NULL) { - sk->sent_seq = sk->write_seq; - prot->queue_xmit(sk, dev, buff, 0); - } else { - reset_timer(sk, TIME_WRITE, sk->rto); - if (buff->next != NULL) { - printk("tcp_close: next != NULL\n"); - skb_unlink(buff); + sk->delay_acks = 0; + t1->ack_seq = ntohl(sk->acked_seq); + t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->fin = 1; + t1->rst = need_reset; + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + + tcp_statistics.TcpOutSegs++; + + if (skb_peek(&sk->write_queue) == NULL) + { + sk->sent_seq = sk->write_seq; + prot->queue_xmit(sk, dev, buff, 0); + } + else + { + 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); } - skb_queue_tail(&sk->write_queue, buff); - } - if (sk->state == TCP_CLOSE_WAIT) { - sk->state = TCP_FIN_WAIT2; - } else { - sk->state = TCP_FIN_WAIT1; + if (sk->state == TCP_CLOSE_WAIT) + { + sk->state = TCP_FIN_WAIT2; + } + else + { + sk->state = TCP_FIN_WAIT1; + } } - } - release_sock(sk); + release_sock(sk); } @@ -2762,51 +2919,56 @@ } -/* This deals with incoming fins. 'Linus at 9 O'clock' 8-) */ -static int -tcp_fin(struct sock *sk, struct tcphdr *th, +/* + * This deals with incoming fins. 'Linus at 9 O'clock' 8-) + */ + +static int tcp_fin(struct sock *sk, struct tcphdr *th, unsigned long saddr, struct device *dev) { - DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n", - sk, th, saddr, dev)); + DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n", + sk, th, saddr, dev)); - if (!sk->dead) { - 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: - case TCP_FIN_WAIT2: - break; /* we got a retransmit of the fin. */ + if (!sk->dead) + { + sk->state_change(sk); + } - case TCP_FIN_WAIT1: - /* Contains the one that needs to be acked */ - sk->fin_seq = th->seq+1; - sk->state = TCP_FIN_WAIT2; - break; + 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; - default: - case TCP_TIME_WAIT: - sk->state = TCP_LAST_ACK; + case TCP_CLOSE_WAIT: + case TCP_FIN_WAIT2: + break; /* we got a retransmit of the fin. */ + + case TCP_FIN_WAIT1: + /* Contains the one that needs to be acked */ + sk->fin_seq = th->seq+1; + sk->state = TCP_FIN_WAIT2; + break; - /* Start the timers. */ - reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return(0); - } - sk->ack_backlog++; + default: + case TCP_TIME_WAIT: + sk->state = TCP_LAST_ACK; + + /* Start the timers. */ + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + return(0); + } + sk->ack_backlog++; - return(0); + return(0); } @@ -2861,124 +3023,164 @@ } -/* This will initiate an outgoing connection. */ -static int -tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) +/* + * This will initiate an outgoing connection. + */ + +static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) { - struct sk_buff *buff; - struct sockaddr_in sin; - struct device *dev=NULL; - unsigned char *ptr; - int tmp; - struct tcphdr *t1; - int err; - - if (sk->state != TCP_CLOSE) return(-EISCONN); - if (addr_len < 8) return(-EINVAL); + struct sk_buff *buff; + struct sockaddr_in sin; + struct device *dev=NULL; + unsigned char *ptr; + int tmp; + struct tcphdr *t1; + int err; - err=verify_area(VERIFY_READ, usin, addr_len); - if(err) - return err; + if (sk->state != TCP_CLOSE) + return(-EISCONN); + if (addr_len < 8) + return(-EINVAL); + + err=verify_area(VERIFY_READ, usin, addr_len); + if(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))); - - /* 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); - } + DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr))); + + /* + * connect() to INADDR_ANY means loopback (BSD'ism). + */ + + 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)) - return -EBUSY; + /* + * Connect back to the same socket: Blows up so disallow it + */ - sk->inuse = 1; - sk->daddr = sin.sin_addr.s_addr; - 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); + if(sk->saddr == sin.sin_addr.s_addr && sk->num==ntohs(sin.sin_port)) + return -EBUSY; - buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); - if (buff == NULL) { - return(-ENOMEM); - } - sk->inuse = 1; - buff->len = 24; - buff->sk = sk; - buff->free = 1; - t1 = (struct tcphdr *) buff->data; + sk->inuse = 1; + sk->daddr = sin.sin_addr.s_addr; + 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); - /* 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, + buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); + if (buff == NULL) + { + 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); - if (tmp < 0) { - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - release_sock(sk); - return(-ENETUNREACH); - } - buff->len += tmp; - t1 = (struct tcphdr *)((char *)t1 +tmp); + if (tmp < 0) + { + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + release_sock(sk); + return(-ENETUNREACH); + } - 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; + buff->len += tmp; + t1 = (struct tcphdr *)((char *)t1 +tmp); -/* use 512 or whatever user asked for */ - if (sk->user_mss) - 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 - if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr)) + if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr)) #else - if ((sk->saddr ^ sk->daddr) & dev->pa_mask) + if ((sk->saddr ^ sk->daddr) & dev->pa_mask) #endif - sk->mtu = 576 - HEADER_SIZE; - else - sk->mtu = MAX_WINDOW; - } -/* but not bigger than device MTU */ - sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE); + sk->mtu = 576 - HEADER_SIZE; + else + sk->mtu = MAX_WINDOW; + } + /* + * but not bigger than device MTU + */ - /* Put in the TCP options to say MTU. */ - 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, + sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE); + + /* + * Put in the TCP options to say MTU. + */ + + 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); - /* This must go first otherwise a really quick response will get reset. */ - sk->state = TCP_SYN_SENT; - 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; + /* + * This must go first otherwise a really quick response will get reset. + */ - sk->prot->queue_xmit(sk, dev, buff, 0); - tcp_statistics.TcpActiveOpens++; - tcp_statistics.TcpOutSegs++; + sk->state = TCP_SYN_SENT; + 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); + tcp_statistics.TcpActiveOpens++; + tcp_statistics.TcpOutSegs++; - release_sock(sk); - return(0); + release_sock(sk); + return(0); } @@ -3451,69 +3653,73 @@ /* - * This routine sends a packet with an out of date sequence - * number. It assumes the other end will try to ack it. - */ -static void -tcp_write_wakeup(struct sock *sk) + * This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. + */ + +static void tcp_write_wakeup(struct sock *sk) { - struct sk_buff *buff; - struct tcphdr *t1; - struct device *dev=NULL; - int tmp; + struct sk_buff *buff; + struct tcphdr *t1; + struct device *dev=NULL; + int tmp; - if (sk->zapped) - return; /* Afer a valid reset we can send no more */ + if (sk->zapped) + return; /* Afer a valid reset we can send no more */ - if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && - sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2) - return; + if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && + sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2) + return; - buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); - if (buff == NULL) return; + buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); + if (buff == NULL) + return; - buff->len = sizeof(struct tcphdr); - buff->free = 1; - buff->sk = sk; - DPRINTF((DBG_TCP, "in tcp_write_wakeup\n")); - t1 = (struct tcphdr *) buff->data; + buff->len = sizeof(struct tcphdr); + buff->free = 1; + buff->sk = sk; + buff->localroute = sk->localroute; - /* Put in the IP header and routing stuff. */ - tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, + DPRINTF((DBG_TCP, "in tcp_write_wakeup\n")); + 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); - if (tmp < 0) { - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - return; - } + if (tmp < 0) + { + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + return; + } - buff->len += tmp; - t1 = (struct tcphdr *)((char *)t1 +tmp); + buff->len += 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. - * This should cause the other end to send an ack. - */ - t1->seq = htonl(sk->sent_seq-1); - t1->ack = 1; - t1->res1= 0; - t1->res2= 0; - t1->rst = 0; - t1->urg = 0; - t1->psh = 0; - t1->fin = 0; - t1->syn = 0; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/); - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); - - /* Send it and free it. - * This will prevent the timer from automatically being restarted. - */ - sk->prot->queue_xmit(sk, dev, buff, 1); - tcp_statistics.TcpOutSegs++; + /* + * Use a previous sequence. + * This should cause the other end to send an ack. + */ + t1->seq = htonl(sk->sent_seq-1); + t1->ack = 1; + t1->res1= 0; + t1->res2= 0; + t1->rst = 0; + t1->urg = 0; + t1->psh = 0; + t1->fin = 0; + t1->syn = 0; + t1->ack_seq = ntohl(sk->acked_seq); + t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + + /* Send it and free it. + * This will prevent the timer from automatically being restarted. + */ + sk->prot->queue_xmit(sk, dev, buff, 1); + tcp_statistics.TcpOutSegs++; } void diff -u --new-file --recursive v1.1.5/linux/net/inet/udp.c linux/net/inet/udp.c --- v1.1.5/linux/net/inet/udp.c Tue Apr 19 10:54:07 1994 +++ linux/net/inet/udp.c Tue Apr 19 07:24:55 1994 @@ -250,7 +250,7 @@ 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 device *dev; @@ -281,6 +281,7 @@ skb->sk = NULL; /* to avoid changing sk->saddr */ skb->free = 1; + skb->localroute = sk->localroute|(rt&MSG_DONTROUTE); /* * Now build the IP and MAC header. @@ -357,7 +358,7 @@ /* * Check the flags. We support no flags for UDP sending */ - if (flags) + if (flags&~MSG_DONTROUTE) return(-EINVAL); if (len < 0) return(-EINVAL); @@ -400,7 +401,7 @@ sk->inuse = 1; /* 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. */ release_sock(sk); @@ -601,27 +602,29 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) { - struct sockaddr_in sin; - int er; + struct sockaddr_in sin; + int er; - if (addr_len < sizeof(sin)) - return(-EINVAL); + if (addr_len < sizeof(sin)) + return(-EINVAL); + + er=verify_area(VERIFY_READ, usin, sizeof(sin)); + if(er) + return er; - er=verify_area(VERIFY_READ, usin, sizeof(sin)); - if(er) - return er; - - memcpy_fromfs(&sin, usin, sizeof(sin)); - if (sin.sin_family && sin.sin_family != AF_INET) - return(-EAFNOSUPPORT); + memcpy_fromfs(&sin, usin, sizeof(sin)); + if (sin.sin_family && sin.sin_family != AF_INET) + 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) - return -EACCES; /* Must turn broadcast on first */ + if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + return -EACCES; /* Must turn broadcast on first */ - sk->daddr = sin.sin_addr.s_addr; - sk->dummy_th.dest = sin.sin_port; - sk->state = TCP_ESTABLISHED; - return(0); + sk->daddr = sin.sin_addr.s_addr; + sk->dummy_th.dest = sin.sin_port; + sk->state = TCP_ESTABLISHED; + return(0); }