diff options
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r-- | net/ipv6/raw.c | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ad622cc11bda..53f01b4982c7 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -60,8 +60,10 @@ | |||
60 | #include <linux/proc_fs.h> | 60 | #include <linux/proc_fs.h> |
61 | #include <linux/seq_file.h> | 61 | #include <linux/seq_file.h> |
62 | 62 | ||
63 | struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; | 63 | #define RAWV6_HTABLE_SIZE MAX_INET_PROTOS |
64 | DEFINE_RWLOCK(raw_v6_lock); | 64 | |
65 | static struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; | ||
66 | static DEFINE_RWLOCK(raw_v6_lock); | ||
65 | 67 | ||
66 | static void raw_v6_hash(struct sock *sk) | 68 | static void raw_v6_hash(struct sock *sk) |
67 | { | 69 | { |
@@ -83,10 +85,8 @@ static void raw_v6_unhash(struct sock *sk) | |||
83 | } | 85 | } |
84 | 86 | ||
85 | 87 | ||
86 | /* Grumble... icmp and ip_input want to get at this... */ | 88 | static struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, |
87 | struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, | 89 | struct in6_addr *loc_addr, struct in6_addr *rmt_addr, int dif) |
88 | struct in6_addr *loc_addr, struct in6_addr *rmt_addr, | ||
89 | int dif) | ||
90 | { | 90 | { |
91 | struct hlist_node *node; | 91 | struct hlist_node *node; |
92 | int is_multicast = ipv6_addr_is_multicast(loc_addr); | 92 | int is_multicast = ipv6_addr_is_multicast(loc_addr); |
@@ -167,7 +167,7 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); | |||
167 | * | 167 | * |
168 | * Caller owns SKB so we must make clones. | 168 | * Caller owns SKB so we must make clones. |
169 | */ | 169 | */ |
170 | int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | 170 | static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) |
171 | { | 171 | { |
172 | struct in6_addr *saddr; | 172 | struct in6_addr *saddr; |
173 | struct in6_addr *daddr; | 173 | struct in6_addr *daddr; |
@@ -242,6 +242,17 @@ out: | |||
242 | return delivered; | 242 | return delivered; |
243 | } | 243 | } |
244 | 244 | ||
245 | int raw6_local_deliver(struct sk_buff *skb, int nexthdr) | ||
246 | { | ||
247 | struct sock *raw_sk; | ||
248 | |||
249 | raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]); | ||
250 | if (raw_sk && !ipv6_raw_deliver(skb, nexthdr)) | ||
251 | raw_sk = NULL; | ||
252 | |||
253 | return raw_sk != NULL; | ||
254 | } | ||
255 | |||
245 | /* This cleans up af_inet6 a bit. -DaveM */ | 256 | /* This cleans up af_inet6 a bit. -DaveM */ |
246 | static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 257 | static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
247 | { | 258 | { |
@@ -316,7 +327,7 @@ out: | |||
316 | return err; | 327 | return err; |
317 | } | 328 | } |
318 | 329 | ||
319 | void rawv6_err(struct sock *sk, struct sk_buff *skb, | 330 | static void rawv6_err(struct sock *sk, struct sk_buff *skb, |
320 | struct inet6_skb_parm *opt, | 331 | struct inet6_skb_parm *opt, |
321 | int type, int code, int offset, __be32 info) | 332 | int type, int code, int offset, __be32 info) |
322 | { | 333 | { |
@@ -350,6 +361,31 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb, | |||
350 | } | 361 | } |
351 | } | 362 | } |
352 | 363 | ||
364 | void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | ||
365 | int type, int code, int inner_offset, __be32 info) | ||
366 | { | ||
367 | struct sock *sk; | ||
368 | int hash; | ||
369 | struct in6_addr *saddr, *daddr; | ||
370 | |||
371 | hash = nexthdr & (RAWV6_HTABLE_SIZE - 1); | ||
372 | |||
373 | read_lock(&raw_v6_lock); | ||
374 | sk = sk_head(&raw_v6_htable[hash]); | ||
375 | if (sk != NULL) { | ||
376 | saddr = &ipv6_hdr(skb)->saddr; | ||
377 | daddr = &ipv6_hdr(skb)->daddr; | ||
378 | |||
379 | while ((sk = __raw_v6_lookup(sk, nexthdr, saddr, daddr, | ||
380 | IP6CB(skb)->iif))) { | ||
381 | rawv6_err(sk, skb, NULL, type, code, | ||
382 | inner_offset, info); | ||
383 | sk = sk_next(sk); | ||
384 | } | ||
385 | } | ||
386 | read_unlock(&raw_v6_lock); | ||
387 | } | ||
388 | |||
353 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | 389 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) |
354 | { | 390 | { |
355 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && | 391 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && |