diff options
-rw-r--r-- | include/net/inet_frag.h | 6 | ||||
-rw-r--r-- | include/net/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv4/inet_fragment.c | 25 | ||||
-rw-r--r-- | net/ipv4/ip_fragment.c | 57 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 32 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 50 |
6 files changed, 73 insertions, 98 deletions
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index e33072b9fd91..64299266a868 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h | |||
@@ -45,6 +45,8 @@ struct inet_frags { | |||
45 | void (*skb_free)(struct sk_buff *); | 45 | void (*skb_free)(struct sk_buff *); |
46 | int (*equal)(struct inet_frag_queue *q1, | 46 | int (*equal)(struct inet_frag_queue *q1, |
47 | struct inet_frag_queue *q2); | 47 | struct inet_frag_queue *q2); |
48 | int (*match)(struct inet_frag_queue *q, | ||
49 | void *arg); | ||
48 | void (*frag_expire)(unsigned long data); | 50 | void (*frag_expire)(unsigned long data); |
49 | }; | 51 | }; |
50 | 52 | ||
@@ -55,8 +57,8 @@ void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); | |||
55 | void inet_frag_destroy(struct inet_frag_queue *q, | 57 | void inet_frag_destroy(struct inet_frag_queue *q, |
56 | struct inet_frags *f, int *work); | 58 | struct inet_frags *f, int *work); |
57 | int inet_frag_evictor(struct inet_frags *f); | 59 | int inet_frag_evictor(struct inet_frags *f); |
58 | struct inet_frag_queue *inet_frag_create(struct inet_frags *f, | 60 | struct inet_frag_queue *inet_frag_find(struct inet_frags *f, void *key, |
59 | void *create_arg, unsigned int hash); | 61 | unsigned int hash); |
60 | 62 | ||
61 | static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) | 63 | static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) |
62 | { | 64 | { |
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9dc99bf5cf0e..005853a33ef6 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -387,6 +387,7 @@ struct ip6_create_arg { | |||
387 | }; | 387 | }; |
388 | 388 | ||
389 | void ip6_frag_init(struct inet_frag_queue *q, void *a); | 389 | void ip6_frag_init(struct inet_frag_queue *q, void *a); |
390 | int ip6_frag_match(struct inet_frag_queue *q, void *a); | ||
390 | 391 | ||
391 | static inline int ipv6_addr_any(const struct in6_addr *a) | 392 | static inline int ipv6_addr_any(const struct in6_addr *a) |
392 | { | 393 | { |
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index b531f803cda4..6ba98ebbed93 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c | |||
@@ -226,8 +226,8 @@ static struct inet_frag_queue *inet_frag_alloc(struct inet_frags *f, void *arg) | |||
226 | return q; | 226 | return q; |
227 | } | 227 | } |
228 | 228 | ||
229 | struct inet_frag_queue *inet_frag_create(struct inet_frags *f, void *arg, | 229 | static struct inet_frag_queue *inet_frag_create(struct inet_frags *f, |
230 | unsigned int hash) | 230 | void *arg, unsigned int hash) |
231 | { | 231 | { |
232 | struct inet_frag_queue *q; | 232 | struct inet_frag_queue *q; |
233 | 233 | ||
@@ -237,4 +237,23 @@ struct inet_frag_queue *inet_frag_create(struct inet_frags *f, void *arg, | |||
237 | 237 | ||
238 | return inet_frag_intern(q, f, hash); | 238 | return inet_frag_intern(q, f, hash); |
239 | } | 239 | } |
240 | EXPORT_SYMBOL(inet_frag_create); | 240 | |
241 | struct inet_frag_queue *inet_frag_find(struct inet_frags *f, void *key, | ||
242 | unsigned int hash) | ||
243 | { | ||
244 | struct inet_frag_queue *q; | ||
245 | struct hlist_node *n; | ||
246 | |||
247 | read_lock(&f->lock); | ||
248 | hlist_for_each_entry(q, n, &f->hash[hash], list) { | ||
249 | if (f->match(q, key)) { | ||
250 | atomic_inc(&q->refcnt); | ||
251 | read_unlock(&f->lock); | ||
252 | return q; | ||
253 | } | ||
254 | } | ||
255 | read_unlock(&f->lock); | ||
256 | |||
257 | return inet_frag_create(f, key, hash); | ||
258 | } | ||
259 | EXPORT_SYMBOL(inet_frag_find); | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 0d6cff1de5a3..928259dbc0f8 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -142,6 +142,19 @@ static int ip4_frag_equal(struct inet_frag_queue *q1, | |||
142 | qp1->user == qp2->user); | 142 | qp1->user == qp2->user); |
143 | } | 143 | } |
144 | 144 | ||
145 | static int ip4_frag_match(struct inet_frag_queue *q, void *a) | ||
146 | { | ||
147 | struct ipq *qp; | ||
148 | struct ip4_create_arg *arg = a; | ||
149 | |||
150 | qp = container_of(q, struct ipq, q); | ||
151 | return (qp->id == arg->iph->id && | ||
152 | qp->saddr == arg->iph->saddr && | ||
153 | qp->daddr == arg->iph->daddr && | ||
154 | qp->protocol == arg->iph->protocol && | ||
155 | qp->user == arg->user); | ||
156 | } | ||
157 | |||
145 | /* Memory Tracking Functions. */ | 158 | /* Memory Tracking Functions. */ |
146 | static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) | 159 | static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) |
147 | { | 160 | { |
@@ -235,18 +248,20 @@ out: | |||
235 | ipq_put(qp); | 248 | ipq_put(qp); |
236 | } | 249 | } |
237 | 250 | ||
238 | /* Creation primitives. */ | 251 | /* Find the correct entry in the "incomplete datagrams" queue for |
239 | 252 | * this IP datagram, and create new one, if nothing is found. | |
240 | /* Add an entry to the 'ipq' queue for a newly received IP datagram. */ | 253 | */ |
241 | static struct ipq *ip_frag_create(struct iphdr *iph, u32 user, unsigned int h) | 254 | static inline struct ipq *ip_find(struct iphdr *iph, u32 user) |
242 | { | 255 | { |
243 | struct inet_frag_queue *q; | 256 | struct inet_frag_queue *q; |
244 | struct ip4_create_arg arg; | 257 | struct ip4_create_arg arg; |
258 | unsigned int hash; | ||
245 | 259 | ||
246 | arg.iph = iph; | 260 | arg.iph = iph; |
247 | arg.user = user; | 261 | arg.user = user; |
262 | hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); | ||
248 | 263 | ||
249 | q = inet_frag_create(&ip4_frags, &arg, h); | 264 | q = inet_frag_find(&ip4_frags, &arg, hash); |
250 | if (q == NULL) | 265 | if (q == NULL) |
251 | goto out_nomem; | 266 | goto out_nomem; |
252 | 267 | ||
@@ -257,37 +272,6 @@ out_nomem: | |||
257 | return NULL; | 272 | return NULL; |
258 | } | 273 | } |
259 | 274 | ||
260 | /* Find the correct entry in the "incomplete datagrams" queue for | ||
261 | * this IP datagram, and create new one, if nothing is found. | ||
262 | */ | ||
263 | static inline struct ipq *ip_find(struct iphdr *iph, u32 user) | ||
264 | { | ||
265 | __be16 id = iph->id; | ||
266 | __be32 saddr = iph->saddr; | ||
267 | __be32 daddr = iph->daddr; | ||
268 | __u8 protocol = iph->protocol; | ||
269 | unsigned int hash; | ||
270 | struct ipq *qp; | ||
271 | struct hlist_node *n; | ||
272 | |||
273 | read_lock(&ip4_frags.lock); | ||
274 | hash = ipqhashfn(id, saddr, daddr, protocol); | ||
275 | hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) { | ||
276 | if (qp->id == id && | ||
277 | qp->saddr == saddr && | ||
278 | qp->daddr == daddr && | ||
279 | qp->protocol == protocol && | ||
280 | qp->user == user) { | ||
281 | atomic_inc(&qp->q.refcnt); | ||
282 | read_unlock(&ip4_frags.lock); | ||
283 | return qp; | ||
284 | } | ||
285 | } | ||
286 | read_unlock(&ip4_frags.lock); | ||
287 | |||
288 | return ip_frag_create(iph, user, hash); | ||
289 | } | ||
290 | |||
291 | /* Is the fragment too far ahead to be part of ipq? */ | 275 | /* Is the fragment too far ahead to be part of ipq? */ |
292 | static inline int ip_frag_too_far(struct ipq *qp) | 276 | static inline int ip_frag_too_far(struct ipq *qp) |
293 | { | 277 | { |
@@ -648,6 +632,7 @@ void __init ipfrag_init(void) | |||
648 | ip4_frags.skb_free = NULL; | 632 | ip4_frags.skb_free = NULL; |
649 | ip4_frags.qsize = sizeof(struct ipq); | 633 | ip4_frags.qsize = sizeof(struct ipq); |
650 | ip4_frags.equal = ip4_frag_equal; | 634 | ip4_frags.equal = ip4_frag_equal; |
635 | ip4_frags.match = ip4_frag_match; | ||
651 | ip4_frags.frag_expire = ip_expire; | 636 | ip4_frags.frag_expire = ip_expire; |
652 | inet_frags_init(&ip4_frags); | 637 | inet_frags_init(&ip4_frags); |
653 | } | 638 | } |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 127d1d842786..bff63d79c644 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -176,18 +176,19 @@ out: | |||
176 | 176 | ||
177 | /* Creation primitives. */ | 177 | /* Creation primitives. */ |
178 | 178 | ||
179 | static struct nf_ct_frag6_queue * | 179 | static __inline__ struct nf_ct_frag6_queue * |
180 | nf_ct_frag6_create(unsigned int hash, __be32 id, struct in6_addr *src, | 180 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) |
181 | struct in6_addr *dst) | ||
182 | { | 181 | { |
183 | struct inet_frag_queue *q; | 182 | struct inet_frag_queue *q; |
184 | struct ip6_create_arg arg; | 183 | struct ip6_create_arg arg; |
184 | unsigned int hash; | ||
185 | 185 | ||
186 | arg.id = id; | 186 | arg.id = id; |
187 | arg.src = src; | 187 | arg.src = src; |
188 | arg.dst = dst; | 188 | arg.dst = dst; |
189 | hash = ip6qhashfn(id, src, dst); | ||
189 | 190 | ||
190 | q = inet_frag_create(&nf_frags, &arg, hash); | 191 | q = inet_frag_find(&nf_frags, &arg, hash); |
191 | if (q == NULL) | 192 | if (q == NULL) |
192 | goto oom; | 193 | goto oom; |
193 | 194 | ||
@@ -198,28 +199,6 @@ oom: | |||
198 | return NULL; | 199 | return NULL; |
199 | } | 200 | } |
200 | 201 | ||
201 | static __inline__ struct nf_ct_frag6_queue * | ||
202 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) | ||
203 | { | ||
204 | struct nf_ct_frag6_queue *fq; | ||
205 | struct hlist_node *n; | ||
206 | unsigned int hash = ip6qhashfn(id, src, dst); | ||
207 | |||
208 | read_lock(&nf_frags.lock); | ||
209 | hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) { | ||
210 | if (fq->id == id && | ||
211 | ipv6_addr_equal(src, &fq->saddr) && | ||
212 | ipv6_addr_equal(dst, &fq->daddr)) { | ||
213 | atomic_inc(&fq->q.refcnt); | ||
214 | read_unlock(&nf_frags.lock); | ||
215 | return fq; | ||
216 | } | ||
217 | } | ||
218 | read_unlock(&nf_frags.lock); | ||
219 | |||
220 | return nf_ct_frag6_create(hash, id, src, dst); | ||
221 | } | ||
222 | |||
223 | 202 | ||
224 | static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | 203 | static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, |
225 | struct frag_hdr *fhdr, int nhoff) | 204 | struct frag_hdr *fhdr, int nhoff) |
@@ -706,6 +685,7 @@ int nf_ct_frag6_init(void) | |||
706 | nf_frags.destructor = nf_frag_free; | 685 | nf_frags.destructor = nf_frag_free; |
707 | nf_frags.skb_free = nf_skb_free; | 686 | nf_frags.skb_free = nf_skb_free; |
708 | nf_frags.qsize = sizeof(struct nf_ct_frag6_queue); | 687 | nf_frags.qsize = sizeof(struct nf_ct_frag6_queue); |
688 | nf_frags.match = ip6_frag_match; | ||
709 | nf_frags.equal = ip6_frag_equal; | 689 | nf_frags.equal = ip6_frag_equal; |
710 | nf_frags.frag_expire = nf_ct_frag6_expire; | 690 | nf_frags.frag_expire = nf_ct_frag6_expire; |
711 | inet_frags_init(&nf_frags); | 691 | inet_frags_init(&nf_frags); |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index ce8734028d94..11fffe791fc4 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -155,6 +155,18 @@ int ip6_frag_equal(struct inet_frag_queue *q1, struct inet_frag_queue *q2) | |||
155 | } | 155 | } |
156 | EXPORT_SYMBOL(ip6_frag_equal); | 156 | EXPORT_SYMBOL(ip6_frag_equal); |
157 | 157 | ||
158 | int ip6_frag_match(struct inet_frag_queue *q, void *a) | ||
159 | { | ||
160 | struct frag_queue *fq; | ||
161 | struct ip6_create_arg *arg = a; | ||
162 | |||
163 | fq = container_of(q, struct frag_queue, q); | ||
164 | return (fq->id == arg->id && | ||
165 | ipv6_addr_equal(&fq->saddr, arg->src) && | ||
166 | ipv6_addr_equal(&fq->daddr, arg->dst)); | ||
167 | } | ||
168 | EXPORT_SYMBOL(ip6_frag_match); | ||
169 | |||
158 | /* Memory Tracking Functions. */ | 170 | /* Memory Tracking Functions. */ |
159 | static inline void frag_kfree_skb(struct sk_buff *skb, int *work) | 171 | static inline void frag_kfree_skb(struct sk_buff *skb, int *work) |
160 | { | 172 | { |
@@ -245,20 +257,20 @@ out: | |||
245 | fq_put(fq); | 257 | fq_put(fq); |
246 | } | 258 | } |
247 | 259 | ||
248 | /* Creation primitives. */ | 260 | static __inline__ struct frag_queue * |
249 | 261 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst, | |
250 | static struct frag_queue * | 262 | struct inet6_dev *idev) |
251 | ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst, | ||
252 | struct inet6_dev *idev, unsigned int hash) | ||
253 | { | 263 | { |
254 | struct inet_frag_queue *q; | 264 | struct inet_frag_queue *q; |
255 | struct ip6_create_arg arg; | 265 | struct ip6_create_arg arg; |
266 | unsigned int hash; | ||
256 | 267 | ||
257 | arg.id = id; | 268 | arg.id = id; |
258 | arg.src = src; | 269 | arg.src = src; |
259 | arg.dst = dst; | 270 | arg.dst = dst; |
271 | hash = ip6qhashfn(id, src, dst); | ||
260 | 272 | ||
261 | q = inet_frag_create(&ip6_frags, &arg, hash); | 273 | q = inet_frag_find(&ip6_frags, &arg, hash); |
262 | if (q == NULL) | 274 | if (q == NULL) |
263 | goto oom; | 275 | goto oom; |
264 | 276 | ||
@@ -269,31 +281,6 @@ oom: | |||
269 | return NULL; | 281 | return NULL; |
270 | } | 282 | } |
271 | 283 | ||
272 | static __inline__ struct frag_queue * | ||
273 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst, | ||
274 | struct inet6_dev *idev) | ||
275 | { | ||
276 | struct frag_queue *fq; | ||
277 | struct hlist_node *n; | ||
278 | unsigned int hash; | ||
279 | |||
280 | read_lock(&ip6_frags.lock); | ||
281 | hash = ip6qhashfn(id, src, dst); | ||
282 | hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) { | ||
283 | if (fq->id == id && | ||
284 | ipv6_addr_equal(src, &fq->saddr) && | ||
285 | ipv6_addr_equal(dst, &fq->daddr)) { | ||
286 | atomic_inc(&fq->q.refcnt); | ||
287 | read_unlock(&ip6_frags.lock); | ||
288 | return fq; | ||
289 | } | ||
290 | } | ||
291 | read_unlock(&ip6_frags.lock); | ||
292 | |||
293 | return ip6_frag_create(id, src, dst, idev, hash); | ||
294 | } | ||
295 | |||
296 | |||
297 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | 284 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, |
298 | struct frag_hdr *fhdr, int nhoff) | 285 | struct frag_hdr *fhdr, int nhoff) |
299 | { | 286 | { |
@@ -673,6 +660,7 @@ void __init ipv6_frag_init(void) | |||
673 | ip6_frags.destructor = ip6_frag_free; | 660 | ip6_frags.destructor = ip6_frag_free; |
674 | ip6_frags.skb_free = NULL; | 661 | ip6_frags.skb_free = NULL; |
675 | ip6_frags.qsize = sizeof(struct frag_queue); | 662 | ip6_frags.qsize = sizeof(struct frag_queue); |
663 | ip6_frags.match = ip6_frag_match; | ||
676 | ip6_frags.equal = ip6_frag_equal; | 664 | ip6_frags.equal = ip6_frag_equal; |
677 | ip6_frags.frag_expire = ip6_frag_expire; | 665 | ip6_frags.frag_expire = ip6_frag_expire; |
678 | inet_frags_init(&ip6_frags); | 666 | inet_frags_init(&ip6_frags); |