Commit 7bc54c90 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by David S. Miller

[IPv4] RAW: Compact the API for the kernel

The raw sockets functions are explicitly used from
inside the kernel in two places:

1. in ip_local_deliver_finish to intercept skb-s
2. in icmp_error

For this purposes many functions and even data structures,
that are naturally internal for raw protocol, are exported.

Compact the API to two functions and hide all the other
(including hash table and rwlock) inside the net/ipv4/raw.c
Signed-off-by: default avatarPavel Emelyanov <xemul@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e372c414
...@@ -22,23 +22,10 @@ ...@@ -22,23 +22,10 @@
extern struct proto raw_prot; extern struct proto raw_prot;
extern void raw_err(struct sock *, struct sk_buff *, u32 info); void raw_icmp_error(struct sk_buff *, int, u32);
extern int raw_rcv(struct sock *, struct sk_buff *); int raw_local_deliver(struct sk_buff *, int);
/* Note: v4 ICMP wants to get at this stuff, if you change the
* hashing mechanism, make sure you update icmp.c as well.
*/
#define RAWV4_HTABLE_SIZE MAX_INET_PROTOS
extern struct hlist_head raw_v4_htable[RAWV4_HTABLE_SIZE];
extern rwlock_t raw_v4_lock;
extern int raw_rcv(struct sock *, struct sk_buff *);
extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
__be32 raddr, __be32 laddr,
int dif);
extern int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern int raw_proc_init(void); extern int raw_proc_init(void);
......
...@@ -603,7 +603,6 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -603,7 +603,6 @@ static void icmp_unreach(struct sk_buff *skb)
struct icmphdr *icmph; struct icmphdr *icmph;
int hash, protocol; int hash, protocol;
struct net_protocol *ipprot; struct net_protocol *ipprot;
struct sock *raw_sk;
u32 info = 0; u32 info = 0;
/* /*
...@@ -697,21 +696,9 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -697,21 +696,9 @@ static void icmp_unreach(struct sk_buff *skb)
/* /*
* Deliver ICMP message to raw sockets. Pretty useless feature? * Deliver ICMP message to raw sockets. Pretty useless feature?
*/ */
raw_icmp_error(skb, protocol, info);
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
hash = protocol & (MAX_INET_PROTOS - 1); hash = protocol & (MAX_INET_PROTOS - 1);
read_lock(&raw_v4_lock);
if ((raw_sk = sk_head(&raw_v4_htable[hash])) != NULL) {
while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr,
iph->saddr,
skb->dev->ifindex)) != NULL) {
raw_err(raw_sk, skb, info);
raw_sk = sk_next(raw_sk);
iph = (struct iphdr *)skb->data;
}
}
read_unlock(&raw_v4_lock);
rcu_read_lock(); rcu_read_lock();
ipprot = rcu_dereference(inet_protos[hash]); ipprot = rcu_dereference(inet_protos[hash]);
if (ipprot && ipprot->err_handler) if (ipprot && ipprot->err_handler)
......
...@@ -204,22 +204,14 @@ static int ip_local_deliver_finish(struct sk_buff *skb) ...@@ -204,22 +204,14 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
rcu_read_lock(); rcu_read_lock();
{ {
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
int protocol = ip_hdr(skb)->protocol; int protocol = ip_hdr(skb)->protocol;
int hash; int hash, raw;
struct sock *raw_sk;
struct net_protocol *ipprot; struct net_protocol *ipprot;
resubmit: resubmit:
hash = protocol & (MAX_INET_PROTOS - 1); raw = raw_local_deliver(skb, protocol);
raw_sk = sk_head(&raw_v4_htable[hash]);
/* If there maybe a raw socket we must check - if not we
* don't care less
*/
if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
raw_sk = NULL;
hash = protocol & (MAX_INET_PROTOS - 1);
if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
int ret; int ret;
...@@ -237,7 +229,7 @@ static int ip_local_deliver_finish(struct sk_buff *skb) ...@@ -237,7 +229,7 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
} }
IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
} else { } else {
if (!raw_sk) { if (!raw) {
if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS);
icmp_send(skb, ICMP_DEST_UNREACH, icmp_send(skb, ICMP_DEST_UNREACH,
......
...@@ -80,8 +80,10 @@ ...@@ -80,8 +80,10 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
struct hlist_head raw_v4_htable[RAWV4_HTABLE_SIZE]; #define RAWV4_HTABLE_SIZE MAX_INET_PROTOS
DEFINE_RWLOCK(raw_v4_lock);
static struct hlist_head raw_v4_htable[RAWV4_HTABLE_SIZE];
static DEFINE_RWLOCK(raw_v4_lock);
static void raw_v4_hash(struct sock *sk) static void raw_v4_hash(struct sock *sk)
{ {
...@@ -102,7 +104,7 @@ static void raw_v4_unhash(struct sock *sk) ...@@ -102,7 +104,7 @@ static void raw_v4_unhash(struct sock *sk)
write_unlock_bh(&raw_v4_lock); write_unlock_bh(&raw_v4_lock);
} }
struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, static struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
__be32 raddr, __be32 laddr, __be32 raddr, __be32 laddr,
int dif) int dif)
{ {
...@@ -150,7 +152,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) ...@@ -150,7 +152,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
* RFC 1122: SHOULD pass TOS value up to the transport layer. * RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> It does. And not only TOS, but all IP header. * -> It does. And not only TOS, but all IP header.
*/ */
int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
{ {
struct sock *sk; struct sock *sk;
struct hlist_head *head; struct hlist_head *head;
...@@ -182,7 +184,25 @@ int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) ...@@ -182,7 +184,25 @@ int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
return delivered; return delivered;
} }
void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) int raw_local_deliver(struct sk_buff *skb, int protocol)
{
int hash;
struct sock *raw_sk;
hash = protocol & (RAWV4_HTABLE_SIZE - 1);
raw_sk = sk_head(&raw_v4_htable[hash]);
/* If there maybe a raw socket we must check - if not we
* don't care less
*/
if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
raw_sk = NULL;
return raw_sk != NULL;
}
static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
{ {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
const int type = icmp_hdr(skb)->type; const int type = icmp_hdr(skb)->type;
...@@ -236,6 +256,29 @@ void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) ...@@ -236,6 +256,29 @@ void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
} }
} }
void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
{
int hash;
struct sock *raw_sk;
struct iphdr *iph;
hash = protocol & (RAWV4_HTABLE_SIZE - 1);
read_lock(&raw_v4_lock);
raw_sk = sk_head(&raw_v4_htable[hash]);
if (raw_sk != NULL) {
iph = (struct iphdr *)skb->data;
while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr,
iph->saddr,
skb->dev->ifindex)) != NULL) {
raw_err(raw_sk, skb, info);
raw_sk = sk_next(raw_sk);
iph = (struct iphdr *)skb->data;
}
}
read_unlock(&raw_v4_lock);
}
static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb) static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
{ {
/* Charge it to the socket. */ /* Charge it to the socket. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment