git://git.onelab.eu
/
linux-2.6.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git]
/
net
/
ipv6
/
reassembly.c
diff --git
a/net/ipv6/reassembly.c
b/net/ipv6/reassembly.c
index
4e299c6
..
6f9a904
100644
(file)
--- a/
net/ipv6/reassembly.c
+++ b/
net/ipv6/reassembly.c
@@
-47,16
+47,17
@@
#include <net/snmp.h>
#include <net/ipv6.h>
#include <net/snmp.h>
#include <net/ipv6.h>
+#include <net/ip6_route.h>
#include <net/protocol.h>
#include <net/transp_v6.h>
#include <net/rawv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/protocol.h>
#include <net/transp_v6.h>
#include <net/rawv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
-int sysctl_ip6frag_high_thresh = 256*1024;
-int sysctl_ip6frag_low_thresh = 192*1024;
+int sysctl_ip6frag_high_thresh
__read_mostly
= 256*1024;
+int sysctl_ip6frag_low_thresh
__read_mostly
= 192*1024;
-int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT;
+int sysctl_ip6frag_time
__read_mostly
= IPV6_FRAG_TIMEOUT;
struct ip6frag_skb_cb
{
struct ip6frag_skb_cb
{
@@
-76,7
+77,7
@@
struct frag_queue
struct hlist_node list;
struct list_head lru_list; /* lru list member */
struct hlist_node list;
struct list_head lru_list; /* lru list member */
- __
u32
id; /* fragment id */
+ __
be32
id; /* fragment id */
struct in6_addr saddr;
struct in6_addr daddr;
struct in6_addr saddr;
struct in6_addr daddr;
@@
-124,35
+125,35
@@
static __inline__ void fq_unlink(struct frag_queue *fq)
* callers should be careful not to use the hash value outside the ipfrag_lock
* as doing so could race with ipfrag_hash_rnd being recalculated.
*/
* callers should be careful not to use the hash value outside the ipfrag_lock
* as doing so could race with ipfrag_hash_rnd being recalculated.
*/
-static unsigned int ip6qhashfn(
u
32 id, struct in6_addr *saddr,
+static unsigned int ip6qhashfn(
__be
32 id, struct in6_addr *saddr,
struct in6_addr *daddr)
{
u32 a, b, c;
struct in6_addr *daddr)
{
u32 a, b, c;
- a = saddr->s6_addr32[0];
- b = saddr->s6_addr32[1];
- c = saddr->s6_addr32[2];
+ a =
(__force u32)
saddr->s6_addr32[0];
+ b =
(__force u32)
saddr->s6_addr32[1];
+ c =
(__force u32)
saddr->s6_addr32[2];
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
c += ip6_frag_hash_rnd;
__jhash_mix(a, b, c);
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
c += ip6_frag_hash_rnd;
__jhash_mix(a, b, c);
- a += saddr->s6_addr32[3];
- b += daddr->s6_addr32[0];
- c += daddr->s6_addr32[1];
+ a +=
(__force u32)
saddr->s6_addr32[3];
+ b +=
(__force u32)
daddr->s6_addr32[0];
+ c +=
(__force u32)
daddr->s6_addr32[1];
__jhash_mix(a, b, c);
__jhash_mix(a, b, c);
- a += daddr->s6_addr32[2];
- b += daddr->s6_addr32[3];
- c += id;
+ a +=
(__force u32)
daddr->s6_addr32[2];
+ b +=
(__force u32)
daddr->s6_addr32[3];
+ c +=
(__force u32)
id;
__jhash_mix(a, b, c);
return c & (IP6Q_HASHSZ - 1);
}
static struct timer_list ip6_frag_secret_timer;
__jhash_mix(a, b, c);
return c & (IP6Q_HASHSZ - 1);
}
static struct timer_list ip6_frag_secret_timer;
-int sysctl_ip6frag_secret_interval = 10 * 60 * HZ;
+int sysctl_ip6frag_secret_interval
__read_mostly
= 10 * 60 * HZ;
static void ip6_frag_secret_rebuild(unsigned long dummy)
{
static void ip6_frag_secret_rebuild(unsigned long dummy)
{
@@
-257,7
+258,7
@@
static __inline__ void fq_kill(struct frag_queue *fq)
}
}
}
}
-static void ip6_evictor(
void
)
+static void ip6_evictor(
struct inet6_dev *idev
)
{
struct frag_queue *fq;
struct list_head *tmp;
{
struct frag_queue *fq;
struct list_head *tmp;
@@
-284,14
+285,14
@@
static void ip6_evictor(void)
spin_unlock(&fq->lock);
fq_put(fq, &work);
spin_unlock(&fq->lock);
fq_put(fq, &work);
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+ IP6_INC_STATS_BH(
idev,
IPSTATS_MIB_REASMFAILS);
}
}
static void ip6_frag_expire(unsigned long data)
{
struct frag_queue *fq = (struct frag_queue *) data;
}
}
static void ip6_frag_expire(unsigned long data)
{
struct frag_queue *fq = (struct frag_queue *) data;
- struct net_device *dev;
+ struct net_device *dev
= NULL
;
spin_lock(&fq->lock);
spin_lock(&fq->lock);
@@
-300,17
+301,19
@@
static void ip6_frag_expire(unsigned long data)
fq_kill(fq);
fq_kill(fq);
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+ dev = dev_get_by_index(fq->iif);
+ if (!dev)
+ goto out;
+
+ rcu_read_lock();
+ IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
+ IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+ rcu_read_unlock();
/* Don't send error if the first segment did not arrive. */
if (!(fq->last_in&FIRST_IN) || !fq->fragments)
goto out;
/* Don't send error if the first segment did not arrive. */
if (!(fq->last_in&FIRST_IN) || !fq->fragments)
goto out;
- dev = dev_get_by_index(fq->iif);
- if (!dev)
- goto out;
-
/*
But use as source device on which LAST ARRIVED
segment was received. And do not use fq->dev
/*
But use as source device on which LAST ARRIVED
segment was received. And do not use fq->dev
@@
-318,8
+321,9
@@
static void ip6_frag_expire(unsigned long data)
*/
fq->fragments->dev = dev;
icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
*/
fq->fragments->dev = dev;
icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
- dev_put(dev);
out:
out:
+ if (dev)
+ dev_put(dev);
spin_unlock(&fq->lock);
fq_put(fq, NULL);
}
spin_unlock(&fq->lock);
fq_put(fq, NULL);
}
@@
-366,7
+370,8
@@
static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
static struct frag_queue *
static struct frag_queue *
-ip6_frag_create(u32 id, struct in6_addr *src, struct in6_addr *dst)
+ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst,
+ struct inet6_dev *idev)
{
struct frag_queue *fq;
{
struct frag_queue *fq;
@@
-386,12
+391,13
@@
ip6_frag_create(u32 id, struct in6_addr *src, struct in6_addr *dst)
return ip6_frag_intern(fq);
oom:
return ip6_frag_intern(fq);
oom:
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+ IP6_INC_STATS_BH(
idev,
IPSTATS_MIB_REASMFAILS);
return NULL;
}
static __inline__ struct frag_queue *
return NULL;
}
static __inline__ struct frag_queue *
-fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
+fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst,
+ struct inet6_dev *idev)
{
struct frag_queue *fq;
struct hlist_node *n;
{
struct frag_queue *fq;
struct hlist_node *n;
@@
-410,7
+416,7
@@
fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
}
read_unlock(&ip6_frag_lock);
}
read_unlock(&ip6_frag_lock);
- return ip6_frag_create(id, src, dst);
+ return ip6_frag_create(id, src, dst
, idev
);
}
}
@@
-428,12
+434,13
@@
static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
if ((unsigned int)end > IPV6_MAXPLEN) {
((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
if ((unsigned int)end > IPV6_MAXPLEN) {
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
return;
}
icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
return;
}
- if (skb->ip_summed == CHECKSUM_
HW
)
+ if (skb->ip_summed == CHECKSUM_
COMPLETE
)
skb->csum = csum_sub(skb->csum,
csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
skb->csum = csum_sub(skb->csum,
csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
@@
-455,7
+462,8
@@
static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
/* RFC2460 says always send parameter problem in
* this case. -DaveM
*/
/* RFC2460 says always send parameter problem in
* this case. -DaveM
*/
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
offsetof(struct ipv6hdr, payload_len));
return;
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
offsetof(struct ipv6hdr, payload_len));
return;
@@
-571,7
+579,7
@@
static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
return;
err:
return;
err:
- IP6_INC_STATS(IPSTATS_MIB_REASMFAILS);
+ IP6_INC_STATS(
ip6_dst_idev(skb->dst),
IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
}
kfree_skb(skb);
}
@@
-647,7
+655,7
@@
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
head->len += fp->len;
if (head->ip_summed != fp->ip_summed)
head->ip_summed = CHECKSUM_NONE;
head->len += fp->len;
if (head->ip_summed != fp->ip_summed)
head->ip_summed = CHECKSUM_NONE;
- else if (head->ip_summed == CHECKSUM_
HW
)
+ else if (head->ip_summed == CHECKSUM_
COMPLETE
)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
atomic_sub(fp->truesize, &ip6_frag_mem);
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
atomic_sub(fp->truesize, &ip6_frag_mem);
@@
-662,10
+670,12
@@
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
*skb_in = head;
/* Yes, and fold redundant checksum back. 8) */
*skb_in = head;
/* Yes, and fold redundant checksum back. 8) */
- if (head->ip_summed == CHECKSUM_
HW
)
+ if (head->ip_summed == CHECKSUM_
COMPLETE
)
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
+ rcu_read_lock();
+ IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
+ rcu_read_unlock();
fq->fragments = NULL;
return 1;
fq->fragments = NULL;
return 1;
@@
-677,7
+687,9
@@
out_oom:
if (net_ratelimit())
printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
out_fail:
if (net_ratelimit())
printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
out_fail:
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+ rcu_read_lock();
+ IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+ rcu_read_unlock();
return -1;
}
return -1;
}
@@
-691,16
+703,16
@@
static int ipv6_frag_rcv(struct sk_buff **skbp)
hdr = skb->nh.ipv6h;
hdr = skb->nh.ipv6h;
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
+ IP6_INC_STATS_BH(
ip6_dst_idev(skb->dst),
IPSTATS_MIB_REASMREQDS);
/* Jumbo payload inhibits frag. header */
if (hdr->payload_len==0) {
/* Jumbo payload inhibits frag. header */
if (hdr->payload_len==0) {
- IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS(
ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
- IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS(
ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
@@
-711,16
+723,17
@@
static int ipv6_frag_rcv(struct sk_buff **skbp)
if (!(fhdr->frag_off & htons(0xFFF9))) {
/* It is not a fragmented frame */
skb->h.raw += sizeof(struct frag_hdr);
if (!(fhdr->frag_off & htons(0xFFF9))) {
/* It is not a fragmented frame */
skb->h.raw += sizeof(struct frag_hdr);
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
+ IP6_INC_STATS_BH(
ip6_dst_idev(skb->dst),
IPSTATS_MIB_REASMOKS);
IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw;
return 1;
}
if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw;
return 1;
}
if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
- ip6_evictor();
+ ip6_evictor(
ip6_dst_idev(skb->dst)
);
- if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) {
+ if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr,
+ ip6_dst_idev(skb->dst))) != NULL) {
int ret = -1;
spin_lock(&fq->lock);
int ret = -1;
spin_lock(&fq->lock);
@@
-736,7
+749,7
@@
static int ipv6_frag_rcv(struct sk_buff **skbp)
return ret;
}
return ret;
}
- IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+ IP6_INC_STATS_BH(
ip6_dst_idev(skb->dst),
IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
return -1;
}
kfree_skb(skb);
return -1;
}