diff options
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r-- | net/ipv6/reassembly.c | 89 |
1 files changed, 24 insertions, 65 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 4ff9af628e72..da8a4e301b1b 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -65,36 +65,8 @@ struct ip6frag_skb_cb | |||
65 | #define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb)) | 65 | #define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb)) |
66 | 66 | ||
67 | 67 | ||
68 | /* | ||
69 | * Equivalent of ipv4 struct ipq | ||
70 | */ | ||
71 | |||
72 | struct frag_queue | ||
73 | { | ||
74 | struct inet_frag_queue q; | ||
75 | |||
76 | __be32 id; /* fragment id */ | ||
77 | u32 user; | ||
78 | struct in6_addr saddr; | ||
79 | struct in6_addr daddr; | ||
80 | |||
81 | int iif; | ||
82 | unsigned int csum; | ||
83 | __u16 nhoffset; | ||
84 | }; | ||
85 | |||
86 | static struct inet_frags ip6_frags; | 68 | static struct inet_frags ip6_frags; |
87 | 69 | ||
88 | int ip6_frag_nqueues(struct net *net) | ||
89 | { | ||
90 | return net->ipv6.frags.nqueues; | ||
91 | } | ||
92 | |||
93 | int ip6_frag_mem(struct net *net) | ||
94 | { | ||
95 | return atomic_read(&net->ipv6.frags.mem); | ||
96 | } | ||
97 | |||
98 | static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | 70 | static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, |
99 | struct net_device *dev); | 71 | struct net_device *dev); |
100 | 72 | ||
@@ -159,46 +131,18 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a) | |||
159 | } | 131 | } |
160 | EXPORT_SYMBOL(ip6_frag_init); | 132 | EXPORT_SYMBOL(ip6_frag_init); |
161 | 133 | ||
162 | /* Destruction primitives. */ | 134 | void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, |
163 | 135 | struct inet_frags *frags) | |
164 | static __inline__ void fq_put(struct frag_queue *fq) | ||
165 | { | ||
166 | inet_frag_put(&fq->q, &ip6_frags); | ||
167 | } | ||
168 | |||
169 | /* Kill fq entry. It is not destroyed immediately, | ||
170 | * because caller (and someone more) holds reference count. | ||
171 | */ | ||
172 | static __inline__ void fq_kill(struct frag_queue *fq) | ||
173 | { | ||
174 | inet_frag_kill(&fq->q, &ip6_frags); | ||
175 | } | ||
176 | |||
177 | static void ip6_evictor(struct net *net, struct inet6_dev *idev) | ||
178 | { | 136 | { |
179 | int evicted; | ||
180 | |||
181 | evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags); | ||
182 | if (evicted) | ||
183 | IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted); | ||
184 | } | ||
185 | |||
186 | static void ip6_frag_expire(unsigned long data) | ||
187 | { | ||
188 | struct frag_queue *fq; | ||
189 | struct net_device *dev = NULL; | 137 | struct net_device *dev = NULL; |
190 | struct net *net; | ||
191 | |||
192 | fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); | ||
193 | 138 | ||
194 | spin_lock(&fq->q.lock); | 139 | spin_lock(&fq->q.lock); |
195 | 140 | ||
196 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 141 | if (fq->q.last_in & INET_FRAG_COMPLETE) |
197 | goto out; | 142 | goto out; |
198 | 143 | ||
199 | fq_kill(fq); | 144 | inet_frag_kill(&fq->q, frags); |
200 | 145 | ||
201 | net = container_of(fq->q.net, struct net, ipv6.frags); | ||
202 | rcu_read_lock(); | 146 | rcu_read_lock(); |
203 | dev = dev_get_by_index_rcu(net, fq->iif); | 147 | dev = dev_get_by_index_rcu(net, fq->iif); |
204 | if (!dev) | 148 | if (!dev) |
@@ -222,7 +166,19 @@ out_rcu_unlock: | |||
222 | rcu_read_unlock(); | 166 | rcu_read_unlock(); |
223 | out: | 167 | out: |
224 | spin_unlock(&fq->q.lock); | 168 | spin_unlock(&fq->q.lock); |
225 | fq_put(fq); | 169 | inet_frag_put(&fq->q, frags); |
170 | } | ||
171 | EXPORT_SYMBOL(ip6_expire_frag_queue); | ||
172 | |||
173 | static void ip6_frag_expire(unsigned long data) | ||
174 | { | ||
175 | struct frag_queue *fq; | ||
176 | struct net *net; | ||
177 | |||
178 | fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); | ||
179 | net = container_of(fq->q.net, struct net, ipv6.frags); | ||
180 | |||
181 | ip6_expire_frag_queue(net, fq, &ip6_frags); | ||
226 | } | 182 | } |
227 | 183 | ||
228 | static __inline__ struct frag_queue * | 184 | static __inline__ struct frag_queue * |
@@ -391,7 +347,7 @@ found: | |||
391 | return -1; | 347 | return -1; |
392 | 348 | ||
393 | discard_fq: | 349 | discard_fq: |
394 | fq_kill(fq); | 350 | inet_frag_kill(&fq->q, &ip6_frags); |
395 | err: | 351 | err: |
396 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 352 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
397 | IPSTATS_MIB_REASMFAILS); | 353 | IPSTATS_MIB_REASMFAILS); |
@@ -417,7 +373,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
417 | unsigned int nhoff; | 373 | unsigned int nhoff; |
418 | int sum_truesize; | 374 | int sum_truesize; |
419 | 375 | ||
420 | fq_kill(fq); | 376 | inet_frag_kill(&fq->q, &ip6_frags); |
421 | 377 | ||
422 | /* Make the one we just received the head. */ | 378 | /* Make the one we just received the head. */ |
423 | if (prev) { | 379 | if (prev) { |
@@ -550,6 +506,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
550 | struct frag_queue *fq; | 506 | struct frag_queue *fq; |
551 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | 507 | const struct ipv6hdr *hdr = ipv6_hdr(skb); |
552 | struct net *net = dev_net(skb_dst(skb)->dev); | 508 | struct net *net = dev_net(skb_dst(skb)->dev); |
509 | int evicted; | ||
553 | 510 | ||
554 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); | 511 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); |
555 | 512 | ||
@@ -574,8 +531,10 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
574 | return 1; | 531 | return 1; |
575 | } | 532 | } |
576 | 533 | ||
577 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) | 534 | evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags, false); |
578 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); | 535 | if (evicted) |
536 | IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), | ||
537 | IPSTATS_MIB_REASMFAILS, evicted); | ||
579 | 538 | ||
580 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); | 539 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); |
581 | if (fq != NULL) { | 540 | if (fq != NULL) { |
@@ -586,7 +545,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
586 | ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff); | 545 | ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff); |
587 | 546 | ||
588 | spin_unlock(&fq->q.lock); | 547 | spin_unlock(&fq->q.lock); |
589 | fq_put(fq); | 548 | inet_frag_put(&fq->q, &ip6_frags); |
590 | return ret; | 549 | return ret; |
591 | } | 550 | } |
592 | 551 | ||