Hopefully this helps anyone attempting such a feat, as well as clearing up
a few important points/dependencies.
-
register_filesystem (struct file_system_type *fstype)
=====================================================
int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
[optional]
- The follow_link function is only necessary if a filesystem uses a really
- twisted form of symbolic links - namely if the symbolic link comes from a
- foreign filesystem that makes no sense....
- I threw this one out - too much redundant code!
+ follow_link must be implemented if readlink is implemented.
+ Note that follow_link can return a different inode than a
+ lookup_dentry() on the result of readlink() would return.
+ The proc filesystem, in particular, uses this feature heavily.
+ For most user filesystems, however, follow_link() and readlink()
+ should return consistent results.
int (*readpage) (struct inode *, struct page *); [optional]
int (*writepage) (struct inode *, struct page *); [mandatory with readpage]
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 99
+SUBLEVEL = 100
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
{
int hdr_len = 0;
skb->protocol = type;
- hdr_len = wan_encapsulate(skb, dev);
+ hdr_len = wanrouter_encapsulate(skb, dev);
if (hdr_len < 0)
{
hdr_len = 0;
/* Decapsulate packet and pass it up the protocol stack */
skb->dev = dev;
buf = skb_pull(skb, 1); /* remove hardware header */
- if (!wan_type_trans(skb, dev))
+ if (!wanrouter_type_trans(skb, dev))
{
/* can't decapsulate packet */
dev_kfree_skb(skb);
skb->dev = dev;
/* remove hardware header */
buf = skb_pull(skb, 1);
- if (!wan_type_trans(skb, dev))
+ if (!wanrouter_type_trans(skb, dev))
{
/* can't decapsulate packet */
dev_kfree_skb(skb);
stack */
new_skb->dev = dev;
buf = skb_pull(new_skb, 1); /* remove hardware header */
- if (!wan_type_trans(new_skb, dev))
+ if (!wanrouter_type_trans(new_skb, dev))
{
++chan->UDP_FPIPE_mgmt_not_passed_to_stack;
/* can't decapsulate packet */
new_skb->dev = dev;
/* remove hardware header */
buf = skb_pull(new_skb, 1);
- if (!wan_type_trans(new_skb, dev))
+ if (!wanrouter_type_trans(new_skb, dev))
{
/* can't decapsulate packet */
++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
skb->protocol = type;
if (!chan->protocol)
{
- hdr_len = wan_encapsulate(skb, dev);
+ hdr_len = wanrouter_encapsulate(skb, dev);
if (hdr_len < 0)
{
hdr_len = 0;
chan->rx_skb = NULL; /* dequeue packet */
/* Decapsulate packet, if necessary */
- if (!skb->protocol && !wan_type_trans(skb, dev))
+ if (!skb->protocol && !wanrouter_type_trans(skb, dev))
{
/* can't decapsulate packet */
dev_kfree_skb(skb);
wandev->setup = &setup;
wandev->shutdown = &shutdown;
wandev->ioctl = &ioctl;
- err = register_wandev(wandev);
+ err = register_wan_device(wandev);
if (err)
{
printk(KERN_ERR
for (i = 0; i < ncards; ++i)
{
sdla_t* card = &card_array[i];
- unregister_wandev(card->devname);
+ unregister_wan_device(card->devname);
}
kfree(card_array);
}
dev->name = namelist+(NAMELEN*this_dev);
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
- dev->init = ultra_probe;
+ dev->init = ultramca_probe;
if (io[this_dev] == 0)
{
if (this_dev != 0)
#include "hosts.h"
#include <scsi/scsi_ioctl.h>
-#define MAX_RETRIES 5
-#define MAX_TIMEOUT (9 * HZ)
+#define NORMAL_RETRIES 5
+#define NORMAL_TIMEOUT (10 * HZ)
+#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
+#define START_STOP_TIMEOUT (60 * HZ)
+#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
+#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
+
#define MAX_BUF PAGE_SIZE
#define max(a,b) (((a) > (b)) ? (a) : (b))
/*
*
* The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
- * The MAX_TIMEOUT and MAX_RETRIES variables are used.
+ * The NORMAL_TIMEOUT and NORMAL_RETRIES variables are used.
*
* dev is the SCSI device struct ptr, *(int *) arg is the length of the
* input data, if any, not including the command string & counts,
}
}
-static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
+static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
+ int timeout, int retries)
{
unsigned long flags;
int result;
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
spin_lock_irqsave(&io_request_lock, flags);
- scsi_do_cmd(SCpnt, cmd, NULL, 0,
- scsi_ioctl_done, MAX_TIMEOUT,
- MAX_RETRIES);
+ scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries);
spin_unlock_irqrestore(&io_request_lock, flags);
down(&sem);
SCpnt->request.sem = NULL;
switch (opcode)
{
case FORMAT_UNIT:
- timeout = 2 * 60 * 60 * HZ; /* 2 Hours */
+ timeout = FORMAT_UNIT_TIMEOUT;
retries = 1;
break;
case START_STOP:
- timeout = 2 * 60 * HZ; /* 2 minutes */
- retries = 1;
+ timeout = START_STOP_TIMEOUT;
+ retries = NORMAL_RETRIES;
break;
case MOVE_MEDIUM:
+ timeout = MOVE_MEDIUM_TIMEOUT;
+ retries = NORMAL_RETRIES;
+ break;
case READ_ELEMENT_STATUS:
- timeout = 5 * 60 * HZ; /* 5 minutes */
- retries = 1;
+ timeout = READ_ELEMENT_STATUS_TIMEOUT;
+ retries = NORMAL_RETRIES;
break;
default:
- timeout = MAX_TIMEOUT;
- retries = MAX_RETRIES;
+ timeout = NORMAL_TIMEOUT;
+ retries = NORMAL_RETRIES;
break;
}
scsi_cmd[1] = dev->lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+ NORMAL_TIMEOUT, NORMAL_RETRIES);
break;
case SCSI_IOCTL_DOORUNLOCK:
if (!dev->removable || !dev->lockable) return 0;
scsi_cmd[1] = dev->lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+ NORMAL_TIMEOUT, NORMAL_RETRIES);
case SCSI_IOCTL_TEST_UNIT_READY:
scsi_cmd[0] = TEST_UNIT_READY;
scsi_cmd[1] = dev->lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 0;
- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+ NORMAL_TIMEOUT, NORMAL_RETRIES);
+ break;
+ case SCSI_IOCTL_START_UNIT:
+ scsi_cmd[0] = START_STOP;
+ scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+ scsi_cmd[4] = 1;
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+ START_STOP_TIMEOUT, NORMAL_RETRIES);
+ break;
+ case SCSI_IOCTL_STOP_UNIT:
+ scsi_cmd[0] = START_STOP;
+ scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+ scsi_cmd[4] = 0;
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+ START_STOP_TIMEOUT, NORMAL_RETRIES);
break;
default :
if (dev->host->hostt->ioctl)
}
inode.i_rdev = full_dev; /* This is all we really need here */
- retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
+ /* Using Start/Stop enables differentiation between drive with
+ * no cartridge loaded - NOT READY, drive with changed cartridge -
+ * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
+ * This also handles drives that auto spin down. eg iomega jaz 1GB
+ * as this will spin up the drive.
+ */
+ retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
+
if(retval){ /* Unable to test, unit probably not ready. This usually
* means there is no disc in the drive. Mark as changed,
* and we will figure it out later once the drive is
* more memory, but aren't really sure how much. So we
* carefully try to free a _bit_ of our dcache, but not
* too much.
+ *
+ * Priority:
+ * 0 - very urgent: schrink everything
+ * ...
+ * 6 - base-level: try to shrink a bit.
*/
-void shrink_dcache_memory(void)
+void shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
int count = select_dcache(32, 8);
if (count)
- prune_dcache(count);
+ prune_dcache((count << 6) >> priority);
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
*
* The new code replaces the old recursive symlink resolution with
* an iterative one (in case of non-nested symlink chains). It does
- * this by looking up the symlink name from the particular filesystem,
- * and then follows this name as if it were a user-supplied one. This
- * is done solely in the VFS level, such that <fs>_follow_link() is not
- * used any more and could be removed in future. As a side effect,
- * dir_namei(), _namei() and follow_link() are now replaced with a single
- * function lookup_dentry() that can handle all the special cases of the former
- * code.
+ * this with calls to <fs>_follow_link().
+ * As a side effect, dir_namei(), _namei() and follow_link() are now
+ * replaced with a single function lookup_dentry() that can handle all
+ * the special cases of the former code.
*
* With the new dcache, the pathname is stored at each inode, at least as
* long as the refcount of the inode is positive. As a side effect, the
* size of the dcache depends on the inode cache and thus is dynamic.
+ *
+ * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink
+ * resolution to correspond with current state of the code.
+ *
+ * Note that the symlink resolution is not *completely* iterative.
+ * There is still a significant amount of tail- and mid- recursion in
+ * the algorithm. Also, note that <fs>_readlink() is not used in
+ * lookup_dentry(): lookup_dentry() on the result of <fs>_readlink()
+ * may return different results than <fs>_follow_link(). Many virtual
+ * filesystems (including /proc) exhibit this behavior.
*/
/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation:
__u32 info,
struct device *dev);
-extern void icmpv6_init(struct net_proto_family *ops);
+extern int icmpv6_init(struct net_proto_family *ops);
extern int icmpv6_err_convert(int type, int code,
int *err);
+extern void icmpv6_cleanup(void);
+extern void icmpv6_param_prob(struct sk_buff *skb,
+ int code, void *pos);
#endif
#endif
*/
};
+
+struct ipv6_opt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ /*
+ * TLV encoded option data follows.
+ */
+};
+
+#define ipv6_destopt_hdr ipv6_opt_hdr
+#define ipv6_hopopt_hdr ipv6_opt_hdr
+
+#ifdef __KERNEL__
+#define ipv6_optlen(p) (((p)->hdrlen+1) << 3)
+#endif
+
+
+
/*
* routing header type 0 (used in cmsghdr struct)
*/
/*
* protocol options
- * usualy carried in IPv6 extension headers
+ * usually carried in IPv6 extension headers
*/
struct ipv6_rt_hdr *srcrt; /* Routing Header */
-
};
+
#endif
#endif
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ipv6.h,v 1.9 1998/03/08 05:55:20 davem Exp $
+ * $Id: ipv6.h,v 1.10 1998/04/30 16:24:14 freitag Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
struct frag_queue *prev;
__u32 id; /* fragment id */
+ struct in6_addr saddr;
+ struct in6_addr daddr;
struct timer_list timer; /* expire timer */
struct ipv6_frag *fragments;
struct device *dev;
extern void ipv6opt_free(struct ipv6_options *opt);
+extern struct ipv6_opt_hdr * ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr,
+ u8 *nexthdrp, int len);
+
+
/*
* socket options (ipv6_sockglue.c)
struct icmp6hdr *hdr,
int len);
+extern void igmp6_cleanup(void);
+
extern __inline__ struct neighbour * ndisc_get_neigh(struct device *dev, struct in6_addr *addr)
{
/* PMTU discovery event has occurred. */
sk->mtu = dst->pmtu;
- sk->mss = sk->mtu - mss_distance;
+ mss_now = sk->mss = sk->mtu - mss_distance;
}
if(tp->sack_ok && tp->num_sacks)
#define SCSI_IOCTL_TEST_UNIT_READY 2
#define SCSI_IOCTL_BENCHMARK_COMMAND 3
#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */
+#define SCSI_IOCTL_START_UNIT 5
+#define SCSI_IOCTL_STOP_UNIT 6
/* The door lock/unlock constants are compatible with Sun constants for
the cdrom */
#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */
switch (state) {
do {
case 0:
- state = 1;
if (shrink_mmap(i, gfp_mask))
return 1;
+ state = 1;
case 1:
- state = 2;
if ((gfp_mask & __GFP_IO) && shm_swap(i, gfp_mask))
return 1;
- default:
- state = 0;
+ state = 2;
+ case 2:
if (swap_out(i, gfp_mask))
return 1;
+ state = 3;
+ case 3:
+ shrink_dcache_memory(i, gfp_mask);
+ state = 0;
i--;
} while ((i - stop) >= 0);
}
schedule();
swapstats.wakeups++;
- /* This will gently shrink the dcache.. */
- shrink_dcache_memory();
-
/*
* Do the background pageout: be
* more aggressive if we're really
extern int lapbeth_init(void);
extern void arcnet_init(void);
extern void ip_auto_config(void);
+#ifdef CONFIG_8xx
+extern int cpm_enet_init(void);
+#endif /* CONFIG_8xx */
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry proc_net_dev = {
#endif
#if defined(CONFIG_ARCNET)
arcnet_init();
+#endif
+#if defined(CONFIG_8xx)
+ cpm_enet_init();
#endif
/*
* SLHC if present needs attaching so other people see it
struct device *dev = skb->dev;
skb->protocol = htons (ETH_P_IPX);
- dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
+ if(dev->hard_header)
+ dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
}
struct datalink_proto *
* license in recognition of the original copyright.
* -- Alan Cox.
*
- * $Id: ip_fw.c,v 1.34 1998/03/20 09:12:06 davem Exp $
+ * $Id: ip_fw.c,v 1.35 1998/04/30 16:29:51 freitag Exp $
*
* Ported from BSD to Linux,
* Alan Cox 22/Nov/1994.
* Wouter Gadeyne : Fixed masquerading support of ftp PORT commands
*
* Juan Jose Ciarlante : Masquerading code moved to ip_masq.c
+ * Andi Kleen : Print frag_offsets and the ip flags properly.
*
* All the real work was done by .....
*
#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
+#ifdef CONFIG_IP_FIREWALL_VERBOSE
+
+/*
+ * VERY ugly piece of code which actually makes kernel printf for
+ * matching packets.
+ */
+
+static char *chain_name(struct ip_fw *chain, int mode)
+{
+ switch (mode) {
+ case IP_FW_MODE_ACCT_IN: return "acct in";
+ case IP_FW_MODE_ACCT_OUT: return "acct out";
+ default:
+ if (chain == ip_fw_fwd_chain)
+ return "fw-fwd";
+ else if (chain == ip_fw_in_chain)
+ return "fw-in";
+ else
+ return "fw-out";
+ }
+}
+
+static char *rule_name(struct ip_fw *f, int mode, char *buf)
+{
+ if (mode == IP_FW_MODE_ACCT_IN || mode == IP_FW_MODE_ACCT_OUT)
+ return "";
+
+ if(f->fw_flg&IP_FW_F_ACCEPT) {
+ if(f->fw_flg&IP_FW_F_REDIR) {
+ sprintf(buf, "acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]);
+ return buf;
+ } else if(f->fw_flg&IP_FW_F_MASQ)
+ return "acc/masq ";
+ else
+ return "acc ";
+ } else if(f->fw_flg&IP_FW_F_ICMPRPL) {
+ return "rej ";
+ } else {
+ return "deny ";
+ }
+}
+
+static void print_packet(struct iphdr *ip,
+ u16 src_port, u16 dst_port, u16 icmp_type,
+ char *chain, char *rule, char *devname)
+{
+ __u32 *opt = (__u32 *) (ip + 1);
+ int opti;
+ __u16 foff = ntohs(ip->frag_off);
+
+ printk(KERN_INFO "IP %s %s%s", chain, rule, devname);
+
+ switch(ip->protocol)
+ {
+ case IPPROTO_TCP:
+ printk(" TCP ");
+ break;
+ case IPPROTO_UDP:
+ printk(" UDP ");
+ break;
+ case IPPROTO_ICMP:
+ printk(" ICMP/%d ", icmp_type);
+ break;
+ default:
+ printk(" PROTO=%d ", ip->protocol);
+ break;
+ }
+ print_ip(ip->saddr);
+ if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+ printk(":%hu", src_port);
+ printk(" ");
+ print_ip(ip->daddr);
+ if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+ printk(":%hu", dst_port);
+ printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu",
+ ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
+ foff & IP_OFFSET, ip->ttl);
+ if (foff & IP_DF) printk(" DF=1");
+ if (foff & IP_MF) printk(" MF=1");
+ for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
+ printk(" O=0x%8.8X", *opt++);
+ printk("\n");
+}
+#endif
/*
* Returns one of the generic firewall policies, like FW_ACCEPT.
}
#ifdef CONFIG_IP_FIREWALL_VERBOSE
- /*
- * VERY ugly piece of code which actually
- * makes kernel printf for matching packets...
- */
-
if (f->fw_flg & IP_FW_F_PRN)
{
- __u32 *opt = (__u32 *) (ip + 1);
- int opti;
-
- if(mode == IP_FW_MODE_ACCT_IN)
- printk(KERN_INFO "IP acct in ");
- else if(mode == IP_FW_MODE_ACCT_OUT)
- printk(KERN_INFO "IP acct out ");
- else {
- if(chain == ip_fw_fwd_chain)
- printk(KERN_INFO "IP fw-fwd ");
- else if(chain == ip_fw_in_chain)
- printk(KERN_INFO "IP fw-in ");
- else
- printk(KERN_INFO "IP fw-out ");
- if(f->fw_flg&IP_FW_F_ACCEPT) {
- if(f->fw_flg&IP_FW_F_REDIR)
- printk("acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]);
- else if(f->fw_flg&IP_FW_F_MASQ)
- printk("acc/masq ");
- else
- printk("acc ");
- } else if(f->fw_flg&IP_FW_F_ICMPRPL)
- printk("rej ");
- else
- printk("deny ");
- }
- printk(rif ? rif->name : "-");
- switch(ip->protocol)
- {
- case IPPROTO_TCP:
- printk(" TCP ");
- break;
- case IPPROTO_UDP:
- printk(" UDP ");
- break;
- case IPPROTO_ICMP:
- printk(" ICMP/%d ", icmp_type);
- break;
- default:
- printk(" PROTO=%d ", ip->protocol);
- break;
- }
- print_ip(ip->saddr);
- if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
- printk(":%hu", src_port);
- printk(" ");
- print_ip(ip->daddr);
- if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
- printk(":%hu", dst_port);
- printk(" L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
- ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
- ip->frag_off, ip->ttl);
- for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
- printk(" O=0x%8.8X", *opt++);
- printk("\n");
+ char buf[16];
+
+ print_packet(ip, src_port, dst_port, icmp_type,
+ chain_name(chain, mode),
+ rule_name(f, mode, buf),
+ rif ? rif->name : "-");
}
#endif
if (mode != IP_FW_MODE_CHK) {
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.114 1998/04/28 06:42:22 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.116 1998/05/02 14:50:11 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
return 1;
}
-#if 0 /* Not working yet... -DaveM */
-static void tcp_compute_tsack(struct sock *sk, struct tcp_opt *tp)
-{
- struct sk_buff *skb = skb_peek(&sk->write_queue);
- __u32 tstamp = tp->rcv_tsecr;
- int fack_count = 0;
-
- while((skb != NULL) &&
- (skb != tp->send_head) &&
- (skb != (struct sk_buff *)&sk->write_queue)) {
- if(TCP_SKB_CB(skb)->when == tstamp) {
- __u8 sacked = TCP_SKB_CB(skb)->sacked;
-
- sacked |= TCPCB_SACKED_ACKED;
- if(sacked & TCPCB_SACKED_RETRANS)
- tp->retrans_out--;
- TCP_SKB_CB(skb)->sacked = sacked;
- }
- if(!before(TCP_SKB_CB(skb)->when, tstamp))
- fack_count++;
- skb = skb->next;
- }
- if(fack_count > tp->fackets_out)
- tp->fackets_out = fack_count;
-}
-#endif
-
#define FLAG_DATA 0x01 /* Incoming frame contained data. */
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */
if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) {
/* This is the standard reno style fast retransmit branch. */
-#if 0 /* Not working yet... -DaveM */
- /* If not doing SACK, but doing timestamps, compute timestamp
- * based pseudo-SACKs when we see duplicate ACKs.
- */
- if(!tp->sack_ok && tp->saw_tstamp)
- tcp_compute_tsack(sk, tp);
-#endif
/* 1. When the third duplicate ack is received, set ssthresh
* to one half the current congestion window, but no less
* than two segments. Retransmit the missing segment.
while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) {
struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
+ __u8 sacked = scb->sacked;
/* If our packet is before the ack sequence we can
* discard it as it's confirmed to have arrived at
* connection startup slow start one packet too
* quickly. This is severely frowned upon behavior.
*/
+ if(sacked & TCPCB_SACKED_RETRANS && tp->retrans_out)
+ tp->retrans_out--;
if(!(scb->flags & TCPCB_FLAG_SYN)) {
- __u8 sacked = scb->sacked;
-
acked |= FLAG_DATA_ACKED;
- if(sacked & TCPCB_SACKED_RETRANS) {
+ if(sacked & TCPCB_SACKED_RETRANS)
acked |= FLAG_RETRANS_DATA_ACKED;
-
- /* XXX The race is, fast retrans frame -->
- * XXX retrans timeout sends older frame -->
- * XXX ACK arrives for fast retrans frame -->
- * XXX retrans_out goes negative --> splat.
- * XXX Please help me find a better way -DaveM
- */
- if(tp->retrans_out)
- tp->retrans_out--;
- }
if(tp->fackets_out)
tp->fackets_out--;
} else {
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.142 1998/04/30 12:00:45 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.145 1998/05/02 12:47:13 davem Exp $
*
* IPv4 specific functions
*
#include <linux/config.h>
#include <linux/types.h>
-#include <linux/stddef.h>
#include <linux/fcntl.h>
#include <linux/random.h>
#include <linux/init.h>
#include <asm/segment.h>
#include <linux/inet.h>
+#include <linux/stddef.h>
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
extern int sysctl_tcp_sack;
extern int sysctl_tcp_syncookies;
extern int sysctl_ip_dynaddr;
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
/* Check TCP sequence numbers in ICMP packets. */
#define ICMP_MIN_LENGTH 8
return tb;
}
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
/* Ensure that the bound bucket for the port exists.
* Return 0 on success.
*/
static __inline__ int tcp_bucket_check(unsigned short snum)
{
- if (tcp_bound_hash[tcp_bhashfn(snum)] == NULL &&
- tcp_bucket_create(snum) == NULL)
+ struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(snum)];
+ for( ; (tb && (tb->port != snum)); tb = tb->next)
+ ;
+ if(tb == NULL && tcp_bucket_create(snum) == NULL)
return 1;
else
return 0;
}
+#endif
static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
{
result = 1;
}
}
- if((result == 0) &&
- (tb == NULL) &&
- (tcp_bucket_create(snum) == NULL))
- result = 1;
+ if(result == 0) {
+ if(tb == NULL) {
+ if(tcp_bucket_create(snum) == NULL)
+ result = 1;
+ } else {
+ /* It could be pending garbage collection, this
+ * kills the race and prevents it from disappearing
+ * out from under us by the time we use it. -DaveM
+ */
+ if(tb->owners == NULL && !(tb->flags & TCPB_FLAG_LOCKED)) {
+ tb->flags = TCPB_FLAG_LOCKED;
+ tcp_dec_slow_timer(TCP_SLT_BUCKETGC);
+ }
+ }
+ }
go_like_smoke:
SOCKHASH_UNLOCK();
return result;
if (!newsk)
goto exit;
+ if (newsk->rcvbuf < (3 * newsk->mtu))
+ newsk->rcvbuf = min ((3 * newsk->mtu), sysctl_rmem_max);
+ if (newsk->sndbuf < (3 * newsk->mtu))
+ newsk->sndbuf = min ((3 * newsk->mtu), sysctl_wmem_max);
+
sk->tp_pinfo.af_tcp.syn_backlog--;
sk->ack_backlog++;
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_timer.c,v 1.50 1998/04/14 09:08:59 davem Exp $
+ * Version: $Id: tcp_timer.c,v 1.51 1998/05/02 15:19:26 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*/
if(tp->sack_ok) {
struct sk_buff *skb = skb_peek(&sk->write_queue);
- __u8 toclear = TCPCB_SACKED_ACKED;
- if(tp->retransmits == 0)
- toclear |= TCPCB_SACKED_RETRANS;
while((skb != NULL) &&
(skb != tp->send_head) &&
(skb != (struct sk_buff *)&sk->write_queue)) {
- TCP_SKB_CB(skb)->sacked &= ~(toclear);
+ TCP_SKB_CB(skb)->sacked &=
+ ~(TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS);
skb = skb->next;
}
- tp->fackets_out = 0;
}
/* Retransmission. */
tp->retrans_head = NULL;
+ tp->fackets_out = 0;
+ tp->retrans_out = 0;
if (tp->retransmits == 0) {
/* remember window where we lost
* "one half of the current window but at least 2 segments"
*/
- tp->retrans_out = 0;
tp->snd_ssthresh = max(tp->snd_cwnd >> (1 + TCP_CWND_SHIFT), 2);
tp->snd_cwnd = (1 << TCP_CWND_SHIFT);
}
*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
+ * Andi Kleen <ak@muc.de>
*
- * $Id: exthdrs.c,v 1.5 1998/02/12 07:43:39 davem Exp $
+ * $Id: exthdrs.c,v 1.6 1998/04/30 16:24:20 freitag Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#include <asm/uaccess.h>
+
+#define swap(a,b) do { typeof (a) tmp; tmp = (a); (a) = (b); (b) = (tmp); } while(0)
+
/*
* inbound
*/
*/
int ipv6opt_bld_rthdr(struct sk_buff *skb, struct ipv6_options *opt,
- struct in6_addr *addr, int proto)
+ struct in6_addr *addr)
{
struct rt0_hdr *phdr, *ihdr;
int hops;
ipv6_addr_copy(phdr->addr + (hops - 1), addr);
- phdr->rt_hdr.nexthdr = proto;
-
+ phdr->rt_hdr.nexthdr = proto;
return NEXTHDR_ROUTING;
}
#endif
+
+/*
+ * find out if nexthdr is an extension header or a protocol
+ */
+
+static __inline__ int ipv6_ext_hdr(u8 nexthdr)
+{
+ /*
+ * find out if nexthdr is an extension header or a protocol
+ */
+ return ( (nexthdr == NEXTHDR_HOP) ||
+ (nexthdr == NEXTHDR_ROUTING) ||
+ (nexthdr == NEXTHDR_FRAGMENT) ||
+ (nexthdr == NEXTHDR_ESP) ||
+ (nexthdr == NEXTHDR_AUTH) ||
+ (nexthdr == NEXTHDR_NONE) ||
+ (nexthdr == NEXTHDR_DEST) );
+
+}
+
+/*
+ * Skip any extension headers. This is used by the ICMP module.
+ *
+ * Note that strictly speaking this conflicts with RFC1883 4.0:
+ * ...The contents and semantics of each extension header determine whether
+ * or not to proceed to the next header. Therefore, extension headers must
+ * be processed strictly in the order they appear in the packet; a
+ * receiver must not, for example, scan through a packet looking for a
+ * particular kind of extension header and process that header prior to
+ * processing all preceding ones.
+ *
+ * We do exactly this. This is a protocol bug. We can't decide after a
+ * seeing an unknown discard-with-error flavour TLV option if it's a
+ * ICMP error message or not (errors should never be send in reply to
+ * ICMP error messages).
+ *
+ * But I see no other way to do this. This might need to be reexamined
+ * when Linux implements ESP (and maybe AUTH) headers.
+ */
+struct ipv6_opt_hdr *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr,
+ u8 *nexthdrp, int len)
+{
+ u8 nexthdr = *nexthdrp;
+
+ while (ipv6_ext_hdr(nexthdr)) {
+ int hdrlen;
+
+ if (nexthdr == NEXTHDR_NONE)
+ return NULL;
+ if (len < sizeof(struct ipv6_opt_hdr)) /* be anal today */
+ return NULL;
+
+ hdrlen = ipv6_optlen(hdr);
+ if (len < hdrlen)
+ return NULL;
+
+ nexthdr = hdr->nexthdr;
+ hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen);
+ len -= hdrlen;
+ }
+
+ /* Hack.. Do the same for AUTH headers? */
+ if (nexthdr == NEXTHDR_ESP)
+ return NULL;
+
+ *nexthdrp = nexthdr;
+ return hdr;
+}
+
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.15 1998/03/21 07:28:03 davem Exp $
+ * $Id: icmp.c,v 1.17 1998/05/01 10:31:41 davem Exp $
*
* Based on net/ipv4/icmp.c
*
* Changes:
*
* Andi Kleen : exception handling
+ * Andi Kleen add rate limits. never reply to a icmp.
+ * add more length checks and other fixes.
*/
#define __NO_VERSION__
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#include <net/icmp.h>
#include <asm/uaccess.h>
#include <asm/system.h>
return 0;
}
+
+/*
+ * Slightly more convenient version of icmpv6_send.
+ */
+void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos)
+{
+ int offset = (u8*)pos - (u8*)skb->nh.ipv6h;
+
+ icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev);
+ kfree_skb(skb);
+}
+
+static inline int is_icmp(struct ipv6hdr *hdr, int len)
+{
+ __u8 nexthdr = hdr->nexthdr;
+
+ if (!ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len))
+ return 0;
+ return nexthdr == IPPROTO_ICMP;
+}
+
+int sysctl_icmpv6_time = 1*HZ;
+
+/*
+ * Check the ICMP output rate limit
+ */
+static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
+ struct flowi *fl)
+{
+#if 0
+ struct dst_entry *dst;
+ int allow = 0;
+#endif
+ /* Informational messages are not limited. */
+ if (type & 0x80)
+ return 1;
+
+#if 0 /* not yet, first fix routing COW */
+
+ /*
+ * Look up the output route.
+ * XXX: perhaps the expire for routing entries cloned by
+ * this lookup should be more aggressive (not longer than timeout).
+ */
+ dst = ip6_route_output(sk, fl, 1);
+ if (dst->error)
+ ipv6_statistics.Ip6OutNoRoutes++;
+ else
+ allow = xrlim_allow(dst, sysctl_icmpv6_time);
+ dst_release(dst);
+ return allow;
+#else
+ return 1;
+#endif
+}
+
/*
* an inline helper for the "simple" if statement below
* checks if parameter problem report is caused by an
return;
}
+ /*
+ * Never answer to a ICMP packet.
+ */
+ if (is_icmp(hdr, (u8*)skb->tail - (u8*)hdr)) {
+ printk(KERN_DEBUG "icmpv6_send: no reply to icmp\n");
+ return;
+ }
+
+ fl.proto = IPPROTO_ICMPV6;
+ fl.nl_u.ip6_u.daddr = &hdr->saddr;
+ fl.nl_u.ip6_u.saddr = saddr;
+ fl.oif = iif;
+ fl.uli_u.icmpt.type = type;
+ fl.uli_u.icmpt.code = code;
+
+ if (!icmpv6_xrlim_allow(sk, type, &fl))
+ return;
+
/*
* ok. kick it. checksum will be provided by the
* getfrag_t callback.
msg.len = len;
- fl.proto = IPPROTO_ICMPV6;
- fl.nl_u.ip6_u.daddr = &hdr->saddr;
- fl.nl_u.ip6_u.saddr = saddr;
- fl.oif = iif;
- fl.uli_u.icmpt.type = type;
- fl.uli_u.icmpt.code = code;
-
ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
MSG_DONTWAIT);
dst_release(xchg(&sk->dst_cache, NULL));
}
-static __inline__ int ipv6_ext_hdr(u8 nexthdr)
-{
- /*
- * find out if nexthdr is an extension header or a protocol
- */
- return ( (nexthdr == NEXTHDR_HOP) ||
- (nexthdr == NEXTHDR_ROUTING) ||
- (nexthdr == NEXTHDR_FRAGMENT) ||
- (nexthdr == NEXTHDR_ESP) ||
- (nexthdr == NEXTHDR_AUTH) ||
- (nexthdr == NEXTHDR_NONE) ||
- (nexthdr == NEXTHDR_DEST) );
-
-}
-
static void icmpv6_notify(struct sk_buff *skb,
int type, int code, unsigned char *buff, int len,
struct in6_addr *saddr, struct in6_addr *daddr,
struct ipv6hdr *hdr = (struct ipv6hdr *) buff;
struct inet6_protocol *ipprot;
struct sock *sk;
- char * pbuff;
+ struct ipv6_opt_hdr *pb;
__u32 info = 0;
int hash;
u8 nexthdr;
- /* now skip over extension headers */
-
nexthdr = hdr->nexthdr;
- pbuff = (char *) (hdr + 1);
+ pb = (struct ipv6_opt_hdr *) (hdr + 1);
len -= sizeof(struct ipv6hdr);
+ if (len < 0)
+ return;
- while (ipv6_ext_hdr(nexthdr)) {
- int hdrlen;
-
- if (nexthdr == NEXTHDR_NONE)
- return;
-
- nexthdr = *pbuff;
-
- /* Header length is size in 8-octet units, not
- * including the first 8 octets.
- */
- hdrlen = *(pbuff+1);
- hdrlen = (hdrlen + 1) << 3;
-
- if (hdrlen > len)
- return;
-
- /* Now this is right. */
- pbuff += hdrlen;
- len -= hdrlen;
- }
+ /* now skip over extension headers */
+ pb = ipv6_skip_exthdr(pb, &nexthdr, len);
+ if (!pb)
+ return;
hash = nexthdr & (MAX_INET_PROTOS - 1);
continue;
if (ipprot->err_handler)
- ipprot->err_handler(skb, type, code, pbuff, info,
+ ipprot->err_handler(skb, type, code, (u8*)pb, info,
saddr, daddr, ipprot);
return;
}
return;
while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
- rawv6_err(sk, type, code, pbuff, saddr, daddr);
+ rawv6_err(sk, type, code, (char*)pb, saddr, daddr);
sk = sk->next;
}
}
return 0;
}
-__initfunc(void icmpv6_init(struct net_proto_family *ops))
+__initfunc(int icmpv6_init(struct net_proto_family *ops))
{
struct sock *sk;
int err;
icmpv6_socket->state = SS_UNCONNECTED;
icmpv6_socket->type=SOCK_RAW;
- if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0)
+ if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) {
printk(KERN_DEBUG
"Failed to create the ICMP6 control socket.\n");
-
- MOD_DEC_USE_COUNT;
+ return 1;
+ }
sk = icmpv6_socket->sk;
sk->allocation = GFP_ATOMIC;
ndisc_init(ops);
igmp6_init(ops);
+ return 0;
+}
+
+void icmpv6_cleanup(void)
+{
+ inet6_del_protocol(&icmpv6_protocol);
+#if 0
+ ndisc_cleanup();
+#endif
+ igmp6_cleanup();
}
static struct icmp6_err {
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.8 1998/02/12 07:43:43 davem Exp $
+ * $Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
u8 len;
};
-struct ipv6_destopt_hdr {
- u8 nexthdr;
- u8 hdrlen;
-};
-
-
struct tlvtype_proc {
u8 type;
int (*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.18 1998/03/20 09:12:18 davem Exp $
+ * $Id: ipv6_sockglue.c,v 1.19 1998/04/30 16:24:26 freitag Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
ipv6_sysctl_unregister();
#endif
ip6_route_cleanup();
- ndisc_cleanup();
+ icmpv6_cleanup();
addrconf_cleanup();
}
#endif
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: mcast.c,v 1.14 1998/03/20 09:12:18 davem Exp $
+ * $Id: mcast.c,v 1.15 1998/04/30 16:24:28 freitag Exp $
*
* Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
*
printk(KERN_DEBUG
"Failed to create the IGMP6 control socket.\n");
- MOD_DEC_USE_COUNT;
-
sk = igmp6_socket->sk;
sk->allocation = GFP_ATOMIC;
sk->num = 256; /* Don't receive any data */
#endif
}
+void igmp6_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("net/igmp6", 0);
+#endif
+}
printk(KERN_DEBUG
"Failed to create the NDISC control socket.\n");
- /* Eeeh... What is it? --ANK */
- MOD_DEC_USE_COUNT;
-
sk = ndisc_socket->sk;
sk->allocation = GFP_ATOMIC;
sk->net_pinfo.af_inet6.hop_limit = 255;
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: reassembly.c,v 1.9 1998/02/12 07:43:48 davem Exp $
+ * $Id: reassembly.c,v 1.10 1998/04/30 16:24:32 freitag Exp $
*
* Based on: net/ipv4/ip_fragment.c
*
* 2 of the License, or (at your option) any later version.
*/
+/*
+ * Fixes:
+ * Andi Kleen Make it work with multiple hosts.
+ * More RFC compliance.
+ */
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
static struct frag_queue ipv6_frag_queue = {
&ipv6_frag_queue, &ipv6_frag_queue,
- 0, {0}, NULL, NULL,
- 0
+ 0, {{{0}}}, {{{0}}},
+ {0}, NULL, NULL,
+ 0, 0, NULL
};
static void create_frag_entry(struct sk_buff *skb,
* one it's the kmalloc for a struct ipv6_frag.
* Feel free to try other alternatives...
*/
- reasm_queue(fq, *skb, fhdr);
-
if ((fhdr->frag_off & __constant_htons(0x0001)) == 0) {
fq->last_in = 1;
fq->nhptr = nhptr;
}
+ reasm_queue(fq, *skb, fhdr);
if (fq->last_in) {
if ((nh = reasm_frag_1(fq, skb)))
return 0;
}
-int ipv6_reassembly(struct sk_buff **skb, struct device *dev, __u8 *nhptr,
+int ipv6_reassembly(struct sk_buff **skbp, struct device *dev, __u8 *nhptr,
struct ipv6_options *opt)
{
- struct frag_hdr *fhdr = (struct frag_hdr *) ((*skb)->h.raw);
+ struct sk_buff *skb = *skbp;
+ struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw);
struct frag_queue *fq;
-
+ struct ipv6hdr *hdr;
+
+ if ((u8 *)(fhdr+1) > skb->tail) {
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw);
+ return 0;
+ }
+ hdr = skb->nh.ipv6h;
for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next) {
- if (fq->id == fhdr->identification)
- return reasm_frag(fq, skb, nhptr,fhdr);
+ if (fq->id == fhdr->identification &&
+ !ipv6_addr_cmp(&hdr->saddr, &fq->saddr) &&
+ !ipv6_addr_cmp(&hdr->daddr, &fq->daddr))
+ return reasm_frag(fq, skbp, nhptr,fhdr);
}
- create_frag_entry(*skb, dev, nhptr, fhdr);
+ create_frag_entry(skb, dev, nhptr, fhdr);
return 0;
}
struct frag_hdr *fhdr)
{
struct frag_queue *fq;
+ struct ipv6hdr *hdr;
fq = (struct frag_queue *) kmalloc(sizeof(struct frag_queue),
GFP_ATOMIC);
fq->id = fhdr->identification;
+ hdr = skb->nh.ipv6h;
+ ipv6_addr_copy(&fq->saddr, &hdr->saddr);
+ ipv6_addr_copy(&fq->daddr, &hdr->daddr);
+
fq->dev = dev;
/* init_timer has been done by the memset */
static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb,
- struct frag_hdr *fhdr)
+ struct frag_hdr *fhdr)
{
struct ipv6_frag *nfp, *fp, **bptr;
nfp = (struct ipv6_frag *) kmalloc(sizeof(struct ipv6_frag),
GFP_ATOMIC);
- if (nfp == NULL) {
+ if (nfp == NULL) {
kfree_skb(skb);
return;
}
nfp->len = (ntohs(skb->nh.ipv6h->payload_len) -
((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+ if ((u32)nfp->offset + (u32)nfp->len > 65536) {
+ icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off);
+ goto err;
+ }
nfp->skb = skb;
nfp->fhdr = fhdr;
}
if (fp && fp->offset == nfp->offset) {
- if (fp->len != nfp->len) {
- /* this cannot happen */
+ if (nfp->len != fp->len) {
printk(KERN_DEBUG "reasm_queue: dup with wrong len\n");
}
/* duplicate. discard it. */
- kfree_skb(skb);
- kfree(nfp);
- return;
+ goto err;
}
*bptr = nfp;
nfp->next = fp;
+
+#ifdef STRICT_RFC
+ if (fhdr->frag_off & __constant_htons(0x0001)) {
+ /* Check if the fragment is rounded to 8 bytes.
+ * Required by the RFC.
+ */
+ if (nfp->len & 0x7) {
+ printk(KERN_DEBUG "fragment not rounded to 8bytes\n");
+
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+ &skb->nh.ipv6h->payload_len);
+ goto err;
+ }
+ }
+#endif
+
+ return;
+
+err:
+ kfree(nfp);
+ kfree_skb(skb);
}
/*
/*
* FIXME: If we don't have a checksum we ought to be able
* to defragment and checksum in this pass. [AC]
+ * Note that we don't really know yet whether the protocol
+ * needs checksums at all. It might still be a good idea. -AK
*/
for(fp = fq->fragments; fp; ) {
struct ipv6_frag *back;
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.78 1998/04/16 16:29:22 freitag Exp $
+ * $Id: tcp_ipv6.c,v 1.80 1998/05/02 12:47:15 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
result = 1;
}
}
- if((result == 0) &&
- (tb == NULL) &&
- (tcp_bucket_create(snum) == NULL))
- result = 1;
+ if(result == 0) {
+ if(tb == NULL) {
+ if(tcp_bucket_create(snum) == NULL)
+ result = 1;
+ } else {
+ /* It could be pending garbage collection, this
+ * kills the race and prevents it from disappearing
+ * out from under us by the time we use it. -DaveM
+ */
+ if(tb->owners == NULL && !(tb->flags & TCPB_FLAG_LOCKED)) {
+ tb->flags = TCPB_FLAG_LOCKED;
+ tcp_dec_slow_timer(TCP_SLT_BUCKETGC);
+ }
+ }
+ }
go_like_smoke:
SOCKHASH_UNLOCK();
return result;
isn = tcp_v6_init_sequence(sk,skb);
/*
- * There are no SYN attacks on IPv6, yet...
+ * There are no SYN attacks on IPv6, yet...
*/
if (BACKLOG(sk) >= BACKLOGMAX(sk)) {
printk(KERN_DEBUG "droping syn ack:%d max:%d\n",
EXPORT_SYMBOL(qdisc_new_estimator);
EXPORT_SYMBOL(qdisc_kill_estimator);
#endif
-#ifdef CONFIG_NET_POLICE
+#ifdef CONFIG_NET_CLS_POLICE
EXPORT_SYMBOL(tcf_police);
EXPORT_SYMBOL(tcf_police_locate);
EXPORT_SYMBOL(tcf_police_destroy);