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 ad622cc11bd..53f01b4982c 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -60,8 +60,10 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> -struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; -DEFINE_RWLOCK(raw_v6_lock); +#define RAWV6_HTABLE_SIZE MAX_INET_PROTOS + +static struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; +static DEFINE_RWLOCK(raw_v6_lock); static void raw_v6_hash(struct sock *sk) { @@ -83,10 +85,8 @@ static void raw_v6_unhash(struct sock *sk) } -/* Grumble... icmp and ip_input want to get at this... */ -struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, - struct in6_addr *loc_addr, struct in6_addr *rmt_addr, - int dif) +static struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, + struct in6_addr *loc_addr, struct in6_addr *rmt_addr, int dif) { struct hlist_node *node; int is_multicast = ipv6_addr_is_multicast(loc_addr); @@ -167,7 +167,7 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); * * Caller owns SKB so we must make clones. */ -int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) +static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { struct in6_addr *saddr; struct in6_addr *daddr; @@ -242,6 +242,17 @@ out: return delivered; } +int raw6_local_deliver(struct sk_buff *skb, int nexthdr) +{ + struct sock *raw_sk; + + raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]); + if (raw_sk && !ipv6_raw_deliver(skb, nexthdr)) + raw_sk = NULL; + + return raw_sk != NULL; +} + /* This cleans up af_inet6 a bit. -DaveM */ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -316,7 +327,7 @@ out: return err; } -void rawv6_err(struct sock *sk, struct sk_buff *skb, +static void rawv6_err(struct sock *sk, struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { @@ -350,6 +361,31 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb, } } +void raw6_icmp_error(struct sk_buff *skb, int nexthdr, + int type, int code, int inner_offset, __be32 info) +{ + struct sock *sk; + int hash; + struct in6_addr *saddr, *daddr; + + hash = nexthdr & (RAWV6_HTABLE_SIZE - 1); + + read_lock(&raw_v6_lock); + sk = sk_head(&raw_v6_htable[hash]); + if (sk != NULL) { + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + + while ((sk = __raw_v6_lookup(sk, nexthdr, saddr, daddr, + IP6CB(skb)->iif))) { + rawv6_err(sk, skb, NULL, type, code, + inner_offset, info); + sk = sk_next(sk); + } + } + read_unlock(&raw_v6_lock); +} + static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) { if ((raw6_sk(sk)->checksum || sk->sk_filter) && |