aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/raw.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r--net/ipv6/raw.c52
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
63struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; 63#define RAWV6_HTABLE_SIZE MAX_INET_PROTOS
64DEFINE_RWLOCK(raw_v6_lock); 64
65static struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
66static DEFINE_RWLOCK(raw_v6_lock);
65 67
66static void raw_v6_hash(struct sock *sk) 68static 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... */ 88static struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
87struct 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 */
170int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) 170static 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
245int 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 */
246static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) 257static 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
319void rawv6_err(struct sock *sk, struct sk_buff *skb, 330static 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
364void 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
353static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) 389static 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) &&