aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/raw.h19
-rw-r--r--net/ipv4/icmp.c15
-rw-r--r--net/ipv4/ip_input.c16
-rw-r--r--net/ipv4/raw.c53
4 files changed, 56 insertions, 47 deletions
diff --git a/include/net/raw.h b/include/net/raw.h
index e4af5978194..7fc3c770f17 100644
--- a/include/net/raw.h
+++ b/include/net/raw.h
@@ -22,23 +22,10 @@
22 22
23extern struct proto raw_prot; 23extern struct proto raw_prot;
24 24
25extern void raw_err(struct sock *, struct sk_buff *, u32 info); 25void raw_icmp_error(struct sk_buff *, int, u32);
26extern int raw_rcv(struct sock *, struct sk_buff *); 26int raw_local_deliver(struct sk_buff *, int);
27
28/* Note: v4 ICMP wants to get at this stuff, if you change the
29 * hashing mechanism, make sure you update icmp.c as well.
30 */
31#define RAWV4_HTABLE_SIZE MAX_INET_PROTOS
32extern struct hlist_head raw_v4_htable[RAWV4_HTABLE_SIZE];
33
34extern rwlock_t raw_v4_lock;
35 27
36 28extern int raw_rcv(struct sock *, struct sk_buff *);
37extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
38 __be32 raddr, __be32 laddr,
39 int dif);
40
41extern int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
42 29
43#ifdef CONFIG_PROC_FS 30#ifdef CONFIG_PROC_FS
44extern int raw_proc_init(void); 31extern int raw_proc_init(void);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 82baea02648..13d74598d3e 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -603,7 +603,6 @@ static void icmp_unreach(struct sk_buff *skb)
603 struct icmphdr *icmph; 603 struct icmphdr *icmph;
604 int hash, protocol; 604 int hash, protocol;
605 struct net_protocol *ipprot; 605 struct net_protocol *ipprot;
606 struct sock *raw_sk;
607 u32 info = 0; 606 u32 info = 0;
608 607
609 /* 608 /*
@@ -697,21 +696,9 @@ static void icmp_unreach(struct sk_buff *skb)
697 /* 696 /*
698 * Deliver ICMP message to raw sockets. Pretty useless feature? 697 * Deliver ICMP message to raw sockets. Pretty useless feature?
699 */ 698 */
699 raw_icmp_error(skb, protocol, info);
700 700
701 /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
702 hash = protocol & (MAX_INET_PROTOS - 1); 701 hash = protocol & (MAX_INET_PROTOS - 1);
703 read_lock(&raw_v4_lock);
704 if ((raw_sk = sk_head(&raw_v4_htable[hash])) != NULL) {
705 while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr,
706 iph->saddr,
707 skb->dev->ifindex)) != NULL) {
708 raw_err(raw_sk, skb, info);
709 raw_sk = sk_next(raw_sk);
710 iph = (struct iphdr *)skb->data;
711 }
712 }
713 read_unlock(&raw_v4_lock);
714
715 rcu_read_lock(); 702 rcu_read_lock();
716 ipprot = rcu_dereference(inet_protos[hash]); 703 ipprot = rcu_dereference(inet_protos[hash]);
717 if (ipprot && ipprot->err_handler) 704 if (ipprot && ipprot->err_handler)
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 4068e178d74..65631391d47 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -204,22 +204,14 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
204 204
205 rcu_read_lock(); 205 rcu_read_lock();
206 { 206 {
207 /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
208 int protocol = ip_hdr(skb)->protocol; 207 int protocol = ip_hdr(skb)->protocol;
209 int hash; 208 int hash, raw;
210 struct sock *raw_sk;
211 struct net_protocol *ipprot; 209 struct net_protocol *ipprot;
212 210
213 resubmit: 211 resubmit:
214 hash = protocol & (MAX_INET_PROTOS - 1); 212 raw = raw_local_deliver(skb, protocol);
215 raw_sk = sk_head(&raw_v4_htable[hash]);
216
217 /* If there maybe a raw socket we must check - if not we
218 * don't care less
219 */
220 if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
221 raw_sk = NULL;
222 213
214 hash = protocol & (MAX_INET_PROTOS - 1);
223 if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { 215 if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
224 int ret; 216 int ret;
225 217
@@ -237,7 +229,7 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
237 } 229 }
238 IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); 230 IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
239 } else { 231 } else {
240 if (!raw_sk) { 232 if (!raw) {
241 if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 233 if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
242 IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); 234 IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS);
243 icmp_send(skb, ICMP_DEST_UNREACH, 235 icmp_send(skb, ICMP_DEST_UNREACH,
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index b80987d2fc5..8a506618b91 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -80,8 +80,10 @@
80#include <linux/netfilter.h> 80#include <linux/netfilter.h>
81#include <linux/netfilter_ipv4.h> 81#include <linux/netfilter_ipv4.h>
82 82
83struct hlist_head raw_v4_htable[RAWV4_HTABLE_SIZE]; 83#define RAWV4_HTABLE_SIZE MAX_INET_PROTOS
84DEFINE_RWLOCK(raw_v4_lock); 84
85static struct hlist_head raw_v4_htable[RAWV4_HTABLE_SIZE];
86static DEFINE_RWLOCK(raw_v4_lock);
85 87
86static void raw_v4_hash(struct sock *sk) 88static void raw_v4_hash(struct sock *sk)
87{ 89{
@@ -102,7 +104,7 @@ static void raw_v4_unhash(struct sock *sk)
102 write_unlock_bh(&raw_v4_lock); 104 write_unlock_bh(&raw_v4_lock);
103} 105}
104 106
105struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, 107static struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
106 __be32 raddr, __be32 laddr, 108 __be32 raddr, __be32 laddr,
107 int dif) 109 int dif)
108{ 110{
@@ -150,7 +152,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
150 * RFC 1122: SHOULD pass TOS value up to the transport layer. 152 * RFC 1122: SHOULD pass TOS value up to the transport layer.
151 * -> It does. And not only TOS, but all IP header. 153 * -> It does. And not only TOS, but all IP header.
152 */ 154 */
153int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) 155static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
154{ 156{
155 struct sock *sk; 157 struct sock *sk;
156 struct hlist_head *head; 158 struct hlist_head *head;
@@ -182,7 +184,25 @@ out:
182 return delivered; 184 return delivered;
183} 185}
184 186
185void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) 187int raw_local_deliver(struct sk_buff *skb, int protocol)
188{
189 int hash;
190 struct sock *raw_sk;
191
192 hash = protocol & (RAWV4_HTABLE_SIZE - 1);
193 raw_sk = sk_head(&raw_v4_htable[hash]);
194
195 /* If there maybe a raw socket we must check - if not we
196 * don't care less
197 */
198 if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
199 raw_sk = NULL;
200
201 return raw_sk != NULL;
202
203}
204
205static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
186{ 206{
187 struct inet_sock *inet = inet_sk(sk); 207 struct inet_sock *inet = inet_sk(sk);
188 const int type = icmp_hdr(skb)->type; 208 const int type = icmp_hdr(skb)->type;
@@ -236,6 +256,29 @@ void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
236 } 256 }
237} 257}
238 258
259void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
260{
261 int hash;
262 struct sock *raw_sk;
263 struct iphdr *iph;
264
265 hash = protocol & (RAWV4_HTABLE_SIZE - 1);
266
267 read_lock(&raw_v4_lock);
268 raw_sk = sk_head(&raw_v4_htable[hash]);
269 if (raw_sk != NULL) {
270 iph = (struct iphdr *)skb->data;
271 while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr,
272 iph->saddr,
273 skb->dev->ifindex)) != NULL) {
274 raw_err(raw_sk, skb, info);
275 raw_sk = sk_next(raw_sk);
276 iph = (struct iphdr *)skb->data;
277 }
278 }
279 read_unlock(&raw_v4_lock);
280}
281
239static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb) 282static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
240{ 283{
241 /* Charge it to the socket. */ 284 /* Charge it to the socket. */