Commit 27df0cf8 authored by Richard Russon's avatar Richard Russon

Merge flatcap.org:/home/flatcap/backup/bk/linux-2.6

into flatcap.org:/home/flatcap/backup/bk/ntfs-2.6
parents ee05a6ce aea2fb73
...@@ -250,8 +250,8 @@ struct sk_buff { ...@@ -250,8 +250,8 @@ struct sk_buff {
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
unsigned long nfmark; unsigned long nfmark;
__u32 nfcache; __u32 nfcache;
struct nf_conntrack *nfct;
__u32 nfctinfo; __u32 nfctinfo;
struct nf_conntrack *nfct;
#ifdef CONFIG_NETFILTER_DEBUG #ifdef CONFIG_NETFILTER_DEBUG
unsigned int nf_debug; unsigned int nf_debug;
#endif #endif
......
...@@ -205,6 +205,13 @@ typedef struct tcp_pcount { ...@@ -205,6 +205,13 @@ typedef struct tcp_pcount {
__u32 val; __u32 val;
} tcp_pcount_t; } tcp_pcount_t;
enum tcp_congestion_algo {
TCP_RENO=0,
TCP_VEGAS,
TCP_WESTWOOD,
TCP_BIC,
};
struct tcp_opt { struct tcp_opt {
int tcp_header_len; /* Bytes of tcp header to send */ int tcp_header_len; /* Bytes of tcp header to send */
...@@ -265,7 +272,7 @@ struct tcp_opt { ...@@ -265,7 +272,7 @@ struct tcp_opt {
__u8 frto_counter; /* Number of new acks after RTO */ __u8 frto_counter; /* Number of new acks after RTO */
__u32 frto_highmark; /* snd_nxt when RTO occurred */ __u32 frto_highmark; /* snd_nxt when RTO occurred */
__u8 unused_pad; __u8 adv_cong; /* Using Vegas, Westwood, or BIC */
__u8 defer_accept; /* User waits for some data after accept() */ __u8 defer_accept; /* User waits for some data after accept() */
/* one byte hole, try to pack */ /* one byte hole, try to pack */
...@@ -412,7 +419,6 @@ struct tcp_opt { ...@@ -412,7 +419,6 @@ struct tcp_opt {
__u32 beg_snd_nxt; /* right edge during last RTT */ __u32 beg_snd_nxt; /* right edge during last RTT */
__u32 beg_snd_una; /* left edge during last RTT */ __u32 beg_snd_una; /* left edge during last RTT */
__u32 beg_snd_cwnd; /* saves the size of the cwnd */ __u32 beg_snd_cwnd; /* saves the size of the cwnd */
__u8 do_vegas; /* do vegas for this connection */
__u8 doing_vegas_now;/* if true, do vegas for this RTT */ __u8 doing_vegas_now;/* if true, do vegas for this RTT */
__u16 cntRTT; /* # of RTTs measured within last RTT */ __u16 cntRTT; /* # of RTTs measured within last RTT */
__u32 minRTT; /* min of RTTs measured within last RTT (in usec) */ __u32 minRTT; /* min of RTTs measured within last RTT (in usec) */
......
...@@ -194,6 +194,18 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j) ...@@ -194,6 +194,18 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j)
return (j * 1000) / HZ; return (j * 1000) / HZ;
#endif #endif
} }
static inline unsigned int jiffies_to_usecs(const unsigned long j)
{
#if HZ <= 1000 && !(1000 % HZ)
return (1000000 / HZ) * j;
#elif HZ > 1000 && !(HZ % 1000)
return (j*1000 + (HZ - 1000))/(HZ / 1000);
#else
return (j * 1000000) / HZ;
#endif
}
static inline unsigned long msecs_to_jiffies(const unsigned int m) static inline unsigned long msecs_to_jiffies(const unsigned int m)
{ {
#if HZ <= 1000 && !(1000 % HZ) #if HZ <= 1000 && !(1000 % HZ)
......
...@@ -74,7 +74,7 @@ extern int ipv6_rcv_saddr_equal(const struct sock *sk, ...@@ -74,7 +74,7 @@ extern int ipv6_rcv_saddr_equal(const struct sock *sk,
const struct sock *sk2); const struct sock *sk2);
extern void addrconf_join_solict(struct net_device *dev, extern void addrconf_join_solict(struct net_device *dev,
struct in6_addr *addr); struct in6_addr *addr);
extern void addrconf_leave_solict(struct net_device *dev, extern void addrconf_leave_solict(struct inet6_dev *idev,
struct in6_addr *addr); struct in6_addr *addr);
/* /*
...@@ -89,6 +89,7 @@ extern int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr, ...@@ -89,6 +89,7 @@ extern int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr,
struct in6_addr *src_addr); struct in6_addr *src_addr);
extern int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr); extern int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr);
extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr);
extern int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr); extern int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr);
extern void ipv6_mc_up(struct inet6_dev *idev); extern void ipv6_mc_up(struct inet6_dev *idev);
extern void ipv6_mc_down(struct inet6_dev *idev); extern void ipv6_mc_down(struct inet6_dev *idev);
...@@ -111,6 +112,7 @@ extern void ipv6_sock_ac_close(struct sock *sk); ...@@ -111,6 +112,7 @@ extern void ipv6_sock_ac_close(struct sock *sk);
extern int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex); extern int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex);
extern int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr); extern int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr);
extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr);
extern int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr); extern int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr);
extern int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr); extern int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr);
......
...@@ -18,7 +18,6 @@ struct dn_neigh { ...@@ -18,7 +18,6 @@ struct dn_neigh {
extern void dn_neigh_init(void); extern void dn_neigh_init(void);
extern void dn_neigh_cleanup(void); extern void dn_neigh_cleanup(void);
extern struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr);
extern int dn_neigh_router_hello(struct sk_buff *skb); extern int dn_neigh_router_hello(struct sk_buff *skb);
extern int dn_neigh_endnode_hello(struct sk_buff *skb); extern int dn_neigh_endnode_hello(struct sk_buff *skb);
extern void dn_neigh_pointopoint_hello(struct sk_buff *skb); extern void dn_neigh_pointopoint_hello(struct sk_buff *skb);
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
...@@ -139,9 +140,6 @@ struct pneigh_entry ...@@ -139,9 +140,6 @@ struct pneigh_entry
u8 key[0]; u8 key[0];
}; };
#define NEIGH_HASHMASK 0x1F
#define PNEIGH_HASHMASK 0xF
/* /*
* neighbour table manipulation * neighbour table manipulation
*/ */
...@@ -175,8 +173,11 @@ struct neigh_table ...@@ -175,8 +173,11 @@ struct neigh_table
struct neigh_parms *parms_list; struct neigh_parms *parms_list;
kmem_cache_t *kmem_cachep; kmem_cache_t *kmem_cachep;
struct neigh_statistics stats; struct neigh_statistics stats;
struct neighbour *hash_buckets[NEIGH_HASHMASK+1]; struct neighbour **hash_buckets;
struct pneigh_entry *phash_buckets[PNEIGH_HASHMASK+1]; unsigned int hash_mask;
__u32 hash_rnd;
unsigned int hash_chain_gc;
struct pneigh_entry **phash_buckets;
}; };
/* flags for neigh_update() */ /* flags for neigh_update() */
...@@ -191,6 +192,8 @@ extern int neigh_table_clear(struct neigh_table *tbl); ...@@ -191,6 +192,8 @@ extern int neigh_table_clear(struct neigh_table *tbl);
extern struct neighbour * neigh_lookup(struct neigh_table *tbl, extern struct neighbour * neigh_lookup(struct neigh_table *tbl,
const void *pkey, const void *pkey,
struct net_device *dev); struct net_device *dev);
extern struct neighbour * neigh_lookup_nodev(struct neigh_table *tbl,
const void *pkey);
extern struct neighbour * neigh_create(struct neigh_table *tbl, extern struct neighbour * neigh_create(struct neigh_table *tbl,
const void *pkey, const void *pkey,
struct net_device *dev); struct net_device *dev);
...@@ -224,6 +227,24 @@ extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); ...@@ -224,6 +227,24 @@ extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
extern void neigh_app_ns(struct neighbour *n); extern void neigh_app_ns(struct neighbour *n);
extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie);
extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *));
extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *));
struct neigh_seq_state {
struct neigh_table *tbl;
void *(*neigh_sub_iter)(struct neigh_seq_state *state,
struct neighbour *n, loff_t *pos);
unsigned int bucket;
unsigned int flags;
#define NEIGH_SEQ_NEIGH_ONLY 0x00000001
#define NEIGH_SEQ_IS_PNEIGH 0x00000002
#define NEIGH_SEQ_SKIP_NOARP 0x00000004
};
extern void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *, unsigned int);
extern void *neigh_seq_next(struct seq_file *, void *, loff_t *);
extern void neigh_seq_stop(struct seq_file *, void *);
extern int neigh_sysctl_register(struct net_device *dev, extern int neigh_sysctl_register(struct net_device *dev,
struct neigh_parms *p, struct neigh_parms *p,
int p_id, int pdev_id, int p_id, int pdev_id,
......
...@@ -1271,6 +1271,13 @@ static __inline__ unsigned int tcp_packets_in_flight(struct tcp_opt *tp) ...@@ -1271,6 +1271,13 @@ static __inline__ unsigned int tcp_packets_in_flight(struct tcp_opt *tp)
tcp_get_pcount(&tp->retrans_out)); tcp_get_pcount(&tp->retrans_out));
} }
/*
* Which congestion algorithim is in use on the connection.
*/
#define tcp_is_vegas(__tp) ((__tp)->adv_cong == TCP_VEGAS)
#define tcp_is_westwood(__tp) ((__tp)->adv_cong == TCP_WESTWOOD)
#define tcp_is_bic(__tp) ((__tp)->adv_cong == TCP_BIC)
/* Recalculate snd_ssthresh, we want to set it to: /* Recalculate snd_ssthresh, we want to set it to:
* *
* Reno: * Reno:
...@@ -1283,7 +1290,7 @@ static __inline__ unsigned int tcp_packets_in_flight(struct tcp_opt *tp) ...@@ -1283,7 +1290,7 @@ static __inline__ unsigned int tcp_packets_in_flight(struct tcp_opt *tp)
*/ */
static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
{ {
if (sysctl_tcp_bic) { if (tcp_is_bic(tp)) {
if (sysctl_tcp_bic_fast_convergence && if (sysctl_tcp_bic_fast_convergence &&
tp->snd_cwnd < tp->bictcp.last_max_cwnd) tp->snd_cwnd < tp->bictcp.last_max_cwnd)
tp->bictcp.last_max_cwnd tp->bictcp.last_max_cwnd
...@@ -1302,11 +1309,6 @@ static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) ...@@ -1302,11 +1309,6 @@ static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
/* Stop taking Vegas samples for now. */ /* Stop taking Vegas samples for now. */
#define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0) #define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0)
/* Is this TCP connection using Vegas (regardless of whether it is taking
* Vegas measurements at the current time)?
*/
#define tcp_is_vegas(__tp) ((__tp)->vegas.do_vegas)
static inline void tcp_vegas_enable(struct tcp_opt *tp) static inline void tcp_vegas_enable(struct tcp_opt *tp)
{ {
...@@ -1340,7 +1342,7 @@ static inline void tcp_vegas_enable(struct tcp_opt *tp) ...@@ -1340,7 +1342,7 @@ static inline void tcp_vegas_enable(struct tcp_opt *tp)
/* Should we be taking Vegas samples right now? */ /* Should we be taking Vegas samples right now? */
#define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now) #define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now)
extern void tcp_vegas_init(struct tcp_opt *tp); extern void tcp_ca_init(struct tcp_opt *tp);
static inline void tcp_set_ca_state(struct tcp_opt *tp, u8 ca_state) static inline void tcp_set_ca_state(struct tcp_opt *tp, u8 ca_state)
{ {
...@@ -2024,7 +2026,7 @@ extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo); ...@@ -2024,7 +2026,7 @@ extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
static inline void tcp_westwood_update_rtt(struct tcp_opt *tp, __u32 rtt_seq) static inline void tcp_westwood_update_rtt(struct tcp_opt *tp, __u32 rtt_seq)
{ {
if (sysctl_tcp_westwood) if (tcp_is_westwood(tp))
tp->westwood.rtt = rtt_seq; tp->westwood.rtt = rtt_seq;
} }
...@@ -2033,13 +2035,13 @@ void __tcp_westwood_slow_bw(struct sock *, struct sk_buff *); ...@@ -2033,13 +2035,13 @@ void __tcp_westwood_slow_bw(struct sock *, struct sk_buff *);
static inline void tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb) static inline void tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb)
{ {
if (sysctl_tcp_westwood) if (tcp_is_westwood(tcp_sk(sk)))
__tcp_westwood_fast_bw(sk, skb); __tcp_westwood_fast_bw(sk, skb);
} }
static inline void tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb) static inline void tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb)
{ {
if (sysctl_tcp_westwood) if (tcp_is_westwood(tcp_sk(sk)))
__tcp_westwood_slow_bw(sk, skb); __tcp_westwood_slow_bw(sk, skb);
} }
...@@ -2052,14 +2054,14 @@ static inline __u32 __tcp_westwood_bw_rttmin(const struct tcp_opt *tp) ...@@ -2052,14 +2054,14 @@ static inline __u32 __tcp_westwood_bw_rttmin(const struct tcp_opt *tp)
static inline __u32 tcp_westwood_bw_rttmin(const struct tcp_opt *tp) static inline __u32 tcp_westwood_bw_rttmin(const struct tcp_opt *tp)
{ {
return sysctl_tcp_westwood ? __tcp_westwood_bw_rttmin(tp) : 0; return tcp_is_westwood(tp) ? __tcp_westwood_bw_rttmin(tp) : 0;
} }
static inline int tcp_westwood_ssthresh(struct tcp_opt *tp) static inline int tcp_westwood_ssthresh(struct tcp_opt *tp)
{ {
__u32 ssthresh = 0; __u32 ssthresh = 0;
if (sysctl_tcp_westwood) { if (tcp_is_westwood(tp)) {
ssthresh = __tcp_westwood_bw_rttmin(tp); ssthresh = __tcp_westwood_bw_rttmin(tp);
if (ssthresh) if (ssthresh)
tp->snd_ssthresh = ssthresh; tp->snd_ssthresh = ssthresh;
...@@ -2072,7 +2074,7 @@ static inline int tcp_westwood_cwnd(struct tcp_opt *tp) ...@@ -2072,7 +2074,7 @@ static inline int tcp_westwood_cwnd(struct tcp_opt *tp)
{ {
__u32 cwnd = 0; __u32 cwnd = 0;
if (sysctl_tcp_westwood) { if (tcp_is_westwood(tp)) {
cwnd = __tcp_westwood_bw_rttmin(tp); cwnd = __tcp_westwood_bw_rttmin(tp);
if (cwnd) if (cwnd)
tp->snd_cwnd = cwnd; tp->snd_cwnd = cwnd;
......
...@@ -1734,7 +1734,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, ...@@ -1734,7 +1734,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned char ncomm[sizeof(me->comm)]; unsigned char ncomm[sizeof(me->comm)];
ncomm[sizeof(me->comm)-1] = 0; ncomm[sizeof(me->comm)-1] = 0;
if (strncpy_from_user(ncomm, (char *)arg2, if (strncpy_from_user(ncomm, (char __user *)arg2,
sizeof(me->comm)-1) < 0) sizeof(me->comm)-1) < 0)
return -EFAULT; return -EFAULT;
set_task_comm(me, ncomm); set_task_comm(me, ncomm);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/jhash.h>
#include <net/route.h> /* for struct rtable and routing */ #include <net/route.h> /* for struct rtable and routing */
#include <net/icmp.h> /* icmp_send */ #include <net/icmp.h> /* icmp_send */
#include <asm/param.h> /* for HZ */ #include <asm/param.h> /* for HZ */
...@@ -123,64 +124,49 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) ...@@ -123,64 +124,49 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
spin_unlock_bh(&entry->neigh->dev->xmit_lock); spin_unlock_bh(&entry->neigh->dev->xmit_lock);
} }
/* The neighbour entry n->lock is held. */
static void idle_timer_check(unsigned long dummy) static int neigh_check_cb(struct neighbour *n)
{ {
int i; struct atmarp_entry *entry = NEIGH2ENTRY(n);
struct clip_vcc *cv;
/*DPRINTK("idle_timer_check\n");*/ for (cv = entry->vccs; cv; cv = cv->next) {
write_lock(&clip_tbl.lock); unsigned long exp = cv->last_use + cv->idle_timeout;
for (i = 0; i <= NEIGH_HASHMASK; i++) {
struct neighbour **np; if (cv->idle_timeout && time_after(jiffies, exp)) {
DPRINTK("releasing vcc %p->%p of entry %p\n",
for (np = &clip_tbl.hash_buckets[i]; *np;) { cv, cv->vcc, entry);
struct neighbour *n = *np; vcc_release_async(cv->vcc, -ETIMEDOUT);
struct atmarp_entry *entry = NEIGH2ENTRY(n);
struct clip_vcc *clip_vcc;
write_lock(&n->lock);
for (clip_vcc = entry->vccs; clip_vcc;
clip_vcc = clip_vcc->next)
if (clip_vcc->idle_timeout &&
time_after(jiffies, clip_vcc->last_use+
clip_vcc->idle_timeout)) {
DPRINTK("releasing vcc %p->%p of "
"entry %p\n",clip_vcc,clip_vcc->vcc,
entry);
vcc_release_async(clip_vcc->vcc,
-ETIMEDOUT);
}
if (entry->vccs ||
time_before(jiffies, entry->expires)) {
np = &n->next;
write_unlock(&n->lock);
continue;
}
if (atomic_read(&n->refcnt) > 1) {
struct sk_buff *skb;
DPRINTK("destruction postponed with ref %d\n",
atomic_read(&n->refcnt));
while ((skb = skb_dequeue(&n->arp_queue)) !=
NULL)
dev_kfree_skb(skb);
np = &n->next;
write_unlock(&n->lock);
continue;
}
*np = n->next;
DPRINTK("expired neigh %p\n",n);
n->dead = 1;
write_unlock(&n->lock);
neigh_release(n);
} }
} }
if (entry->vccs || time_before(jiffies, entry->expires))
return 0;
if (atomic_read(&n->refcnt) > 1) {
struct sk_buff *skb;
DPRINTK("destruction postponed with ref %d\n",
atomic_read(&n->refcnt));
while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
dev_kfree_skb(skb);
return 0;
}
DPRINTK("expired neigh %p\n",n);
return 1;
}
static void idle_timer_check(unsigned long dummy)
{
write_lock(&clip_tbl.lock);
__neigh_for_each_release(&clip_tbl, neigh_check_cb);
mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ); mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ);
write_unlock(&clip_tbl.lock); write_unlock(&clip_tbl.lock);
} }
static int clip_arp_rcv(struct sk_buff *skb) static int clip_arp_rcv(struct sk_buff *skb)
{ {
struct atm_vcc *vcc; struct atm_vcc *vcc;
...@@ -343,15 +329,7 @@ static int clip_constructor(struct neighbour *neigh) ...@@ -343,15 +329,7 @@ static int clip_constructor(struct neighbour *neigh)
static u32 clip_hash(const void *pkey, const struct net_device *dev) static u32 clip_hash(const void *pkey, const struct net_device *dev)
{ {
u32 hash_val; return jhash_2words(*(u32 *)pkey, dev->ifindex, clip_tbl.hash_rnd);
hash_val = *(u32*)pkey;
hash_val ^= (hash_val>>16);
hash_val ^= hash_val>>8;
hash_val ^= hash_val>>3;
hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
return hash_val;
} }
static struct neigh_table clip_tbl = { static struct neigh_table clip_tbl = {
...@@ -833,120 +811,126 @@ static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr) ...@@ -833,120 +811,126 @@ static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr)
} }
} }
/* This means the neighbour entry has no attached VCC objects. */
#define SEQ_NO_VCC_TOKEN ((void *) 2)
static void atmarp_info(struct seq_file *seq, struct net_device *dev, static void atmarp_info(struct seq_file *seq, struct net_device *dev,
struct atmarp_entry *entry, struct clip_vcc *clip_vcc) struct atmarp_entry *entry, struct clip_vcc *clip_vcc)
{ {
unsigned long exp;
char buf[17]; char buf[17];
int svc, off; int svc, llc, off;
svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
(clip_vcc->vcc->sk->sk_family == AF_ATMSVC));
llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
clip_vcc->encap);
svc = !clip_vcc || clip_vcc->vcc->sk->sk_family == AF_ATMSVC; if (clip_vcc == SEQ_NO_VCC_TOKEN)
seq_printf(seq, "%-6s%-4s%-4s%5ld ", dev->name, svc ? "SVC" : "PVC", exp = entry->neigh->used;
!clip_vcc || clip_vcc->encap ? "LLC" : "NULL", else
(jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/HZ); exp = clip_vcc->last_use;
off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d", NIPQUAD(entry->ip)); exp = (jiffies - exp) / HZ;
seq_printf(seq, "%-6s%-4s%-4s%5ld ",
dev->name,
svc ? "SVC" : "PVC",
llc ? "LLC" : "NULL",
exp);
off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d",
NIPQUAD(entry->ip));
while (off < 16) while (off < 16)
buf[off++] = ' '; buf[off++] = ' ';
buf[off] = '\0'; buf[off] = '\0';
seq_printf(seq, "%s", buf); seq_printf(seq, "%s", buf);
if (!clip_vcc) { if (clip_vcc == SEQ_NO_VCC_TOKEN) {
if (time_before(jiffies, entry->expires)) if (time_before(jiffies, entry->expires))
seq_printf(seq, "(resolving)\n"); seq_printf(seq, "(resolving)\n");
else else
seq_printf(seq, "(expired, ref %d)\n", seq_printf(seq, "(expired, ref %d)\n",
atomic_read(&entry->neigh->refcnt)); atomic_read(&entry->neigh->refcnt));
} else if (!svc) { } else if (!svc) {
seq_printf(seq, "%d.%d.%d\n", clip_vcc->vcc->dev->number, seq_printf(seq, "%d.%d.%d\n",
clip_vcc->vcc->vpi, clip_vcc->vcc->vci); clip_vcc->vcc->dev->number,
clip_vcc->vcc->vpi,
clip_vcc->vcc->vci);
} else { } else {
svc_addr(seq, &clip_vcc->vcc->remote); svc_addr(seq, &clip_vcc->vcc->remote);
seq_putc(seq, '\n'); seq_putc(seq, '\n');
} }
} }
struct arp_state { struct clip_seq_state {
int bucket; /* This member must be first. */
struct neighbour *n; struct neigh_seq_state ns;
/* Local to clip specific iteration. */
struct clip_vcc *vcc; struct clip_vcc *vcc;
}; };
static void *arp_vcc_walk(struct arp_state *state,
struct atmarp_entry *e, loff_t *l)
{
struct clip_vcc *vcc = state->vcc;
if (!vcc) static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e,
vcc = e->vccs; struct clip_vcc *curr)
if (vcc == (void *)1) {
vcc = e->vccs;
--*l;
}
for (; vcc; vcc = vcc->next) {
if (--*l < 0)
break;
}
state->vcc = vcc;
return (*l < 0) ? state : NULL;
}
static void *arp_get_idx(struct arp_state *state, loff_t l)
{ {
void *v = NULL; if (!curr) {
curr = e->vccs;
for (; state->bucket <= NEIGH_HASHMASK; state->bucket++) { if (!curr)
for (; state->n; state->n = state->n->next) { return SEQ_NO_VCC_TOKEN;
v = arp_vcc_walk(state, NEIGH2ENTRY(state->n), &l); return curr;
if (v)
goto done;
}
state->n = clip_tbl.hash_buckets[state->bucket + 1];
} }
done: if (curr == SEQ_NO_VCC_TOKEN)
return v; return NULL;
curr = curr->next;
return curr;
} }
static void *arp_seq_start(struct seq_file *seq, loff_t *pos) static void *clip_seq_vcc_walk(struct clip_seq_state *state,
struct atmarp_entry *e, loff_t *pos)
{ {
struct arp_state *state = seq->private; struct clip_vcc *vcc = state->vcc;
void *ret = (void *)1;
read_lock_bh(&clip_tbl.lock);
state->bucket = 0;
state->n = clip_tbl.hash_buckets[0];
state->vcc = (void *)1;
if (*pos)
ret = arp_get_idx(state, *pos);
return ret;
}
static void arp_seq_stop(struct seq_file *seq, void *v) vcc = clip_seq_next_vcc(e, vcc);
if (vcc && pos != NULL) {
while (*pos) {
vcc = clip_seq_next_vcc(e, vcc);
if (!vcc)
break;
--(*pos);
}
}
state->vcc = vcc;
return vcc;
}
static void *clip_seq_sub_iter(struct neigh_seq_state *_state,
struct neighbour *n, loff_t *pos)
{ {
struct arp_state *state = seq->private; struct clip_seq_state *state = (struct clip_seq_state *) _state;
if (state->bucket != -1) return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos);
read_unlock_bh(&clip_tbl.lock);
} }
static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *clip_seq_start(struct seq_file *seq, loff_t *pos)
{ {
struct arp_state *state = seq->private; return neigh_seq_start(seq, pos, &clip_tbl, NEIGH_SEQ_NEIGH_ONLY);
v = arp_get_idx(state, 1);
*pos += !!PTR_ERR(v);
return v;
} }
static int arp_seq_show(struct seq_file *seq, void *v) static int clip_seq_show(struct seq_file *seq, void *v)
{ {
static char atm_arp_banner[] = static char atm_arp_banner[] =
"IPitf TypeEncp Idle IP address ATM address\n"; "IPitf TypeEncp Idle IP address ATM address\n";
if (v == (void *)1) if (v == SEQ_START_TOKEN) {
seq_puts(seq, atm_arp_banner); seq_puts(seq, atm_arp_banner);
else { } else {
struct arp_state *state = seq->private; struct clip_seq_state *state = seq->private;
struct neighbour *n = state->n; struct neighbour *n = v;
struct clip_vcc *vcc = state->vcc; struct clip_vcc *vcc = state->vcc;
atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc); atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc);
...@@ -955,15 +939,15 @@ static int arp_seq_show(struct seq_file *seq, void *v) ...@@ -955,15 +939,15 @@ static int arp_seq_show(struct seq_file *seq, void *v)
} }
static struct seq_operations arp_seq_ops = { static struct seq_operations arp_seq_ops = {
.start = arp_seq_start, .start = clip_seq_start,
.next = arp_seq_next, .next = neigh_seq_next,
.stop = arp_seq_stop, .stop = neigh_seq_stop,
.show = arp_seq_show, .show = clip_seq_show,
}; };
static int arp_seq_open(struct inode *inode, struct file *file) static int arp_seq_open(struct inode *inode, struct file *file)
{ {
struct arp_state *state; struct clip_seq_state *state;
struct seq_file *seq; struct seq_file *seq;
int rc = -EAGAIN; int rc = -EAGAIN;
...@@ -972,6 +956,8 @@ static int arp_seq_open(struct inode *inode, struct file *file) ...@@ -972,6 +956,8 @@ static int arp_seq_open(struct inode *inode, struct file *file)
rc = -ENOMEM; rc = -ENOMEM;
goto out_kfree; goto out_kfree;
} }
memset(state, 0, sizeof(*state));
state->ns.neigh_sub_iter = clip_seq_sub_iter;
rc = seq_open(file, &arp_seq_ops); rc = seq_open(file, &arp_seq_ops);
if (rc) if (rc)
...@@ -987,16 +973,11 @@ static int arp_seq_open(struct inode *inode, struct file *file) ...@@ -987,16 +973,11 @@ static int arp_seq_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
static int arp_seq_release(struct inode *inode, struct file *file)
{
return seq_release_private(inode, file);
}
static struct file_operations arp_seq_fops = { static struct file_operations arp_seq_fops = {
.open = arp_seq_open, .open = arp_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = arp_seq_release, .release = seq_release_private,
.owner = THIS_MODULE .owner = THIS_MODULE
}; };
#endif #endif
......
This diff is collapsed.
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/jhash.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <net/neighbour.h> #include <net/neighbour.h>
#include <net/dst.h> #include <net/dst.h>
...@@ -122,13 +123,7 @@ struct neigh_table dn_neigh_table = { ...@@ -122,13 +123,7 @@ struct neigh_table dn_neigh_table = {
static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev) static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev)
{ {
u32 hash_val; return jhash_2words(*(dn_address *)pkey, 0, dn_neigh_table.hash_rnd);
hash_val = *(dn_address *)pkey;
hash_val ^= (hash_val >> 10);
hash_val ^= (hash_val >> 3);
return hash_val & NEIGH_HASHMASK;
} }
static int dn_neigh_construct(struct neighbour *neigh) static int dn_neigh_construct(struct neighbour *neigh)
...@@ -359,27 +354,6 @@ static int dn_phase3_output(struct sk_buff *skb) ...@@ -359,27 +354,6 @@ static int dn_phase3_output(struct sk_buff *skb)
* basically does a neigh_lookup(), but without comparing the device * basically does a neigh_lookup(), but without comparing the device
* field. This is required for the On-Ethernet cache * field. This is required for the On-Ethernet cache
*/ */
struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr)
{
struct neighbour *neigh;
u32 hash_val;
hash_val = tbl->hash(ptr, NULL);
read_lock_bh(&tbl->lock);
for(neigh = tbl->hash_buckets[hash_val]; neigh != NULL; neigh = neigh->next) {
if (memcmp(neigh->primary_key, ptr, tbl->key_len) == 0) {
atomic_inc(&neigh->refcnt);
read_unlock_bh(&tbl->lock);
return neigh;
}
}
read_unlock_bh(&tbl->lock);
return NULL;
}
/* /*
* Any traffic on a pointopoint link causes the timer to be reset * Any traffic on a pointopoint link causes the timer to be reset
* for the entry in the neighbour table. * for the entry in the neighbour table.
...@@ -514,141 +488,66 @@ static char *dn_find_slot(char *base, int max, int priority) ...@@ -514,141 +488,66 @@ static char *dn_find_slot(char *base, int max, int priority)
return (*min < priority) ? (min - 6) : NULL; return (*min < priority) ? (min - 6) : NULL;
} }
int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) struct elist_cb_state {
{ struct net_device *dev;
int t = 0; unsigned char *ptr;
int i; unsigned char *rs;
struct neighbour *neigh; int t, n;
struct dn_neigh *dn;
struct neigh_table *tbl = &dn_neigh_table;
unsigned char *rs = ptr;
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
read_lock_bh(&tbl->lock);
for(i = 0; i < NEIGH_HASHMASK; i++) {
for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = neigh->next) {
if (neigh->dev != dev)
continue;
dn = (struct dn_neigh *)neigh;
if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
continue;
if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
continue;
if (t == n)
rs = dn_find_slot(ptr, n, dn->priority);
else
t++;
if (rs == NULL)
continue;
dn_dn2eth(rs, dn->addr);
rs += 6;
*rs = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
*rs |= dn->priority;
rs++;
}
}
read_unlock_bh(&tbl->lock);
return t;
}
#ifdef CONFIG_PROC_FS
struct dn_neigh_iter_state {
int bucket;
}; };
static struct neighbour *neigh_get_first(struct seq_file *seq) static void neigh_elist_cb(struct neighbour *neigh, void *_info)
{
struct dn_neigh_iter_state *state = seq->private;
struct neighbour *n = NULL;
for(state->bucket = 0;
state->bucket <= NEIGH_HASHMASK;
++state->bucket) {
n = dn_neigh_table.hash_buckets[state->bucket];
if (n)
break;
}
return n;
}
static struct neighbour *neigh_get_next(struct seq_file *seq,
struct neighbour *n)
{ {
struct dn_neigh_iter_state *state = seq->private; struct elist_cb_state *s = _info;
struct dn_dev *dn_db;
n = n->next; struct dn_neigh *dn;
try_again:
if (n)
goto out;
if (++state->bucket > NEIGH_HASHMASK)
goto out;
n = dn_neigh_table.hash_buckets[state->bucket];
goto try_again;
out:
return n;
}
static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) if (neigh->dev != s->dev)
{ return;
struct neighbour *n = neigh_get_first(seq);
if (n) dn = (struct dn_neigh *) neigh;
while(*pos && (n = neigh_get_next(seq, n))) if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
--*pos; return;
return *pos ? NULL : n;
}
static void *dn_neigh_get_idx(struct seq_file *seq, loff_t pos) dn_db = (struct dn_dev *) s->dev->dn_ptr;
{ if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
void *rc; return;
read_lock_bh(&dn_neigh_table.lock);
rc = neigh_get_idx(seq, &pos);
if (!rc) {
read_unlock_bh(&dn_neigh_table.lock);
}
return rc;
}
static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos) if (s->t == s->n)
{ s->rs = dn_find_slot(s->ptr, s->n, dn->priority);
return *pos ? dn_neigh_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; else
s->t++;
if (s->rs == NULL)
return;
dn_dn2eth(s->rs, dn->addr);
s->rs += 6;
*(s->rs) = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
*(s->rs) |= dn->priority;
s->rs++;
} }
static void *dn_neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos) int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
{ {
void *rc; struct elist_cb_state state;
state.dev = dev;
state.t = 0;
state.n = n;
state.ptr = ptr;
state.rs = ptr;
if (v == SEQ_START_TOKEN) { neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state);
rc = dn_neigh_get_idx(seq, 0);
goto out;
}
rc = neigh_get_next(seq, v); return state.t;
if (rc)
goto out;
read_unlock_bh(&dn_neigh_table.lock);
out:
++*pos;
return rc;
} }
static void dn_neigh_seq_stop(struct seq_file *seq, void *v)
{ #ifdef CONFIG_PROC_FS
if (v && v != SEQ_START_TOKEN)
read_unlock_bh(&dn_neigh_table.lock);
}
static inline void dn_neigh_format_entry(struct seq_file *seq, static inline void dn_neigh_format_entry(struct seq_file *seq,
struct neighbour *n) struct neighbour *n)
{ {
struct dn_neigh *dn = (struct dn_neigh *)n; struct dn_neigh *dn = (struct dn_neigh *) n;
char buf[DN_ASCBUF_LEN]; char buf[DN_ASCBUF_LEN];
read_lock(&n->lock); read_lock(&n->lock);
...@@ -675,10 +574,16 @@ static int dn_neigh_seq_show(struct seq_file *seq, void *v) ...@@ -675,10 +574,16 @@ static int dn_neigh_seq_show(struct seq_file *seq, void *v)
return 0; return 0;
} }
static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
{
return neigh_seq_start(seq, pos, &dn_neigh_table,
NEIGH_SEQ_NEIGH_ONLY);
}
static struct seq_operations dn_neigh_seq_ops = { static struct seq_operations dn_neigh_seq_ops = {
.start = dn_neigh_seq_start, .start = dn_neigh_seq_start,
.next = dn_neigh_seq_next, .next = neigh_seq_next,
.stop = dn_neigh_seq_stop, .stop = neigh_seq_stop,
.show = dn_neigh_seq_show, .show = dn_neigh_seq_show,
}; };
...@@ -686,11 +591,12 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file) ...@@ -686,11 +591,12 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file)
{ {
struct seq_file *seq; struct seq_file *seq;
int rc = -ENOMEM; int rc = -ENOMEM;
struct dn_neigh_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s) if (!s)
goto out; goto out;
memset(s, 0, sizeof(*s));
rc = seq_open(file, &dn_neigh_seq_ops); rc = seq_open(file, &dn_neigh_seq_ops);
if (rc) if (rc)
goto out_kfree; goto out_kfree;
......
...@@ -996,7 +996,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old ...@@ -996,7 +996,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
* here * here
*/ */
if (!try_hard) { if (!try_hard) {
neigh = dn_neigh_lookup(&dn_neigh_table, &fl.fld_dst); neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst);
if (neigh) { if (neigh) {
if ((oldflp->oif && if ((oldflp->oif &&
(neigh->dev->ifindex != oldflp->oif)) || (neigh->dev->ifindex != oldflp->oif)) ||
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
* arp_xmit so intermediate drivers like * arp_xmit so intermediate drivers like
* bonding can change the skb before * bonding can change the skb before
* sending (e.g. insert 8021q tag). * sending (e.g. insert 8021q tag).
* Harald Welte : convert to make use of jenkins hash
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -97,6 +98,7 @@ ...@@ -97,6 +98,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/jhash.h>
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
#include <linux/sysctl.h> #include <linux/sysctl.h>
#endif #endif
...@@ -223,15 +225,7 @@ int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) ...@@ -223,15 +225,7 @@ int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir)
static u32 arp_hash(const void *pkey, const struct net_device *dev) static u32 arp_hash(const void *pkey, const struct net_device *dev)
{ {
u32 hash_val; return jhash_2words(*(u32 *)pkey, dev->ifindex, arp_tbl.hash_rnd);
hash_val = *(u32*)pkey;
hash_val ^= (hash_val>>16);
hash_val ^= hash_val>>8;
hash_val ^= hash_val>>3;
hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
return hash_val;
} }
static int arp_constructor(struct neighbour *neigh) static int arp_constructor(struct neighbour *neigh)
...@@ -1269,162 +1263,10 @@ static char *ax2asc2(ax25_address *a, char *buf) ...@@ -1269,162 +1263,10 @@ static char *ax2asc2(ax25_address *a, char *buf)
} }
#endif /* CONFIG_AX25 */ #endif /* CONFIG_AX25 */
struct arp_iter_state {
int is_pneigh, bucket;
};
static struct neighbour *neigh_get_first(struct seq_file *seq)
{
struct arp_iter_state* state = seq->private;
struct neighbour *n = NULL;
state->is_pneigh = 0;
for (state->bucket = 0;
state->bucket <= NEIGH_HASHMASK;
++state->bucket) {
n = arp_tbl.hash_buckets[state->bucket];
while (n && !(n->nud_state & ~NUD_NOARP))
n = n->next;
if (n)
break;
}
return n;
}
static struct neighbour *neigh_get_next(struct seq_file *seq,
struct neighbour *n)
{
struct arp_iter_state* state = seq->private;
do {
n = n->next;
/* Don't confuse "arp -a" w/ magic entries */
try_again:
;
} while (n && !(n->nud_state & ~NUD_NOARP));
if (n)
goto out;
if (++state->bucket > NEIGH_HASHMASK)
goto out;
n = arp_tbl.hash_buckets[state->bucket];
goto try_again;
out:
return n;
}
static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
{
struct neighbour *n = neigh_get_first(seq);
if (n)
while (*pos && (n = neigh_get_next(seq, n)))
--*pos;
return *pos ? NULL : n;
}
static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
{
struct arp_iter_state* state = seq->private;
struct pneigh_entry *pn;
state->is_pneigh = 1;
for (state->bucket = 0;
state->bucket <= PNEIGH_HASHMASK;
++state->bucket) {
pn = arp_tbl.phash_buckets[state->bucket];
if (pn)
break;
}
return pn;
}
static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
struct pneigh_entry *pn)
{
struct arp_iter_state* state = seq->private;
pn = pn->next;
while (!pn) {
if (++state->bucket > PNEIGH_HASHMASK)
break;
pn = arp_tbl.phash_buckets[state->bucket];
}
return pn;
}
static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t pos)
{
struct pneigh_entry *pn = pneigh_get_first(seq);
if (pn)
while (pos && (pn = pneigh_get_next(seq, pn)))
--pos;
return pos ? NULL : pn;
}
static void *arp_get_idx(struct seq_file *seq, loff_t pos)
{
void *rc;
read_lock_bh(&arp_tbl.lock);
rc = neigh_get_idx(seq, &pos);
if (!rc) {
read_unlock_bh(&arp_tbl.lock);
rc = pneigh_get_idx(seq, pos);
}
return rc;
}
static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
{
struct arp_iter_state* state = seq->private;
state->is_pneigh = 0;
state->bucket = 0;
return *pos ? arp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
}
static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
void *rc;
struct arp_iter_state* state;
if (v == SEQ_START_TOKEN) {
rc = arp_get_idx(seq, 0);
goto out;
}
state = seq->private;
if (!state->is_pneigh) {
rc = neigh_get_next(seq, v);
if (rc)
goto out;
read_unlock_bh(&arp_tbl.lock);
rc = pneigh_get_first(seq);
} else
rc = pneigh_get_next(seq, v);
out:
++*pos;
return rc;
}
static void arp_seq_stop(struct seq_file *seq, void *v)
{
struct arp_iter_state* state = seq->private;
if (!state->is_pneigh && v != SEQ_START_TOKEN)
read_unlock_bh(&arp_tbl.lock);
}
#define HBUFFERLEN 30 #define HBUFFERLEN 30
static __inline__ void arp_format_neigh_entry(struct seq_file *seq, static void arp_format_neigh_entry(struct seq_file *seq,
struct neighbour *n) struct neighbour *n)
{ {
char hbuffer[HBUFFERLEN]; char hbuffer[HBUFFERLEN];
const char hexbuf[] = "0123456789ABCDEF"; const char hexbuf[] = "0123456789ABCDEF";
...@@ -1455,8 +1297,8 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq, ...@@ -1455,8 +1297,8 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq,
read_unlock(&n->lock); read_unlock(&n->lock);
} }
static __inline__ void arp_format_pneigh_entry(struct seq_file *seq, static void arp_format_pneigh_entry(struct seq_file *seq,
struct pneigh_entry *n) struct pneigh_entry *n)
{ {
struct net_device *dev = n->dev; struct net_device *dev = n->dev;
int hatype = dev ? dev->type : 0; int hatype = dev ? dev->type : 0;
...@@ -1470,13 +1312,13 @@ static __inline__ void arp_format_pneigh_entry(struct seq_file *seq, ...@@ -1470,13 +1312,13 @@ static __inline__ void arp_format_pneigh_entry(struct seq_file *seq,
static int arp_seq_show(struct seq_file *seq, void *v) static int arp_seq_show(struct seq_file *seq, void *v)
{ {
if (v == SEQ_START_TOKEN) if (v == SEQ_START_TOKEN) {
seq_puts(seq, "IP address HW type Flags " seq_puts(seq, "IP address HW type Flags "
"HW address Mask Device\n"); "HW address Mask Device\n");
else { } else {
struct arp_iter_state* state = seq->private; struct neigh_seq_state *state = seq->private;
if (state->is_pneigh) if (state->flags & NEIGH_SEQ_IS_PNEIGH)
arp_format_pneigh_entry(seq, v); arp_format_pneigh_entry(seq, v);
else else
arp_format_neigh_entry(seq, v); arp_format_neigh_entry(seq, v);
...@@ -1485,12 +1327,20 @@ static int arp_seq_show(struct seq_file *seq, void *v) ...@@ -1485,12 +1327,20 @@ static int arp_seq_show(struct seq_file *seq, void *v)
return 0; return 0;
} }
static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
{
/* Don't want to confuse "arp -a" w/ magic entries,
* so we tell the generic iterator to skip NUD_NOARP.
*/
return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP);
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static struct seq_operations arp_seq_ops = { static struct seq_operations arp_seq_ops = {
.start = arp_seq_start, .start = arp_seq_start,
.next = arp_seq_next, .next = neigh_seq_next,
.stop = arp_seq_stop, .stop = neigh_seq_stop,
.show = arp_seq_show, .show = arp_seq_show,
}; };
...@@ -1498,11 +1348,12 @@ static int arp_seq_open(struct inode *inode, struct file *file) ...@@ -1498,11 +1348,12 @@ static int arp_seq_open(struct inode *inode, struct file *file)
{ {
struct seq_file *seq; struct seq_file *seq;
int rc = -ENOMEM; int rc = -ENOMEM;
struct arp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s) if (!s)
goto out; goto out;
memset(s, 0, sizeof(*s));
rc = seq_open(file, &arp_seq_ops); rc = seq_open(file, &arp_seq_ops);
if (rc) if (rc)
goto out_kfree; goto out_kfree;
......
...@@ -438,17 +438,15 @@ static struct fib_alias *fib_find_alias(struct fib_node *fn, u8 tos, u32 prio) ...@@ -438,17 +438,15 @@ static struct fib_alias *fib_find_alias(struct fib_node *fn, u8 tos, u32 prio)
{ {
if (fn) { if (fn) {
struct list_head *head = &fn->fn_alias; struct list_head *head = &fn->fn_alias;
struct fib_alias *fa, *prev_fa; struct fib_alias *fa;
prev_fa = NULL;
list_for_each_entry(fa, head, fa_list) { list_for_each_entry(fa, head, fa_list) {
if (fa->fa_tos != tos) if (fa->fa_tos > tos)
continue; continue;
prev_fa = fa; if (fa->fa_info->fib_priority >= prio ||
if (prio <= fa->fa_info->fib_priority) fa->fa_tos < tos)
break; return fa;
} }
return prev_fa;
} }
return NULL; return NULL;
} }
...@@ -505,7 +503,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, ...@@ -505,7 +503,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
* and we need to allocate a new one of those as well. * and we need to allocate a new one of those as well.
*/ */
if (fa && if (fa && fa->fa_tos == tos &&
fa->fa_info->fib_priority == fi->fib_priority) { fa->fa_info->fib_priority == fi->fib_priority) {
struct fib_alias *fa_orig; struct fib_alias *fa_orig;
...@@ -537,7 +535,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, ...@@ -537,7 +535,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
* information. * information.
*/ */
fa_orig = fa; fa_orig = fa;
list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) { fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
if (fa->fa_tos != tos) if (fa->fa_tos != tos)
break; break;
if (fa->fa_info->fib_priority != fi->fib_priority) if (fa->fa_info->fib_priority != fi->fib_priority)
...@@ -585,7 +584,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, ...@@ -585,7 +584,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
write_lock_bh(&fib_hash_lock); write_lock_bh(&fib_hash_lock);
if (new_f) if (new_f)
fib_insert_node(fz, new_f); fib_insert_node(fz, new_f);
list_add(&new_fa->fa_list, list_add_tail(&new_fa->fa_list,
(fa ? &fa->fa_list : &f->fn_alias)); (fa ? &fa->fa_list : &f->fn_alias));
write_unlock_bh(&fib_hash_lock); write_unlock_bh(&fib_hash_lock);
...@@ -611,7 +610,6 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, ...@@ -611,7 +610,6 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
struct fn_hash *table = (struct fn_hash*)tb->tb_data; struct fn_hash *table = (struct fn_hash*)tb->tb_data;
struct fib_node *f; struct fib_node *f;
struct fib_alias *fa, *fa_to_delete; struct fib_alias *fa, *fa_to_delete;
struct list_head *fa_head;
int z = r->rtm_dst_len; int z = r->rtm_dst_len;
struct fn_zone *fz; struct fn_zone *fz;
u32 key; u32 key;
...@@ -637,8 +635,8 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, ...@@ -637,8 +635,8 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
return -ESRCH; return -ESRCH;
fa_to_delete = NULL; fa_to_delete = NULL;
fa_head = fa->fa_list.prev; fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
list_for_each_entry(fa, fa_head, fa_list) { list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
struct fib_info *fi = fa->fa_info; struct fib_info *fi = fa->fa_info;
if (fa->fa_tos != tos) if (fa->fa_tos != tos)
......
...@@ -139,7 +139,7 @@ icmp_error_message(struct sk_buff *skb, ...@@ -139,7 +139,7 @@ icmp_error_message(struct sk_buff *skb,
struct { struct {
struct icmphdr icmp; struct icmphdr icmp;
struct iphdr ip; struct iphdr ip;
} inside; } _in, *inside;
struct ip_conntrack_protocol *innerproto; struct ip_conntrack_protocol *innerproto;
struct ip_conntrack_tuple_hash *h; struct ip_conntrack_tuple_hash *h;
int dataoff; int dataoff;
...@@ -147,21 +147,22 @@ icmp_error_message(struct sk_buff *skb, ...@@ -147,21 +147,22 @@ icmp_error_message(struct sk_buff *skb,
IP_NF_ASSERT(skb->nfct == NULL); IP_NF_ASSERT(skb->nfct == NULL);
/* Not enough header? */ /* Not enough header? */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0) inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
if (inside == NULL)
return NF_ACCEPT; return NF_ACCEPT;
/* Ignore ICMP's containing fragments (shouldn't happen) */ /* Ignore ICMP's containing fragments (shouldn't happen) */
if (inside.ip.frag_off & htons(IP_OFFSET)) { if (inside->ip.frag_off & htons(IP_OFFSET)) {
DEBUGP("icmp_error_track: fragment of proto %u\n", DEBUGP("icmp_error_track: fragment of proto %u\n",
inside.ip.protocol); inside->ip.protocol);
return NF_ACCEPT; return NF_ACCEPT;
} }
innerproto = ip_ct_find_proto(inside.ip.protocol); innerproto = ip_ct_find_proto(inside->ip.protocol);
dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4; dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp) + inside->ip.ihl*4;
/* Are they talking about one of our connections? */ /* Are they talking about one of our connections? */
if (!ip_ct_get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) { if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) {
DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol); DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol);
return NF_ACCEPT; return NF_ACCEPT;
} }
...@@ -205,10 +206,11 @@ static int ...@@ -205,10 +206,11 @@ static int
icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
unsigned int hooknum) unsigned int hooknum)
{ {
struct icmphdr icmph; struct icmphdr _ih, *icmph;
/* Not enough header? */ /* Not enough header? */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &icmph, sizeof(icmph))!=0) { icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
if (icmph == NULL) {
if (LOG_INVALID(IPPROTO_ICMP)) if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, nf_log_packet(PF_INET, 0, skb, NULL, NULL,
"ip_ct_icmp: short packet "); "ip_ct_icmp: short packet ");
...@@ -245,7 +247,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, ...@@ -245,7 +247,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
* RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently
* discarded. * discarded.
*/ */
if (icmph.type > NR_ICMP_TYPES) { if (icmph->type > NR_ICMP_TYPES) {
if (LOG_INVALID(IPPROTO_ICMP)) if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, nf_log_packet(PF_INET, 0, skb, NULL, NULL,
"ip_ct_icmp: invalid ICMP type "); "ip_ct_icmp: invalid ICMP type ");
...@@ -253,11 +255,11 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, ...@@ -253,11 +255,11 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
} }
/* Need to track icmp error message? */ /* Need to track icmp error message? */
if (icmph.type != ICMP_DEST_UNREACH if (icmph->type != ICMP_DEST_UNREACH
&& icmph.type != ICMP_SOURCE_QUENCH && icmph->type != ICMP_SOURCE_QUENCH
&& icmph.type != ICMP_TIME_EXCEEDED && icmph->type != ICMP_TIME_EXCEEDED
&& icmph.type != ICMP_PARAMETERPROB && icmph->type != ICMP_PARAMETERPROB
&& icmph.type != ICMP_REDIRECT) && icmph->type != ICMP_REDIRECT)
return NF_ACCEPT; return NF_ACCEPT;
return icmp_error_message(skb, ctinfo, hooknum); return icmp_error_message(skb, ctinfo, hooknum);
......
...@@ -152,18 +152,18 @@ static int sctp_pkt_to_tuple(const struct sk_buff *skb, ...@@ -152,18 +152,18 @@ static int sctp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
struct ip_conntrack_tuple *tuple) struct ip_conntrack_tuple *tuple)
{ {
sctp_sctphdr_t hdr; sctp_sctphdr_t _hdr, *hp;
DEBUGP(__FUNCTION__); DEBUGP(__FUNCTION__);
DEBUGP("\n"); DEBUGP("\n");
/* Actually only need first 8 bytes. */ /* Actually only need first 8 bytes. */
if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0) hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
if (hp == NULL)
return 0; return 0;
tuple->src.u.sctp.port = hdr.source; tuple->src.u.sctp.port = hp->source;
tuple->dst.u.sctp.port = hdr.dest; tuple->dst.u.sctp.port = hp->dest;
return 1; return 1;
} }
...@@ -206,10 +206,11 @@ static int sctp_print_conntrack(struct seq_file *s, ...@@ -206,10 +206,11 @@ static int sctp_print_conntrack(struct seq_file *s,
return seq_printf(s, "%s ", sctp_conntrack_names[state]); return seq_printf(s, "%s ", sctp_conntrack_names[state]);
} }
#define for_each_sctp_chunk(skb, sch, offset, count) \ #define for_each_sctp_chunk(skb, sch, _sch, offset, count) \
for (offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t), count = 0; \ for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0; \
offset < skb->len && !skb_copy_bits(skb, offset, &sch, sizeof(sch)); \ offset < skb->len && \
offset += (htons(sch.length) + 3) & ~3, count++) (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \
offset += (htons(sch->length) + 3) & ~3, count++)
/* Some validity checks to make sure the chunks are fine */ /* Some validity checks to make sure the chunks are fine */
static int do_basic_checks(struct ip_conntrack *conntrack, static int do_basic_checks(struct ip_conntrack *conntrack,
...@@ -217,7 +218,7 @@ static int do_basic_checks(struct ip_conntrack *conntrack, ...@@ -217,7 +218,7 @@ static int do_basic_checks(struct ip_conntrack *conntrack,
char *map) char *map)
{ {
u_int32_t offset, count; u_int32_t offset, count;
sctp_chunkhdr_t sch; sctp_chunkhdr_t _sch, *sch;
int flag; int flag;
DEBUGP(__FUNCTION__); DEBUGP(__FUNCTION__);
...@@ -225,19 +226,19 @@ static int do_basic_checks(struct ip_conntrack *conntrack, ...@@ -225,19 +226,19 @@ static int do_basic_checks(struct ip_conntrack *conntrack,
flag = 0; flag = 0;
for_each_sctp_chunk (skb, sch, offset, count) { for_each_sctp_chunk (skb, sch, _sch, offset, count) {
DEBUGP("Chunk Num: %d Type: %d\n", count, sch.type); DEBUGP("Chunk Num: %d Type: %d\n", count, sch->type);
if (sch.type == SCTP_CID_INIT if (sch->type == SCTP_CID_INIT
|| sch.type == SCTP_CID_INIT_ACK || sch->type == SCTP_CID_INIT_ACK
|| sch.type == SCTP_CID_SHUTDOWN_COMPLETE) { || sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
flag = 1; flag = 1;
} }
/* Cookie Ack/Echo chunks not the first OR /* Cookie Ack/Echo chunks not the first OR
Init / Init Ack / Shutdown compl chunks not the only chunks */ Init / Init Ack / Shutdown compl chunks not the only chunks */
if ((sch.type == SCTP_CID_COOKIE_ACK if ((sch->type == SCTP_CID_COOKIE_ACK
|| sch.type == SCTP_CID_COOKIE_ECHO || sch->type == SCTP_CID_COOKIE_ECHO
|| flag) || flag)
&& count !=0 ) { && count !=0 ) {
DEBUGP("Basic checks failed\n"); DEBUGP("Basic checks failed\n");
...@@ -245,7 +246,7 @@ static int do_basic_checks(struct ip_conntrack *conntrack, ...@@ -245,7 +246,7 @@ static int do_basic_checks(struct ip_conntrack *conntrack,
} }
if (map) { if (map) {
set_bit (sch.type, (void *)map); set_bit(sch->type, (void *)map);
} }
} }
...@@ -313,15 +314,17 @@ static int sctp_packet(struct ip_conntrack *conntrack, ...@@ -313,15 +314,17 @@ static int sctp_packet(struct ip_conntrack *conntrack,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo)
{ {
enum sctp_conntrack newconntrack, oldsctpstate; enum sctp_conntrack newconntrack, oldsctpstate;
sctp_sctphdr_t sctph; struct iphdr *iph = skb->nh.iph;
sctp_chunkhdr_t sch; sctp_sctphdr_t _sctph, *sh;
sctp_chunkhdr_t _sch, *sch;
u_int32_t offset, count; u_int32_t offset, count;
char map[256 / sizeof (char)] = {0}; char map[256 / sizeof (char)] = {0};
DEBUGP(__FUNCTION__); DEBUGP(__FUNCTION__);
DEBUGP("\n"); DEBUGP("\n");
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &sctph, sizeof(sctph)) != 0) sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
if (sh == NULL)
return -1; return -1;
if (do_basic_checks(conntrack, skb, map) != 0) if (do_basic_checks(conntrack, skb, map) != 0)
...@@ -333,71 +336,72 @@ static int sctp_packet(struct ip_conntrack *conntrack, ...@@ -333,71 +336,72 @@ static int sctp_packet(struct ip_conntrack *conntrack,
&& !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map) && !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map)
&& !test_bit(SCTP_CID_ABORT, (void *)map) && !test_bit(SCTP_CID_ABORT, (void *)map)
&& !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map) && !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
&& (sctph.vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { && (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
DEBUGP("Verification tag check failed\n"); DEBUGP("Verification tag check failed\n");
return -1; return -1;
} }
oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX; oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
for_each_sctp_chunk (skb, sch, offset, count) { for_each_sctp_chunk (skb, sch, _sch, offset, count) {
WRITE_LOCK(&sctp_lock); WRITE_LOCK(&sctp_lock);
/* Special cases of Verification tag check (Sec 8.5.1) */ /* Special cases of Verification tag check (Sec 8.5.1) */
if (sch.type == SCTP_CID_INIT) { if (sch->type == SCTP_CID_INIT) {
/* Sec 8.5.1 (A) */ /* Sec 8.5.1 (A) */
if (sctph.vtag != 0) { if (sh->vtag != 0) {
WRITE_UNLOCK(&sctp_lock); WRITE_UNLOCK(&sctp_lock);
return -1; return -1;
} }
} else if (sch.type == SCTP_CID_ABORT) { } else if (sch->type == SCTP_CID_ABORT) {
/* Sec 8.5.1 (B) */ /* Sec 8.5.1 (B) */
if (!(sctph.vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
&& !(sctph.vtag == conntrack->proto.sctp.vtag && !(sh->vtag == conntrack->proto.sctp.vtag
[1 - CTINFO2DIR(ctinfo)])) { [1 - CTINFO2DIR(ctinfo)])) {
WRITE_UNLOCK(&sctp_lock); WRITE_UNLOCK(&sctp_lock);
return -1; return -1;
} }
} else if (sch.type == SCTP_CID_SHUTDOWN_COMPLETE) { } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
/* Sec 8.5.1 (C) */ /* Sec 8.5.1 (C) */
if (!(sctph.vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
&& !(sctph.vtag == conntrack->proto.sctp.vtag && !(sh->vtag == conntrack->proto.sctp.vtag
[1 - CTINFO2DIR(ctinfo)] [1 - CTINFO2DIR(ctinfo)]
&& (sch.flags & 1))) { && (sch->flags & 1))) {
WRITE_UNLOCK(&sctp_lock); WRITE_UNLOCK(&sctp_lock);
return -1; return -1;
} }
} else if (sch.type == SCTP_CID_COOKIE_ECHO) { } else if (sch->type == SCTP_CID_COOKIE_ECHO) {
/* Sec 8.5.1 (D) */ /* Sec 8.5.1 (D) */
if (!(sctph.vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
WRITE_UNLOCK(&sctp_lock); WRITE_UNLOCK(&sctp_lock);
return -1; return -1;
} }
} }
oldsctpstate = conntrack->proto.sctp.state; oldsctpstate = conntrack->proto.sctp.state;
newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch.type); newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type);
/* Invalid */ /* Invalid */
if (newconntrack == SCTP_CONNTRACK_MAX) { if (newconntrack == SCTP_CONNTRACK_MAX) {
DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n", DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
CTINFO2DIR(ctinfo), sch.type, oldsctpstate); CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
WRITE_UNLOCK(&sctp_lock); WRITE_UNLOCK(&sctp_lock);
return -1; return -1;
} }
/* If it is an INIT or an INIT ACK note down the vtag */ /* If it is an INIT or an INIT ACK note down the vtag */
if (sch.type == SCTP_CID_INIT if (sch->type == SCTP_CID_INIT
|| sch.type == SCTP_CID_INIT_ACK) { || sch->type == SCTP_CID_INIT_ACK) {
sctp_inithdr_t inithdr; sctp_inithdr_t _inithdr, *ih;
if (skb_copy_bits(skb, offset + sizeof (sctp_chunkhdr_t), ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
&inithdr, sizeof(inithdr)) != 0) { sizeof(_inithdr), &_inithdr);
if (ih == NULL) {
WRITE_UNLOCK(&sctp_lock); WRITE_UNLOCK(&sctp_lock);
return -1; return -1;
} }
DEBUGP("Setting vtag %x for dir %d\n", DEBUGP("Setting vtag %x for dir %d\n",
inithdr.init_tag, CTINFO2DIR(ctinfo)); ih->init_tag, CTINFO2DIR(ctinfo));
conntrack->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = inithdr.init_tag; conntrack->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = ih->init_tag;
} }
conntrack->proto.sctp.state = newconntrack; conntrack->proto.sctp.state = newconntrack;
...@@ -421,15 +425,17 @@ static int sctp_new(struct ip_conntrack *conntrack, ...@@ -421,15 +425,17 @@ static int sctp_new(struct ip_conntrack *conntrack,
const struct sk_buff *skb) const struct sk_buff *skb)
{ {
enum sctp_conntrack newconntrack; enum sctp_conntrack newconntrack;
sctp_sctphdr_t sctph; struct iphdr *iph = skb->nh.iph;
sctp_chunkhdr_t sch; sctp_sctphdr_t _sctph, *sh;
sctp_chunkhdr_t _sch, *sch;
u_int32_t offset, count; u_int32_t offset, count;
char map[256 / sizeof (char)] = {0}; char map[256 / sizeof (char)] = {0};
DEBUGP(__FUNCTION__); DEBUGP(__FUNCTION__);
DEBUGP("\n"); DEBUGP("\n");
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &sctph, sizeof(sctph)) != 0) sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
if (sh == NULL)
return 0; return 0;
if (do_basic_checks(conntrack, skb, map) != 0) if (do_basic_checks(conntrack, skb, map) != 0)
...@@ -443,10 +449,10 @@ static int sctp_new(struct ip_conntrack *conntrack, ...@@ -443,10 +449,10 @@ static int sctp_new(struct ip_conntrack *conntrack,
} }
newconntrack = SCTP_CONNTRACK_MAX; newconntrack = SCTP_CONNTRACK_MAX;
for_each_sctp_chunk (skb, sch, offset, count) { for_each_sctp_chunk (skb, sch, _sch, offset, count) {
/* Don't need lock here: this conntrack not in circulation yet */ /* Don't need lock here: this conntrack not in circulation yet */
newconntrack = new_state (IP_CT_DIR_ORIGINAL, newconntrack = new_state (IP_CT_DIR_ORIGINAL,
SCTP_CONNTRACK_NONE, sch.type); SCTP_CONNTRACK_NONE, sch->type);
/* Invalid: delete conntrack */ /* Invalid: delete conntrack */
if (newconntrack == SCTP_CONNTRACK_MAX) { if (newconntrack == SCTP_CONNTRACK_MAX) {
...@@ -455,20 +461,20 @@ static int sctp_new(struct ip_conntrack *conntrack, ...@@ -455,20 +461,20 @@ static int sctp_new(struct ip_conntrack *conntrack,
} }
/* Copy the vtag into the state info */ /* Copy the vtag into the state info */
if (sch.type == SCTP_CID_INIT) { if (sch->type == SCTP_CID_INIT) {
if (sctph.vtag == 0) { if (sh->vtag == 0) {
sctp_inithdr_t inithdr; sctp_inithdr_t _inithdr, *ih;
if (skb_copy_bits(skb, offset + sizeof (sctp_chunkhdr_t), ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
&inithdr, sizeof(inithdr)) != 0) { sizeof(_inithdr), &_inithdr);
return 0; if (ih == NULL)
} return 0;
DEBUGP("Setting vtag %x for new conn\n", DEBUGP("Setting vtag %x for new conn\n",
inithdr.init_tag); ih->init_tag);
conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] =
inithdr.init_tag; ih->init_tag;
} else { } else {
/* Sec 8.5.1 (A) */ /* Sec 8.5.1 (A) */
return 0; return 0;
...@@ -478,8 +484,8 @@ static int sctp_new(struct ip_conntrack *conntrack, ...@@ -478,8 +484,8 @@ static int sctp_new(struct ip_conntrack *conntrack,
shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
else { else {
DEBUGP("Setting vtag %x for new conn OOTB\n", DEBUGP("Setting vtag %x for new conn OOTB\n",
sctph.vtag); sh->vtag);
conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sctph.vtag; conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
} }
conntrack->proto.sctp.state = newconntrack; conntrack->proto.sctp.state = newconntrack;
......
...@@ -91,10 +91,11 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, ...@@ -91,10 +91,11 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
{ {
struct iphdr *iph = skb->nh.iph; struct iphdr *iph = skb->nh.iph;
unsigned int udplen = skb->len - iph->ihl * 4; unsigned int udplen = skb->len - iph->ihl * 4;
struct udphdr hdr; struct udphdr _hdr, *hdr;
/* Header is too small? */ /* Header is too small? */
if (skb_copy_bits(skb, iph->ihl*4, &hdr, sizeof(hdr)) != 0) { hdr = skb_header_pointer(skb, iph->ihl*4, sizeof(_hdr), &_hdr);
if (hdr == NULL) {
if (LOG_INVALID(IPPROTO_UDP)) if (LOG_INVALID(IPPROTO_UDP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, nf_log_packet(PF_INET, 0, skb, NULL, NULL,
"ip_ct_udp: short packet "); "ip_ct_udp: short packet ");
...@@ -102,7 +103,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, ...@@ -102,7 +103,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
} }
/* Truncated/malformed packets */ /* Truncated/malformed packets */
if (ntohs(hdr.len) > udplen || ntohs(hdr.len) < sizeof(hdr)) { if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
if (LOG_INVALID(IPPROTO_UDP)) if (LOG_INVALID(IPPROTO_UDP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, nf_log_packet(PF_INET, 0, skb, NULL, NULL,
"ip_ct_udp: truncated/malformed packet "); "ip_ct_udp: truncated/malformed packet ");
...@@ -110,7 +111,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, ...@@ -110,7 +111,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
} }
/* Packet with no checksum */ /* Packet with no checksum */
if (!hdr.check) if (!hdr->check)
return NF_ACCEPT; return NF_ACCEPT;
/* Checksum invalid? Ignore. /* Checksum invalid? Ignore.
......
...@@ -871,7 +871,6 @@ EXPORT_SYMBOL(ip_conntrack_protocol_unregister); ...@@ -871,7 +871,6 @@ EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
EXPORT_SYMBOL(invert_tuplepr); EXPORT_SYMBOL(invert_tuplepr);
EXPORT_SYMBOL(ip_conntrack_alter_reply); EXPORT_SYMBOL(ip_conntrack_alter_reply);
EXPORT_SYMBOL(ip_conntrack_destroyed); EXPORT_SYMBOL(ip_conntrack_destroyed);
EXPORT_SYMBOL(ip_conntrack_get);
EXPORT_SYMBOL(need_ip_conntrack); EXPORT_SYMBOL(need_ip_conntrack);
EXPORT_SYMBOL(ip_conntrack_helper_register); EXPORT_SYMBOL(ip_conntrack_helper_register);
EXPORT_SYMBOL(ip_conntrack_helper_unregister); EXPORT_SYMBOL(ip_conntrack_helper_unregister);
......
...@@ -107,6 +107,7 @@ static struct ipt_match helper_match = { ...@@ -107,6 +107,7 @@ static struct ipt_match helper_match = {
static int __init init(void) static int __init init(void)
{ {
need_ip_conntrack();
return ipt_register_match(&helper_match); return ipt_register_match(&helper_match);
} }
......
...@@ -42,7 +42,7 @@ match_packet(const struct sk_buff *skb, ...@@ -42,7 +42,7 @@ match_packet(const struct sk_buff *skb,
{ {
int offset; int offset;
u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
sctp_chunkhdr_t sch; sctp_chunkhdr_t _sch, *sch;
#ifdef DEBUG_SCTP #ifdef DEBUG_SCTP
int i = 0; int i = 0;
...@@ -54,38 +54,39 @@ match_packet(const struct sk_buff *skb, ...@@ -54,38 +54,39 @@ match_packet(const struct sk_buff *skb,
offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t); offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
do { do {
if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) { sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
if (sch == NULL) {
duprintf("Dropping invalid SCTP packet.\n"); duprintf("Dropping invalid SCTP packet.\n");
*hotdrop = 1; *hotdrop = 1;
return 0; return 0;
} }
duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
++i, offset, sch.type, htons(sch.length), sch.flags); ++i, offset, sch->type, htons(sch->length), sch->flags);
offset += (htons(sch.length) + 3) & ~3; offset += (htons(sch->length) + 3) & ~3;
duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) { if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) {
switch (chunk_match_type) { switch (chunk_match_type) {
case SCTP_CHUNK_MATCH_ANY: case SCTP_CHUNK_MATCH_ANY:
if (match_flags(flag_info, flag_count, if (match_flags(flag_info, flag_count,
sch.type, sch.flags)) { sch->type, sch->flags)) {
return 1; return 1;
} }
break; break;
case SCTP_CHUNK_MATCH_ALL: case SCTP_CHUNK_MATCH_ALL:
if (match_flags(flag_info, flag_count, if (match_flags(flag_info, flag_count,
sch.type, sch.flags)) { sch->type, sch->flags)) {
SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type); SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
} }
break; break;
case SCTP_CHUNK_MATCH_ONLY: case SCTP_CHUNK_MATCH_ONLY:
if (!match_flags(flag_info, flag_count, if (!match_flags(flag_info, flag_count,
sch.type, sch.flags)) { sch->type, sch->flags)) {
return 0; return 0;
} }
break; break;
...@@ -120,7 +121,7 @@ match(const struct sk_buff *skb, ...@@ -120,7 +121,7 @@ match(const struct sk_buff *skb,
int *hotdrop) int *hotdrop)
{ {
const struct ipt_sctp_info *info; const struct ipt_sctp_info *info;
sctp_sctphdr_t sh; sctp_sctphdr_t _sh, *sh;
info = (const struct ipt_sctp_info *)matchinfo; info = (const struct ipt_sctp_info *)matchinfo;
...@@ -129,18 +130,19 @@ match(const struct sk_buff *skb, ...@@ -129,18 +130,19 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) { sh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_sh), &_sh);
if (sh == NULL) {
duprintf("Dropping evil TCP offset=0 tinygram.\n"); duprintf("Dropping evil TCP offset=0 tinygram.\n");
*hotdrop = 1; *hotdrop = 1;
return 0; return 0;
} }
duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest)); duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
return SCCHECK(((ntohs(sh.source) >= info->spts[0]) return SCCHECK(((ntohs(sh->source) >= info->spts[0])
&& (ntohs(sh.source) <= info->spts[1])), && (ntohs(sh->source) <= info->spts[1])),
IPT_SCTP_SRC_PORTS, info->flags, info->invflags) IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
&& SCCHECK(((ntohs(sh.dest) >= info->dpts[0]) && SCCHECK(((ntohs(sh->dest) >= info->dpts[0])
&& (ntohs(sh.dest) <= info->dpts[1])), && (ntohs(sh->dest) <= info->dpts[1])),
IPT_SCTP_DEST_PORTS, info->flags, info->invflags) IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
&& SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type, && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
info->flag_info, info->flag_count, info->flag_info, info->flag_count,
......
...@@ -68,8 +68,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) ...@@ -68,8 +68,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
if (tp->ecn_flags&TCP_ECN_OK) if (tp->ecn_flags&TCP_ECN_OK)
info->tcpi_options |= TCPI_OPT_ECN; info->tcpi_options |= TCPI_OPT_ECN;
info->tcpi_rto = (1000000*tp->rto)/HZ; info->tcpi_rto = jiffies_to_usecs(tp->rto);
info->tcpi_ato = (1000000*tp->ack.ato)/HZ; info->tcpi_ato = jiffies_to_usecs(tp->ack.ato);
info->tcpi_snd_mss = tp->mss_cache_std; info->tcpi_snd_mss = tp->mss_cache_std;
info->tcpi_rcv_mss = tp->ack.rcv_mss; info->tcpi_rcv_mss = tp->ack.rcv_mss;
...@@ -79,20 +79,20 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) ...@@ -79,20 +79,20 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
info->tcpi_retrans = tcp_get_pcount(&tp->retrans_out); info->tcpi_retrans = tcp_get_pcount(&tp->retrans_out);
info->tcpi_fackets = tcp_get_pcount(&tp->fackets_out); info->tcpi_fackets = tcp_get_pcount(&tp->fackets_out);
info->tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ; info->tcpi_last_data_sent = jiffies_to_msecs(now - tp->lsndtime);
info->tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ; info->tcpi_last_data_recv = jiffies_to_msecs(now - tp->ack.lrcvtime);
info->tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ; info->tcpi_last_ack_recv = jiffies_to_msecs(now - tp->rcv_tstamp);
info->tcpi_pmtu = tp->pmtu_cookie; info->tcpi_pmtu = tp->pmtu_cookie;
info->tcpi_rcv_ssthresh = tp->rcv_ssthresh; info->tcpi_rcv_ssthresh = tp->rcv_ssthresh;
info->tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3; info->tcpi_rtt = jiffies_to_usecs(tp->srtt)>>3;
info->tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2; info->tcpi_rttvar = jiffies_to_usecs(tp->mdev)>>2;
info->tcpi_snd_ssthresh = tp->snd_ssthresh; info->tcpi_snd_ssthresh = tp->snd_ssthresh;
info->tcpi_snd_cwnd = tp->snd_cwnd; info->tcpi_snd_cwnd = tp->snd_cwnd;
info->tcpi_advmss = tp->advmss; info->tcpi_advmss = tp->advmss;
info->tcpi_reordering = tp->reordering; info->tcpi_reordering = tp->reordering;
info->tcpi_rcv_rtt = ((1000000*tp->rcv_rtt_est.rtt)/HZ)>>3; info->tcpi_rcv_rtt = jiffies_to_usecs(tp->rcv_rtt_est.rtt)>>3;
info->tcpi_rcv_space = tp->rcvq_space.space; info->tcpi_rcv_space = tp->rcvq_space.space;
} }
...@@ -116,7 +116,8 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -116,7 +116,8 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
if (ext & (1<<(TCPDIAG_INFO-1))) if (ext & (1<<(TCPDIAG_INFO-1)))
info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info)); info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
if (tcp_is_vegas(tp) && (ext & (1<<(TCPDIAG_VEGASINFO-1)))) if ((tcp_is_westwood(tp) || tcp_is_vegas(tp))
&& (ext & (1<<(TCPDIAG_VEGASINFO-1))))
vinfo = TCPDIAG_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*vinfo)); vinfo = TCPDIAG_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*vinfo));
} }
r->tcpdiag_family = sk->sk_family; r->tcpdiag_family = sk->sk_family;
...@@ -209,10 +210,17 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -209,10 +210,17 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
tcp_get_info(sk, info); tcp_get_info(sk, info);
if (vinfo) { if (vinfo) {
vinfo->tcpv_enabled = tp->vegas.doing_vegas_now; if (tcp_is_vegas(tp)) {
vinfo->tcpv_rttcnt = tp->vegas.cntRTT; vinfo->tcpv_enabled = tp->vegas.doing_vegas_now;
vinfo->tcpv_rtt = tp->vegas.baseRTT; vinfo->tcpv_rttcnt = tp->vegas.cntRTT;
vinfo->tcpv_minrtt = tp->vegas.minRTT; vinfo->tcpv_rtt = jiffies_to_usecs(tp->vegas.baseRTT);
vinfo->tcpv_minrtt = jiffies_to_usecs(tp->vegas.minRTT);
} else {
vinfo->tcpv_enabled = 0;
vinfo->tcpv_rttcnt = 0;
vinfo->tcpv_rtt = jiffies_to_usecs(tp->westwood.rtt);
vinfo->tcpv_minrtt = jiffies_to_usecs(tp->westwood.rtt_min);
}
} }
nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_len = skb->tail - b;
......
...@@ -555,17 +555,20 @@ static void tcp_event_data_recv(struct sock *sk, struct tcp_opt *tp, struct sk_b ...@@ -555,17 +555,20 @@ static void tcp_event_data_recv(struct sock *sk, struct tcp_opt *tp, struct sk_b
tcp_grow_window(sk, tp, skb); tcp_grow_window(sk, tp, skb);
} }
/* Set up a new TCP connection, depending on whether it should be /* When starting a new connection, pin down the current choice of
* using Vegas or not. * congestion algorithm.
*/ */
void tcp_vegas_init(struct tcp_opt *tp) void tcp_ca_init(struct tcp_opt *tp)
{ {
if (sysctl_tcp_vegas_cong_avoid) { if (sysctl_tcp_westwood)
tp->vegas.do_vegas = 1; tp->adv_cong = TCP_WESTWOOD;
else if (sysctl_tcp_bic)
tp->adv_cong = TCP_BIC;
else if (sysctl_tcp_vegas_cong_avoid) {
tp->adv_cong = TCP_VEGAS;
tp->vegas.baseRTT = 0x7fffffff; tp->vegas.baseRTT = 0x7fffffff;
tcp_vegas_enable(tp); tcp_vegas_enable(tp);
} else }
tcp_vegas_disable(tp);
} }
/* Do RTT sampling needed for Vegas. /* Do RTT sampling needed for Vegas.
...@@ -2039,7 +2042,7 @@ tcp_ack_update_rtt(struct tcp_opt *tp, int flag, s32 seq_rtt) ...@@ -2039,7 +2042,7 @@ tcp_ack_update_rtt(struct tcp_opt *tp, int flag, s32 seq_rtt)
static inline __u32 bictcp_cwnd(struct tcp_opt *tp) static inline __u32 bictcp_cwnd(struct tcp_opt *tp)
{ {
/* orignal Reno behaviour */ /* orignal Reno behaviour */
if (!sysctl_tcp_bic) if (!tcp_is_bic(tp))
return tp->snd_cwnd; return tp->snd_cwnd;
if (tp->bictcp.last_cwnd == tp->snd_cwnd && if (tp->bictcp.last_cwnd == tp->snd_cwnd &&
...@@ -2617,18 +2620,16 @@ static void westwood_filter(struct sock *sk, __u32 delta) ...@@ -2617,18 +2620,16 @@ static void westwood_filter(struct sock *sk, __u32 delta)
* WESTWOOD_RTT_MIN minimum bound since we could be on a LAN! * WESTWOOD_RTT_MIN minimum bound since we could be on a LAN!
*/ */
static inline __u32 westwood_update_rttmin(struct sock *sk) static inline __u32 westwood_update_rttmin(const struct sock *sk)
{ {
struct tcp_opt *tp = tcp_sk(sk); const struct tcp_opt *tp = tcp_sk(sk);
__u32 rttmin = tp->westwood.rtt_min; __u32 rttmin = tp->westwood.rtt_min;
if (tp->westwood.rtt == 0) if (tp->westwood.rtt != 0 &&
return(rttmin); (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin))
if (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin)
rttmin = tp->westwood.rtt; rttmin = tp->westwood.rtt;
return(rttmin); return rttmin;
} }
/* /*
...@@ -2636,11 +2637,11 @@ static inline __u32 westwood_update_rttmin(struct sock *sk) ...@@ -2636,11 +2637,11 @@ static inline __u32 westwood_update_rttmin(struct sock *sk)
* Evaluate increases for dk. * Evaluate increases for dk.
*/ */
static inline __u32 westwood_acked(struct sock *sk) static inline __u32 westwood_acked(const struct sock *sk)
{ {
struct tcp_opt *tp = tcp_sk(sk); const struct tcp_opt *tp = tcp_sk(sk);
return ((tp->snd_una) - (tp->westwood.snd_una)); return tp->snd_una - tp->westwood.snd_una;
} }
/* /*
...@@ -2652,9 +2653,9 @@ static inline __u32 westwood_acked(struct sock *sk) ...@@ -2652,9 +2653,9 @@ static inline __u32 westwood_acked(struct sock *sk)
* window, 1 if the sample has to be considered in the next window. * window, 1 if the sample has to be considered in the next window.
*/ */
static int westwood_new_window(struct sock *sk) static int westwood_new_window(const struct sock *sk)
{ {
struct tcp_opt *tp = tcp_sk(sk); const struct tcp_opt *tp = tcp_sk(sk);
__u32 left_bound; __u32 left_bound;
__u32 rtt; __u32 rtt;
int ret = 0; int ret = 0;
...@@ -2688,14 +2689,13 @@ static void __westwood_update_window(struct sock *sk, __u32 now) ...@@ -2688,14 +2689,13 @@ static void __westwood_update_window(struct sock *sk, __u32 now)
struct tcp_opt *tp = tcp_sk(sk); struct tcp_opt *tp = tcp_sk(sk);
__u32 delta = now - tp->westwood.rtt_win_sx; __u32 delta = now - tp->westwood.rtt_win_sx;
if (!delta) if (delta) {
return; if (tp->westwood.rtt)
westwood_filter(sk, delta);
if (tp->westwood.rtt)
westwood_filter(sk, delta);
tp->westwood.bk = 0; tp->westwood.bk = 0;
tp->westwood.rtt_win_sx = tcp_time_stamp; tp->westwood.rtt_win_sx = tcp_time_stamp;
}
} }
...@@ -2739,7 +2739,7 @@ static void westwood_dupack_update(struct sock *sk) ...@@ -2739,7 +2739,7 @@ static void westwood_dupack_update(struct sock *sk)
static inline int westwood_may_change_cumul(struct tcp_opt *tp) static inline int westwood_may_change_cumul(struct tcp_opt *tp)
{ {
return ((tp->westwood.cumul_ack) > tp->mss_cache_std); return (tp->westwood.cumul_ack > tp->mss_cache_std);
} }
static inline void westwood_partial_update(struct tcp_opt *tp) static inline void westwood_partial_update(struct tcp_opt *tp)
...@@ -2760,7 +2760,7 @@ static inline void westwood_complete_update(struct tcp_opt *tp) ...@@ -2760,7 +2760,7 @@ static inline void westwood_complete_update(struct tcp_opt *tp)
* delayed or partial acks. * delayed or partial acks.
*/ */
static __u32 westwood_acked_count(struct sock *sk) static inline __u32 westwood_acked_count(struct sock *sk)
{ {
struct tcp_opt *tp = tcp_sk(sk); struct tcp_opt *tp = tcp_sk(sk);
...@@ -2774,7 +2774,7 @@ static __u32 westwood_acked_count(struct sock *sk) ...@@ -2774,7 +2774,7 @@ static __u32 westwood_acked_count(struct sock *sk)
if (westwood_may_change_cumul(tp)) { if (westwood_may_change_cumul(tp)) {
/* Partial or delayed ack */ /* Partial or delayed ack */
if ((tp->westwood.accounted) >= (tp->westwood.cumul_ack)) if (tp->westwood.accounted >= tp->westwood.cumul_ack)
westwood_partial_update(tp); westwood_partial_update(tp);
else else
westwood_complete_update(tp); westwood_complete_update(tp);
......
...@@ -841,7 +841,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, ...@@ -841,7 +841,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
if (newtp->ecn_flags&TCP_ECN_OK) if (newtp->ecn_flags&TCP_ECN_OK)
newsk->sk_no_largesend = 1; newsk->sk_no_largesend = 1;
tcp_vegas_init(newtp); tcp_ca_init(newtp);
TCP_INC_STATS_BH(TCP_MIB_PASSIVEOPENS); TCP_INC_STATS_BH(TCP_MIB_PASSIVEOPENS);
} }
return newsk; return newsk;
......
...@@ -1359,7 +1359,7 @@ static inline void tcp_connect_init(struct sock *sk) ...@@ -1359,7 +1359,7 @@ static inline void tcp_connect_init(struct sock *sk)
tp->window_clamp = dst_metric(dst, RTAX_WINDOW); tp->window_clamp = dst_metric(dst, RTAX_WINDOW);
tp->advmss = dst_metric(dst, RTAX_ADVMSS); tp->advmss = dst_metric(dst, RTAX_ADVMSS);
tcp_initialize_rcv_mss(sk); tcp_initialize_rcv_mss(sk);
tcp_vegas_init(tp); tcp_ca_init(tp);
tcp_select_initial_window(tcp_full_space(sk), tcp_select_initial_window(tcp_full_space(sk),
tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
...@@ -1411,7 +1411,7 @@ int tcp_connect(struct sock *sk) ...@@ -1411,7 +1411,7 @@ int tcp_connect(struct sock *sk)
TCP_SKB_CB(buff)->end_seq = tp->write_seq; TCP_SKB_CB(buff)->end_seq = tp->write_seq;
tp->snd_nxt = tp->write_seq; tp->snd_nxt = tp->write_seq;
tp->pushed_seq = tp->write_seq; tp->pushed_seq = tp->write_seq;
tcp_vegas_init(tp); tcp_ca_init(tp);
/* Send it off. */ /* Send it off. */
TCP_SKB_CB(buff)->when = tcp_time_stamp; TCP_SKB_CB(buff)->when = tcp_time_stamp;
......
...@@ -128,6 +128,9 @@ static struct timer_list addr_chk_timer = ...@@ -128,6 +128,9 @@ static struct timer_list addr_chk_timer =
TIMER_INITIALIZER(addrconf_verify, 0, 0); TIMER_INITIALIZER(addrconf_verify, 0, 0);
static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED; static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
static int addrconf_ifdown(struct net_device *dev, int how); static int addrconf_ifdown(struct net_device *dev, int how);
static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags); static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
...@@ -419,33 +422,28 @@ static void dev_forward_change(struct inet6_dev *idev) ...@@ -419,33 +422,28 @@ static void dev_forward_change(struct inet6_dev *idev)
ipv6_dev_mc_dec(dev, &addr); ipv6_dev_mc_dec(dev, &addr);
} }
for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
ipv6_addr_prefix(&addr, &ifa->addr, ifa->prefix_len);
if (ipv6_addr_any(&addr))
continue;
if (idev->cnf.forwarding) if (idev->cnf.forwarding)
ipv6_dev_ac_inc(idev->dev, &addr); addrconf_join_anycast(ifa);
else else
ipv6_dev_ac_dec(idev->dev, &addr); addrconf_leave_anycast(ifa);
} }
} }
static void addrconf_forward_change(struct inet6_dev *idev) static void addrconf_forward_change(void)
{ {
struct net_device *dev; struct net_device *dev;
struct inet6_dev *idev;
if (idev) {
dev_forward_change(idev);
return;
}
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev=dev_base; dev; dev=dev->next) { for (dev=dev_base; dev; dev=dev->next) {
read_lock(&addrconf_lock); read_lock(&addrconf_lock);
idev = __in6_dev_get(dev); idev = __in6_dev_get(dev);
if (idev) { if (idev) {
int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding);
idev->cnf.forwarding = ipv6_devconf.forwarding; idev->cnf.forwarding = ipv6_devconf.forwarding;
dev_forward_change(idev); if (changed)
dev_forward_change(idev);
} }
read_unlock(&addrconf_lock); read_unlock(&addrconf_lock);
} }
...@@ -1062,17 +1060,34 @@ void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) ...@@ -1062,17 +1060,34 @@ void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
ipv6_dev_mc_inc(dev, &maddr); ipv6_dev_mc_inc(dev, &maddr);
} }
void addrconf_leave_solict(struct net_device *dev, struct in6_addr *addr) void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr)
{ {
struct in6_addr maddr; struct in6_addr maddr;
if (dev->flags&(IFF_LOOPBACK|IFF_NOARP)) if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP))
return; return;
addrconf_addr_solict_mult(addr, &maddr); addrconf_addr_solict_mult(addr, &maddr);
ipv6_dev_mc_dec(dev, &maddr); __ipv6_dev_mc_dec(idev, &maddr);
}
void addrconf_join_anycast(struct inet6_ifaddr *ifp)
{
struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (ipv6_addr_any(&addr))
return;
ipv6_dev_ac_inc(ifp->idev->dev, &addr);
} }
void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
{
struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (ipv6_addr_any(&addr))
return;
__ipv6_dev_ac_dec(ifp->idev, &addr);
}
static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
{ {
...@@ -2225,14 +2240,6 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) ...@@ -2225,14 +2240,6 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval); addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval);
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
} }
if (ifp->idev->cnf.forwarding) {
struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (!ipv6_addr_any(&addr))
ipv6_dev_ac_inc(ifp->idev->dev, &addr);
}
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -2994,16 +3001,13 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) ...@@ -2994,16 +3001,13 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
dst_hold(&ifp->rt->u.dst); dst_hold(&ifp->rt->u.dst);
if (ip6_ins_rt(ifp->rt, NULL, NULL)) if (ip6_ins_rt(ifp->rt, NULL, NULL))
dst_release(&ifp->rt->u.dst); dst_release(&ifp->rt->u.dst);
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
break; break;
case RTM_DELADDR: case RTM_DELADDR:
addrconf_leave_solict(ifp->idev->dev, &ifp->addr); if (ifp->idev->cnf.forwarding)
if (ifp->idev->cnf.forwarding) { addrconf_leave_anycast(ifp);
struct in6_addr addr; addrconf_leave_solict(ifp->idev, &ifp->addr);
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (!ipv6_addr_any(&addr))
ipv6_dev_ac_dec(ifp->idev->dev, &addr);
}
dst_hold(&ifp->rt->u.dst); dst_hold(&ifp->rt->u.dst);
if (ip6_del_rt(ifp->rt, NULL, NULL)) if (ip6_del_rt(ifp->rt, NULL, NULL))
dst_free(&ifp->rt->u.dst); dst_free(&ifp->rt->u.dst);
...@@ -3025,18 +3029,18 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp, ...@@ -3025,18 +3029,18 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
if (write && *valp != val && valp != &ipv6_devconf_dflt.forwarding) { if (write && valp != &ipv6_devconf_dflt.forwarding) {
struct inet6_dev *idev = NULL;
if (valp != &ipv6_devconf.forwarding) { if (valp != &ipv6_devconf.forwarding) {
idev = (struct inet6_dev *)ctl->extra1; if ((!*valp) ^ (!val)) {
if (idev == NULL) struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1;
return ret; if (idev == NULL)
} else return ret;
dev_forward_change(idev);
}
} else {
ipv6_devconf_dflt.forwarding = ipv6_devconf.forwarding; ipv6_devconf_dflt.forwarding = ipv6_devconf.forwarding;
addrconf_forward_change();
addrconf_forward_change(idev); }
if (*valp) if (*valp)
rt6_purge_dflt_routers(0); rt6_purge_dflt_routers(0);
} }
...@@ -3077,15 +3081,19 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, ...@@ -3077,15 +3081,19 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
} }
if (valp != &ipv6_devconf_dflt.forwarding) { if (valp != &ipv6_devconf_dflt.forwarding) {
struct inet6_dev *idev;
if (valp != &ipv6_devconf.forwarding) { if (valp != &ipv6_devconf.forwarding) {
idev = (struct inet6_dev *)table->extra1; struct inet6_dev *idev = (struct inet6_dev *)table->extra1;
int changed;
if (unlikely(idev == NULL)) if (unlikely(idev == NULL))
return -ENODEV; return -ENODEV;
} else changed = (!*valp) ^ (!new);
idev = NULL; *valp = new;
*valp = new; if (changed)
addrconf_forward_change(idev); dev_forward_change(idev);
} else {
*valp = new;
addrconf_forward_change();
}
if (*valp) if (*valp)
rt6_purge_dflt_routers(0); rt6_purge_dflt_routers(0);
......
...@@ -377,15 +377,10 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) ...@@ -377,15 +377,10 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
/* /*
* device anycast group decrement * device anycast group decrement
*/ */
int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
{ {
struct inet6_dev *idev;
struct ifacaddr6 *aca, *prev_aca; struct ifacaddr6 *aca, *prev_aca;
idev = in6_dev_get(dev);
if (idev == NULL)
return -ENODEV;
write_lock_bh(&idev->lock); write_lock_bh(&idev->lock);
prev_aca = NULL; prev_aca = NULL;
for (aca = idev->ac_list; aca; aca = aca->aca_next) { for (aca = idev->ac_list; aca; aca = aca->aca_next) {
...@@ -395,12 +390,10 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) ...@@ -395,12 +390,10 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
} }
if (!aca) { if (!aca) {
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
in6_dev_put(idev);
return -ENOENT; return -ENOENT;
} }
if (--aca->aca_users > 0) { if (--aca->aca_users > 0) {
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
in6_dev_put(idev);
return 0; return 0;
} }
if (prev_aca) if (prev_aca)
...@@ -408,7 +401,7 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) ...@@ -408,7 +401,7 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
else else
idev->ac_list = aca->aca_next; idev->ac_list = aca->aca_next;
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
addrconf_leave_solict(dev, &aca->aca_addr); addrconf_leave_solict(idev, &aca->aca_addr);
dst_hold(&aca->aca_rt->u.dst); dst_hold(&aca->aca_rt->u.dst);
if (ip6_del_rt(aca->aca_rt, NULL, NULL)) if (ip6_del_rt(aca->aca_rt, NULL, NULL))
...@@ -417,10 +410,20 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) ...@@ -417,10 +410,20 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
dst_release(&aca->aca_rt->u.dst); dst_release(&aca->aca_rt->u.dst);
aca_put(aca); aca_put(aca);
in6_dev_put(idev);
return 0; return 0;
} }
int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
{
int ret;
struct inet6_dev *idev = in6_dev_get(dev);
if (idev == NULL)
return -ENODEV;
ret = __ipv6_dev_ac_dec(idev, addr);
in6_dev_put(idev);
return ret;
}
/* /*
* check if the interface has this anycast address * check if the interface has this anycast address
*/ */
......
...@@ -128,6 +128,8 @@ static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED; ...@@ -128,6 +128,8 @@ static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;
static struct socket *igmp6_socket; static struct socket *igmp6_socket;
int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr);
static void igmp6_join_group(struct ifmcaddr6 *ma); static void igmp6_join_group(struct ifmcaddr6 *ma);
static void igmp6_leave_group(struct ifmcaddr6 *ma); static void igmp6_leave_group(struct ifmcaddr6 *ma);
static void igmp6_timer_handler(unsigned long data); static void igmp6_timer_handler(unsigned long data);
...@@ -256,9 +258,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -256,9 +258,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
if (idev) { if (idev) {
(void) ip6_mc_leave_src(sk,mc_lst,idev); (void) ip6_mc_leave_src(sk,mc_lst,idev);
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
in6_dev_put(idev); in6_dev_put(idev);
} }
ipv6_dev_mc_dec(dev, &mc_lst->addr);
dev_put(dev); dev_put(dev);
} }
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
...@@ -322,9 +324,9 @@ void ipv6_sock_mc_close(struct sock *sk) ...@@ -322,9 +324,9 @@ void ipv6_sock_mc_close(struct sock *sk)
if (idev) { if (idev) {
(void) ip6_mc_leave_src(sk, mc_lst, idev); (void) ip6_mc_leave_src(sk, mc_lst, idev);
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
in6_dev_put(idev); in6_dev_put(idev);
} }
ipv6_dev_mc_dec(dev, &mc_lst->addr);
dev_put(dev); dev_put(dev);
} }
...@@ -870,7 +872,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) ...@@ -870,7 +872,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
/* /*
* device multicast group del * device multicast group del
*/ */
static int __ipv6_dev_mc_dec(struct net_device *dev, struct inet6_dev *idev, struct in6_addr *addr) int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr)
{ {
struct ifmcaddr6 *ma, **map; struct ifmcaddr6 *ma, **map;
...@@ -903,7 +905,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) ...@@ -903,7 +905,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
if (!idev) if (!idev)
return -ENODEV; return -ENODEV;
err = __ipv6_dev_mc_dec(dev, idev, addr); err = __ipv6_dev_mc_dec(idev, addr);
in6_dev_put(idev); in6_dev_put(idev);
...@@ -2108,7 +2110,12 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) ...@@ -2108,7 +2110,12 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
* addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will
* fail. * fail.
*/ */
__ipv6_dev_mc_dec(idev->dev, idev, &maddr); __ipv6_dev_mc_dec(idev, &maddr);
if (idev->cnf.forwarding) {
ipv6_addr_all_routers(&maddr);
__ipv6_dev_mc_dec(idev, &maddr);
}
write_lock_bh(&idev->lock); write_lock_bh(&idev->lock);
while ((i = idev->mc_list) != NULL) { while ((i = idev->mc_list) != NULL) {
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
#include <linux/jhash.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h> #include <net/snmp.h>
...@@ -270,15 +271,14 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d ...@@ -270,15 +271,14 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
static u32 ndisc_hash(const void *pkey, const struct net_device *dev) static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
{ {
u32 hash_val; const u32 *p32 = pkey;
u32 addr_hash, i;
hash_val = *(u32*)(pkey + sizeof(struct in6_addr) - 4); addr_hash = 0;
hash_val ^= (hash_val>>16); for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
hash_val ^= hash_val>>8; addr_hash ^= *p32++;
hash_val ^= hash_val>>3;
hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
return hash_val; return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd);
} }
static int ndisc_constructor(struct neighbour *neigh) static int ndisc_constructor(struct neighbour *neigh)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment