summaryrefslogtreecommitdiffstats
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 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) &&