Blame view

net/ipv4/raw.c 24.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * INET		An implementation of the TCP/IP protocol suite for the LINUX
   *		operating system.  INET is implemented using the  BSD Socket
   *		interface as the means of communication with the user level.
   *
   *		RAW - implementation of IP "raw" sockets.
   *
02c30a84e   Jesper Juhl   [PATCH] update Ro...
8
   * Authors:	Ross Biro
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
   *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
   *
   * Fixes:
   *		Alan Cox	:	verify_area() fixed up
   *		Alan Cox	:	ICMP error handling
   *		Alan Cox	:	EMSGSIZE if you send too big a packet
   *		Alan Cox	: 	Now uses generic datagrams and shared
   *					skbuff library. No more peek crashes,
   *					no more backlogs
   *		Alan Cox	:	Checks sk->broadcast.
   *		Alan Cox	:	Uses skb_free_datagram/skb_copy_datagram
   *		Alan Cox	:	Raw passes ip options too
   *		Alan Cox	:	Setsocketopt added
   *		Alan Cox	:	Fixed error return for broadcasts
   *		Alan Cox	:	Removed wake_up calls
   *		Alan Cox	:	Use ttl/tos
   *		Alan Cox	:	Cleaned up old debugging
   *		Alan Cox	:	Use new kernel side addresses
   *	Arnt Gulbrandsen	:	Fixed MSG_DONTROUTE in raw sockets.
   *		Alan Cox	:	BSD style RAW socket demultiplexing.
   *		Alan Cox	:	Beginnings of mrouted support.
   *		Alan Cox	:	Added IP_HDRINCL option.
   *		Alan Cox	:	Skip broadcast check if BSDism set.
   *		David S. Miller	:	New socket lookup architecture.
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   */
bf0d52492   Dave Jones   [NET]: Remove unn...
39

715b49ef2   Alan Cox   [PATCH] EDAC: ato...
40
  #include <linux/types.h>
60063497a   Arun Sharma   atomic: use <linu...
41
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
  #include <asm/byteorder.h>
  #include <asm/current.h>
  #include <asm/uaccess.h>
  #include <asm/ioctls.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
  #include <linux/stddef.h>
  #include <linux/slab.h>
  #include <linux/errno.h>
  #include <linux/aio.h>
  #include <linux/kernel.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
51
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
  #include <linux/spinlock.h>
  #include <linux/sockios.h>
  #include <linux/socket.h>
  #include <linux/in.h>
  #include <linux/mroute.h>
  #include <linux/netdevice.h>
  #include <linux/in_route.h>
  #include <linux/route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  #include <linux/skbuff.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
61
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  #include <net/dst.h>
  #include <net/sock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
70
  #include <linux/ip.h>
  #include <linux/net.h>
  #include <net/ip.h>
  #include <net/icmp.h>
  #include <net/udp.h>
  #include <net/raw.h>
  #include <net/snmp.h>
c752f0739   Arnaldo Carvalho de Melo   [TCP]: Move the t...
71
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
79
  #include <net/inet_common.h>
  #include <net/checksum.h>
  #include <net/xfrm.h>
  #include <linux/rtnetlink.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv4.h>
709b46e8d   Eric W. Biederman   net: Add compat i...
80
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
82
  static struct raw_hashinfo raw_v4_hashinfo = {
938b93adb   Robert P. J. Day   [NET]: Add debugg...
83
  	.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
84
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85

fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
86
  void raw_hash_sk(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  {
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
88
  	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
65b4c50b4   Pavel Emelyanov   [RAW]: Consolidat...
89
  	struct hlist_head *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90

c720c7e83   Eric Dumazet   inet: rename some...
91
  	head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)];
65b4c50b4   Pavel Emelyanov   [RAW]: Consolidat...
92
93
  
  	write_lock_bh(&h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  	sk_add_node(sk, head);
c29a0bc4d   Pavel Emelyanov   [SOCK][NETNS]: Ad...
95
  	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
65b4c50b4   Pavel Emelyanov   [RAW]: Consolidat...
96
97
98
  	write_unlock_bh(&h->lock);
  }
  EXPORT_SYMBOL_GPL(raw_hash_sk);
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
99
  void raw_unhash_sk(struct sock *sk)
ab70768ec   Pavel Emelyanov   [RAW]: Consolidat...
100
  {
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
101
  	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
ab70768ec   Pavel Emelyanov   [RAW]: Consolidat...
102
103
  	write_lock_bh(&h->lock);
  	if (sk_del_node_init(sk))
c29a0bc4d   Pavel Emelyanov   [SOCK][NETNS]: Ad...
104
  		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
ab70768ec   Pavel Emelyanov   [RAW]: Consolidat...
105
106
107
  	write_unlock_bh(&h->lock);
  }
  EXPORT_SYMBOL_GPL(raw_unhash_sk);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
108
109
  static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
  		unsigned short num, __be32 raddr, __be32 laddr, int dif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
  {
  	struct hlist_node *node;
  
  	sk_for_each_from(sk, node) {
  		struct inet_sock *inet = inet_sk(sk);
c720c7e83   Eric Dumazet   inet: rename some...
115
116
117
  		if (net_eq(sock_net(sk), net) && inet->inet_num == num	&&
  		    !(inet->inet_daddr && inet->inet_daddr != raddr) 	&&
  		    !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  		    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
  			goto found; /* gotcha */
  	}
  	sk = NULL;
  found:
  	return sk;
  }
  
  /*
   *	0 - deliver
   *	1 - block
   */
  static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
  {
  	int type;
  
  	if (!pskb_may_pull(skb, sizeof(struct icmphdr)))
  		return 1;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
136
  	type = icmp_hdr(skb)->type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  	if (type < 32) {
  		__u32 data = raw_sk(sk)->filter.data;
  
  		return ((1 << type) & data) != 0;
  	}
  
  	/* Do not block unknown ICMP types */
  	return 0;
  }
  
  /* IP input processing comes here for RAW socket delivery.
   * Caller owns SKB, so we must make clones.
   *
   * RFC 1122: SHOULD pass TOS value up to the transport layer.
   * -> It does. And not only TOS, but all IP header.
   */
b71d1d426   Eric Dumazet   inet: constify ip...
153
  static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
  {
  	struct sock *sk;
  	struct hlist_head *head;
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
157
  	int delivered = 0;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
158
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
160
161
  	read_lock(&raw_v4_hashinfo.lock);
  	head = &raw_v4_hashinfo.ht[hash];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  	if (hlist_empty(head))
  		goto out;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
164

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
165
  	net = dev_net(skb->dev);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
166
  	sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
  			     iph->saddr, iph->daddr,
  			     skb->dev->ifindex);
  
  	while (sk) {
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
171
  		delivered = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
177
178
  		if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
  			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
  
  			/* Not releasing hash table! */
  			if (clone)
  				raw_rcv(sk, clone);
  		}
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
179
  		sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
  				     iph->saddr, iph->daddr,
  				     skb->dev->ifindex);
  	}
  out:
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
184
  	read_unlock(&raw_v4_hashinfo.lock);
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
185
  	return delivered;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  }
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
187
188
189
190
  int raw_local_deliver(struct sk_buff *skb, int protocol)
  {
  	int hash;
  	struct sock *raw_sk;
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
191
192
  	hash = protocol & (RAW_HTABLE_SIZE - 1);
  	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
193
194
195
196
197
198
199
200
201
202
203
204
  
  	/* 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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  {
  	struct inet_sock *inet = inet_sk(sk);
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
207
208
  	const int type = icmp_hdr(skb)->type;
  	const int code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  	int err = 0;
  	int harderr = 0;
  
  	/* Report error on raw socket, if:
  	   1. User requested ip_recverr.
  	   2. Socket is connected (otherwise the error indication
  	      is useless without ip_recverr and error is hard.
  	 */
  	if (!inet->recverr && sk->sk_state != TCP_ESTABLISHED)
  		return;
  
  	switch (type) {
  	default:
  	case ICMP_TIME_EXCEEDED:
  		err = EHOSTUNREACH;
  		break;
  	case ICMP_SOURCE_QUENCH:
  		return;
  	case ICMP_PARAMETERPROB:
  		err = EPROTO;
  		harderr = 1;
  		break;
  	case ICMP_DEST_UNREACH:
  		err = EHOSTUNREACH;
  		if (code > NR_ICMP_UNREACH)
  			break;
  		err = icmp_err_convert[code].errno;
  		harderr = icmp_err_convert[code].fatal;
  		if (code == ICMP_FRAG_NEEDED) {
  			harderr = inet->pmtudisc != IP_PMTUDISC_DONT;
  			err = EMSGSIZE;
  		}
  	}
  
  	if (inet->recverr) {
b71d1d426   Eric Dumazet   inet: constify ip...
244
  		const struct iphdr *iph = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
250
251
252
253
254
255
256
  		u8 *payload = skb->data + (iph->ihl << 2);
  
  		if (inet->hdrincl)
  			payload = skb->data;
  		ip_icmp_error(sk, skb, err, 0, info, payload);
  	}
  
  	if (inet->recverr || harderr) {
  		sk->sk_err = err;
  		sk->sk_error_report(sk);
  	}
  }
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
257
258
259
260
  void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
  {
  	int hash;
  	struct sock *raw_sk;
b71d1d426   Eric Dumazet   inet: constify ip...
261
  	const struct iphdr *iph;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
262
  	struct net *net;
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
263

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
264
  	hash = protocol & (RAW_HTABLE_SIZE - 1);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
265

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
266
267
  	read_lock(&raw_v4_hashinfo.lock);
  	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
268
  	if (raw_sk != NULL) {
b71d1d426   Eric Dumazet   inet: constify ip...
269
  		iph = (const struct iphdr *)skb->data;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
270
  		net = dev_net(skb->dev);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
271
272
273
  
  		while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol,
  						iph->daddr, iph->saddr,
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
274
275
276
  						skb->dev->ifindex)) != NULL) {
  			raw_err(raw_sk, skb, info);
  			raw_sk = sk_next(raw_sk);
b71d1d426   Eric Dumazet   inet: constify ip...
277
  			iph = (const struct iphdr *)skb->data;
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
278
279
  		}
  	}
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
280
  	read_unlock(&raw_v4_hashinfo.lock);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
281
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
  {
  	/* Charge it to the socket. */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
285

d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
286
287
  	ipv4_pktinfo_prepare(skb);
  	if (sock_queue_rcv_skb(sk, skb) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
293
294
295
296
297
  		kfree_skb(skb);
  		return NET_RX_DROP;
  	}
  
  	return NET_RX_SUCCESS;
  }
  
  int raw_rcv(struct sock *sk, struct sk_buff *skb)
  {
  	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
33c732c36   Wang Chen   [IPV4]: Add raw d...
298
  		atomic_inc(&sk->sk_drops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
  		kfree_skb(skb);
  		return NET_RX_DROP;
  	}
b59c27010   Patrick McHardy   [NETFILTER]: Keep...
302
  	nf_reset(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
304
  	skb_push(skb, skb->data - skb_network_header(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
  
  	raw_rcv_skb(sk, skb);
  	return 0;
  }
77968b782   David S. Miller   ipv4: Pass flow k...
309
310
311
312
  static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
  			   void *from, size_t length,
  			   struct rtable **rtp,
  			   unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
  {
  	struct inet_sock *inet = inet_sk(sk);
0388b0042   Pavel Emelyanov   icmp: add struct ...
315
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  	struct iphdr *iph;
  	struct sk_buff *skb;
f844c74fe   Herbert Xu   [IPV4] raw: Stren...
318
  	unsigned int iphlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	int err;
1789a640f   Eric Dumazet   raw: avoid two at...
320
  	struct rtable *rt = *rtp;
660882432   Herbert Xu   ipv4: Remove all ...
321
  	int hlen, tlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322

d8d1f30b9   Changli Gao   net-next: remove ...
323
  	if (length > rt->dst.dev->mtu) {
77968b782   David S. Miller   ipv4: Pass flow k...
324
  		ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
d8d1f30b9   Changli Gao   net-next: remove ...
325
  			       rt->dst.dev->mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
  		return -EMSGSIZE;
  	}
  	if (flags&MSG_PROBE)
  		goto out;
660882432   Herbert Xu   ipv4: Remove all ...
330
331
  	hlen = LL_RESERVED_SPACE(rt->dst.dev);
  	tlen = rt->dst.dev->needed_tailroom;
f5184d267   Johannes Berg   net: Allow netdev...
332
  	skb = sock_alloc_send_skb(sk,
660882432   Herbert Xu   ipv4: Remove all ...
333
  				  length + hlen + tlen + 15,
f5184d267   Johannes Berg   net: Allow netdev...
334
  				  flags & MSG_DONTWAIT, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  	if (skb == NULL)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
336
  		goto error;
660882432   Herbert Xu   ipv4: Remove all ...
337
  	skb_reserve(skb, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
340
  	skb->mark = sk->sk_mark;
d8d1f30b9   Changli Gao   net-next: remove ...
341
  	skb_dst_set(skb, &rt->dst);
1789a640f   Eric Dumazet   raw: avoid two at...
342
  	*rtp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343

7e28ecc28   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
344
  	skb_reset_network_header(skb);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
345
  	iph = ip_hdr(skb);
7e28ecc28   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
346
  	skb_put(skb, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  
  	skb->ip_summed = CHECKSUM_NONE;
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
349
  	skb->transport_header = skb->network_header;
55888dfb6   Neil Horman   AF_RAW: Augment r...
350
351
352
  	err = -EFAULT;
  	if (memcpy_fromiovecend((void *)iph, from, 0, length))
  		goto error_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353

f844c74fe   Herbert Xu   [IPV4] raw: Stren...
354
  	iphlen = iph->ihl * 4;
55888dfb6   Neil Horman   AF_RAW: Augment r...
355
356
357
358
359
360
361
362
363
364
365
366
367
  
  	/*
  	 * We don't want to modify the ip header, but we do need to
  	 * be sure that it won't cause problems later along the network
  	 * stack.  Specifically we want to make sure that iph->ihl is a
  	 * sane value.  If ihl points beyond the length of the buffer passed
  	 * in, reject the frame as invalid
  	 */
  	err = -EINVAL;
  	if (iphlen > length)
  		goto error_free;
  
  	if (iphlen >= sizeof(*iph)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  		if (!iph->saddr)
77968b782   David S. Miller   ipv4: Pass flow k...
369
  			iph->saddr = fl4->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
  		iph->check   = 0;
  		iph->tot_len = htons(length);
  		if (!iph->id)
d8d1f30b9   Changli Gao   net-next: remove ...
373
  			ip_select_ident(iph, &rt->dst, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
  
  		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
  	}
96793b482   David L Stevens   [IPV4]: Add ICMPM...
377
  	if (iph->protocol == IPPROTO_ICMP)
0388b0042   Pavel Emelyanov   icmp: add struct ...
378
  		icmp_out_count(net, ((struct icmphdr *)
96793b482   David L Stevens   [IPV4]: Add ICMPM...
379
  			skb_transport_header(skb))->type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380

9bbc768aa   Jan Engelhardt   netfilter: ipv4: ...
381
  	err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
d8d1f30b9   Changli Gao   net-next: remove ...
382
  		      rt->dst.dev, dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  	if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
384
  		err = net_xmit_errno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
  	if (err)
  		goto error;
  out:
  	return 0;
55888dfb6   Neil Horman   AF_RAW: Augment r...
389
  error_free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  	kfree_skb(skb);
  error:
5e38e2704   Pavel Emelyanov   mib: add net to I...
392
  	IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
393
394
  	if (err == -ENOBUFS && !inet->recverr)
  		err = 0;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
395
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
  }
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
397
  static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
  {
  	struct iovec *iov;
  	u8 __user *type = NULL;
  	u8 __user *code = NULL;
  	int probed = 0;
93765d8a4   Jesper Juhl   [IPV4]: [3/4] sig...
403
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  
  	if (!msg->msg_iov)
a27b58fed   Heiko Carstens   [NET]: fix uacces...
406
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
  
  	for (i = 0; i < msg->msg_iovlen; i++) {
  		iov = &msg->msg_iov[i];
  		if (!iov)
  			continue;
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
412
  		switch (fl4->flowi4_proto) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  		case IPPROTO_ICMP:
  			/* check if one-byte field is readable or not. */
  			if (iov->iov_base && iov->iov_len < 1)
  				break;
  
  			if (!type) {
  				type = iov->iov_base;
  				/* check if code field is readable or not. */
  				if (iov->iov_len > 1)
  					code = type + 1;
  			} else if (!code)
  				code = iov->iov_base;
  
  			if (type && code) {
9cce96df5   David S. Miller   net: Put fl4_* ma...
427
428
  				if (get_user(fl4->fl4_icmp_type, type) ||
  				    get_user(fl4->fl4_icmp_code, code))
a27b58fed   Heiko Carstens   [NET]: fix uacces...
429
  					return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
439
  				probed = 1;
  			}
  			break;
  		default:
  			probed = 1;
  			break;
  		}
  		if (probed)
  			break;
  	}
a27b58fed   Heiko Carstens   [NET]: fix uacces...
440
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
  }
  
  static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  		       size_t len)
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipcm_cookie ipc;
  	struct rtable *rt = NULL;
77968b782   David S. Miller   ipv4: Pass flow k...
449
  	struct flowi4 fl4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	int free = 0;
3ca3c68e7   Al Viro   [IPV4]: struct ip...
451
  	__be32 daddr;
c1d18f9fa   Al Viro   [IPV4]: struct ip...
452
  	__be32 saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  	u8  tos;
  	int err;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
455
  	struct ip_options_data opt_copy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  
  	err = -EMSGSIZE;
926d4b812   Jesper Juhl   [IPV4]: [2/4] sig...
458
  	if (len > 0xFFFF)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
467
  		goto out;
  
  	/*
  	 *	Check the flags.
  	 */
  
  	err = -EOPNOTSUPP;
  	if (msg->msg_flags & MSG_OOB)	/* Mirror BSD error message */
  		goto out;               /* compatibility */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
468

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  	/*
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
470
  	 *	Get and verify the address.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
  	 */
  
  	if (msg->msg_namelen) {
5a5f3a8db   Jianjun Kong   net: clean up net...
474
  		struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  		err = -EINVAL;
  		if (msg->msg_namelen < sizeof(*usin))
  			goto out;
  		if (usin->sin_family != AF_INET) {
  			static int complained;
  			if (!complained++)
  				printk(KERN_INFO "%s forgot to set AF_INET in "
  						 "raw sendmsg. Fix it!
  ",
  						 current->comm);
  			err = -EAFNOSUPPORT;
  			if (usin->sin_family)
  				goto out;
  		}
  		daddr = usin->sin_addr.s_addr;
  		/* ANK: I did not forget to get protocol from port field.
  		 * I just do not know, who uses this weirdness.
  		 * IP_HDRINCL is much more convenient.
  		 */
  	} else {
  		err = -EDESTADDRREQ;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
496
  		if (sk->sk_state != TCP_ESTABLISHED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  			goto out;
c720c7e83   Eric Dumazet   inet: rename some...
498
  		daddr = inet->inet_daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  	}
c720c7e83   Eric Dumazet   inet: rename some...
500
  	ipc.addr = inet->inet_saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  	ipc.opt = NULL;
2244d07bf   Oliver Hartkopp   net: simplify fla...
502
  	ipc.tx_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
  	ipc.oif = sk->sk_bound_dev_if;
  
  	if (msg->msg_controllen) {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
506
  		err = ip_cmsg_send(sock_net(sk), msg, &ipc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
512
513
514
  		if (err)
  			goto out;
  		if (ipc.opt)
  			free = 1;
  	}
  
  	saddr = ipc.addr;
  	ipc.addr = daddr;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
515
516
517
518
519
520
521
522
523
524
525
526
  	if (!ipc.opt) {
  		struct ip_options_rcu *inet_opt;
  
  		rcu_read_lock();
  		inet_opt = rcu_dereference(inet->inet_opt);
  		if (inet_opt) {
  			memcpy(&opt_copy, inet_opt,
  			       sizeof(*inet_opt) + inet_opt->opt.optlen);
  			ipc.opt = &opt_copy.opt;
  		}
  		rcu_read_unlock();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
531
532
533
534
  
  	if (ipc.opt) {
  		err = -EINVAL;
  		/* Linux does not mangle headers on raw sockets,
  		 * so that IP options + IP_HDRINCL is non-sense.
  		 */
  		if (inet->hdrincl)
  			goto done;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
535
  		if (ipc.opt->opt.srr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
  			if (!daddr)
  				goto done;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
538
  			daddr = ipc.opt->opt.faddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
  		}
  	}
  	tos = RT_CONN_FLAGS(sk);
  	if (msg->msg_flags & MSG_DONTROUTE)
  		tos |= RTO_ONLINK;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
544
  	if (ipv4_is_multicast(daddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
  		if (!ipc.oif)
  			ipc.oif = inet->mc_index;
  		if (!saddr)
  			saddr = inet->mc_addr;
  	}
77968b782   David S. Miller   ipv4: Pass flow k...
550
551
552
  	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
  			   RT_SCOPE_UNIVERSE,
  			   inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
47670b767   Julian Anastasov   ipv4: route non-l...
553
554
  			   inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
  			   daddr, saddr, 0, 0);
ef164ae35   David S. Miller   ipv4: Use flowi4_...
555

77968b782   David S. Miller   ipv4: Pass flow k...
556
557
558
  	if (!inet->hdrincl) {
  		err = raw_probe_proto_opt(&fl4, msg);
  		if (err)
b23dd4fe4   David S. Miller   ipv4: Make output...
559
  			goto done;
77968b782   David S. Miller   ipv4: Pass flow k...
560
561
562
563
564
565
566
567
  	}
  
  	security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
  	rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
  	if (IS_ERR(rt)) {
  		err = PTR_ERR(rt);
  		rt = NULL;
  		goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
572
573
574
575
576
577
578
  
  	err = -EACCES;
  	if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST))
  		goto done;
  
  	if (msg->msg_flags & MSG_CONFIRM)
  		goto do_confirm;
  back_from_confirm:
  
  	if (inet->hdrincl)
77968b782   David S. Miller   ipv4: Pass flow k...
579
580
  		err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len,
  				      &rt, msg->msg_flags);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
581

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
  	 else {
  		if (!ipc.addr)
77968b782   David S. Miller   ipv4: Pass flow k...
584
  			ipc.addr = fl4.daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  		lock_sock(sk);
f5fca6086   David S. Miller   ipv4: Pass flow k...
586
  		err = ip_append_data(sk, &fl4, ip_generic_getfrag,
77968b782   David S. Miller   ipv4: Pass flow k...
587
588
  				     msg->msg_iov, len, 0,
  				     &ipc, &rt, msg->msg_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
  		if (err)
  			ip_flush_pending_frames(sk);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
591
  		else if (!(msg->msg_flags & MSG_MORE)) {
77968b782   David S. Miller   ipv4: Pass flow k...
592
  			err = ip_push_pending_frames(sk, &fl4);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
593
594
595
  			if (err == -ENOBUFS && !inet->recverr)
  				err = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
599
600
601
  		release_sock(sk);
  	}
  done:
  	if (free)
  		kfree(ipc.opt);
  	ip_rt_put(rt);
5418c6926   Jesper Juhl   [IPV4]: [1/4] sig...
602
603
604
605
  out:
  	if (err < 0)
  		return err;
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  
  do_confirm:
d8d1f30b9   Changli Gao   net-next: remove ...
608
  	dst_confirm(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
611
612
613
614
615
616
  	if (!(msg->msg_flags & MSG_PROBE) || len)
  		goto back_from_confirm;
  	err = 0;
  	goto done;
  }
  
  static void raw_close(struct sock *sk, long timeout)
  {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
617
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
618
  	 * Raw sockets may have direct kernel references. Kill them.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
623
  	 */
  	ip_ra_control(sk, 0, NULL);
  
  	sk_common_release(sk);
  }
7d06b2e05   Brian Haley   net: change proto...
624
  static void raw_destroy(struct sock *sk)
22dd48502   Denis V. Lunev   raw: Raw socket l...
625
626
627
628
  {
  	lock_sock(sk);
  	ip_flush_pending_frames(sk);
  	release_sock(sk);
22dd48502   Denis V. Lunev   raw: Raw socket l...
629
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
635
636
637
638
639
  /* This gets rid of all the nasties in af_inet. -DaveM */
  static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
  	int ret = -EINVAL;
  	int chk_addr_ret;
  
  	if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
  		goto out;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
640
  	chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
  	ret = -EADDRNOTAVAIL;
  	if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
  	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
  		goto out;
c720c7e83   Eric Dumazet   inet: rename some...
645
  	inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
c720c7e83   Eric Dumazet   inet: rename some...
647
  		inet->inet_saddr = 0;  /* Use device */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  	sk_dst_reset(sk);
  	ret = 0;
  out:	return ret;
  }
  
  /*
   *	This should be easy, if there is something there
   *	we return it, otherwise we block.
   */
  
  static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  		       size_t len, int noblock, int flags, int *addr_len)
  {
  	struct inet_sock *inet = inet_sk(sk);
  	size_t copied = 0;
  	int err = -EOPNOTSUPP;
  	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
  	struct sk_buff *skb;
  
  	if (flags & MSG_OOB)
  		goto out;
  
  	if (addr_len)
  		*addr_len = sizeof(*sin);
  
  	if (flags & MSG_ERRQUEUE) {
  		err = ip_recv_error(sk, msg, len);
  		goto out;
  	}
  
  	skb = skb_recv_datagram(sk, flags, noblock, &err);
  	if (!skb)
  		goto out;
  
  	copied = skb->len;
  	if (len < copied) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
  
  	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
  	if (err)
  		goto done;
3b885787e   Neil Horman   net: Generalize s...
691
  	sock_recv_ts_and_drops(msg, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
  
  	/* Copy the address. */
  	if (sin) {
  		sin->sin_family = AF_INET;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
696
  		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
f59fc7f30   Tetsuo Handa   [IPV4/IPV6]: Sett...
697
  		sin->sin_port = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
  	}
  	if (inet->cmsg_flags)
  		ip_cmsg_recv(msg, skb);
  	if (flags & MSG_TRUNC)
  		copied = skb->len;
  done:
  	skb_free_datagram(sk, skb);
5418c6926   Jesper Juhl   [IPV4]: [1/4] sig...
706
707
708
709
  out:
  	if (err)
  		return err;
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
714
  }
  
  static int raw_init(struct sock *sk)
  {
  	struct raw_sock *rp = raw_sk(sk);
c720c7e83   Eric Dumazet   inet: rename some...
715
  	if (inet_sk(sk)->inet_num == IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  		memset(&rp->filter, 0, sizeof(rp->filter));
  	return 0;
  }
  
  static int raw_seticmpfilter(struct sock *sk, char __user *optval, int optlen)
  {
  	if (optlen > sizeof(struct icmp_filter))
  		optlen = sizeof(struct icmp_filter);
  	if (copy_from_user(&raw_sk(sk)->filter, optval, optlen))
  		return -EFAULT;
  	return 0;
  }
  
  static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *optlen)
  {
  	int len, ret = -EFAULT;
  
  	if (get_user(len, optlen))
  		goto out;
  	ret = -EINVAL;
  	if (len < 0)
  		goto out;
  	if (len > sizeof(struct icmp_filter))
  		len = sizeof(struct icmp_filter);
  	ret = -EFAULT;
  	if (put_user(len, optlen) ||
  	    copy_to_user(optval, &raw_sk(sk)->filter, len))
  		goto out;
  	ret = 0;
  out:	return ret;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
747
  static int do_raw_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
748
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  	if (optname == ICMP_FILTER) {
c720c7e83   Eric Dumazet   inet: rename some...
751
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
757
  			return -EOPNOTSUPP;
  		else
  			return raw_seticmpfilter(sk, optval, optlen);
  	}
  	return -ENOPROTOOPT;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
758
  static int raw_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
759
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  {
  	if (level != SOL_RAW)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
762
763
764
  		return ip_setsockopt(sk, level, optname, optval, optlen);
  	return do_raw_setsockopt(sk, level, optname, optval, optlen);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765

3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
766
767
  #ifdef CONFIG_COMPAT
  static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
768
  				 char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
769
770
  {
  	if (level != SOL_RAW)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
771
  		return compat_ip_setsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
772
773
774
775
776
777
778
  	return do_raw_setsockopt(sk, level, optname, optval, optlen);
  }
  #endif
  
  static int do_raw_getsockopt(struct sock *sk, int level, int optname,
  			  char __user *optval, int __user *optlen)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  	if (optname == ICMP_FILTER) {
c720c7e83   Eric Dumazet   inet: rename some...
780
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
786
  			return -EOPNOTSUPP;
  		else
  			return raw_geticmpfilter(sk, optval, optlen);
  	}
  	return -ENOPROTOOPT;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
787
788
789
790
791
792
793
794
795
796
  static int raw_getsockopt(struct sock *sk, int level, int optname,
  			  char __user *optval, int __user *optlen)
  {
  	if (level != SOL_RAW)
  		return ip_getsockopt(sk, level, optname, optval, optlen);
  	return do_raw_getsockopt(sk, level, optname, optval, optlen);
  }
  
  #ifdef CONFIG_COMPAT
  static int compat_raw_getsockopt(struct sock *sk, int level, int optname,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
797
  				 char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
798
799
  {
  	if (level != SOL_RAW)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
800
  		return compat_ip_getsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
801
802
803
  	return do_raw_getsockopt(sk, level, optname, optval, optlen);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
  static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
  	switch (cmd) {
4500ebf8d   Joe Perches   ipv4: Reduce swit...
807
808
  	case SIOCOUTQ: {
  		int amount = sk_wmem_alloc_get(sk);
31e6d363a   Eric Dumazet   net: correct off-...
809

4500ebf8d   Joe Perches   ipv4: Reduce swit...
810
811
812
813
814
815
816
817
818
819
820
821
822
  		return put_user(amount, (int __user *)arg);
  	}
  	case SIOCINQ: {
  		struct sk_buff *skb;
  		int amount = 0;
  
  		spin_lock_bh(&sk->sk_receive_queue.lock);
  		skb = skb_peek(&sk->sk_receive_queue);
  		if (skb != NULL)
  			amount = skb->len;
  		spin_unlock_bh(&sk->sk_receive_queue.lock);
  		return put_user(amount, (int __user *)arg);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823

4500ebf8d   Joe Perches   ipv4: Reduce swit...
824
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  #ifdef CONFIG_IP_MROUTE
4500ebf8d   Joe Perches   ipv4: Reduce swit...
826
  		return ipmr_ioctl(sk, cmd, (void __user *)arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  #else
4500ebf8d   Joe Perches   ipv4: Reduce swit...
828
  		return -ENOIOCTLCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
  #endif
  	}
  }
709b46e8d   Eric W. Biederman   net: Add compat i...
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
  #ifdef CONFIG_COMPAT
  static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
  {
  	switch (cmd) {
  	case SIOCOUTQ:
  	case SIOCINQ:
  		return -ENOIOCTLCMD;
  	default:
  #ifdef CONFIG_IP_MROUTE
  		return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg));
  #else
  		return -ENOIOCTLCMD;
  #endif
  	}
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  struct proto raw_prot = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
849
850
851
  	.name		   = "RAW",
  	.owner		   = THIS_MODULE,
  	.close		   = raw_close,
22dd48502   Denis V. Lunev   raw: Raw socket l...
852
  	.destroy	   = raw_destroy,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
853
854
855
856
857
858
859
860
861
862
  	.connect	   = ip4_datagram_connect,
  	.disconnect	   = udp_disconnect,
  	.ioctl		   = raw_ioctl,
  	.init		   = raw_init,
  	.setsockopt	   = raw_setsockopt,
  	.getsockopt	   = raw_getsockopt,
  	.sendmsg	   = raw_sendmsg,
  	.recvmsg	   = raw_recvmsg,
  	.bind		   = raw_bind,
  	.backlog_rcv	   = raw_rcv_skb,
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
863
864
  	.hash		   = raw_hash_sk,
  	.unhash		   = raw_unhash_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
865
  	.obj_size	   = sizeof(struct raw_sock),
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
866
  	.h.raw_hash	   = &raw_v4_hashinfo,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
867
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
868
869
  	.compat_setsockopt = compat_raw_setsockopt,
  	.compat_getsockopt = compat_raw_getsockopt,
709b46e8d   Eric W. Biederman   net: Add compat i...
870
  	.compat_ioctl	   = compat_raw_ioctl,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
871
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
  };
  
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
877
  static struct sock *raw_get_first(struct seq_file *seq)
  {
  	struct sock *sk;
5a5f3a8db   Jianjun Kong   net: clean up net...
878
  	struct raw_iter_state *state = raw_seq_private(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
880
881
  	for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE;
  			++state->bucket) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
  		struct hlist_node *node;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
883
  		sk_for_each(sk, node, &state->h->ht[state->bucket])
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
884
  			if (sock_net(sk) == seq_file_net(seq))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
891
892
893
  				goto found;
  	}
  	sk = NULL;
  found:
  	return sk;
  }
  
  static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
  {
5a5f3a8db   Jianjun Kong   net: clean up net...
894
  	struct raw_iter_state *state = raw_seq_private(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
  
  	do {
  		sk = sk_next(sk);
  try_again:
  		;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
900
  	} while (sk && sock_net(sk) != seq_file_net(seq));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
902
  	if (!sk && ++state->bucket < RAW_HTABLE_SIZE) {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
903
  		sk = sk_head(&state->h->ht[state->bucket]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
906
907
908
909
910
911
912
913
914
915
916
917
  		goto try_again;
  	}
  	return sk;
  }
  
  static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos)
  {
  	struct sock *sk = raw_get_first(seq);
  
  	if (sk)
  		while (pos && (sk = raw_get_next(seq, sk)) != NULL)
  			--pos;
  	return pos ? NULL : sk;
  }
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
918
  void *raw_seq_start(struct seq_file *seq, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
920
921
922
  	struct raw_iter_state *state = raw_seq_private(seq);
  
  	read_lock(&state->h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  	return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
  }
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
925
  EXPORT_SYMBOL_GPL(raw_seq_start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926

42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
927
  void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
932
933
934
935
936
937
  {
  	struct sock *sk;
  
  	if (v == SEQ_START_TOKEN)
  		sk = raw_get_first(seq);
  	else
  		sk = raw_get_next(seq, v);
  	++*pos;
  	return sk;
  }
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
938
  EXPORT_SYMBOL_GPL(raw_seq_next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939

42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
940
  void raw_seq_stop(struct seq_file *seq, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
942
943
944
  	struct raw_iter_state *state = raw_seq_private(seq);
  
  	read_unlock(&state->h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  }
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
946
  EXPORT_SYMBOL_GPL(raw_seq_stop);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
948
  static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
  {
  	struct inet_sock *inet = inet_sk(sp);
c720c7e83   Eric Dumazet   inet: rename some...
951
952
  	__be32 dest = inet->inet_daddr,
  	       src = inet->inet_rcv_saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
  	__u16 destp = 0,
c720c7e83   Eric Dumazet   inet: rename some...
954
  	      srcp  = inet->inet_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955

8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
956
  	seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
71338aa7d   Dan Rosenberg   net: convert %p u...
957
958
  		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d
  ",
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
959
  		i, src, srcp, dest, destp, sp->sk_state,
31e6d363a   Eric Dumazet   net: correct off-...
960
961
  		sk_wmem_alloc_get(sp),
  		sk_rmem_alloc_get(sp),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
  		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
33c732c36   Wang Chen   [IPV4]: Add raw d...
963
  		atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
966
967
  }
  
  static int raw_seq_show(struct seq_file *seq, void *v)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  	if (v == SEQ_START_TOKEN)
8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
969
970
  		seq_printf(seq, "  sl  local_address rem_address   st tx_queue "
  				"rx_queue tr tm->when retrnsmt   uid  timeout "
cb61cb9b8   Eric Dumazet   udp: sk_drops han...
971
972
  				"inode ref pointer drops
  ");
8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
973
974
  	else
  		raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
977
  static const struct seq_operations raw_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
979
980
981
982
  	.start = raw_seq_start,
  	.next  = raw_seq_next,
  	.stop  = raw_seq_stop,
  	.show  = raw_seq_show,
  };
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
983
984
  int raw_seq_open(struct inode *ino, struct file *file,
  		 struct raw_hashinfo *h, const struct seq_operations *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
  {
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
986
  	int err;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
987
  	struct raw_iter_state *i;
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
988
  	err = seq_open_net(ino, file, ops, sizeof(struct raw_iter_state));
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
989
990
  	if (err < 0)
  		return err;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
991

f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
992
  	i = raw_seq_private((struct seq_file *)file->private_data);
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
993
  	i->h = h;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
994
995
996
997
998
999
  	return 0;
  }
  EXPORT_SYMBOL_GPL(raw_seq_open);
  
  static int raw_v4_seq_open(struct inode *inode, struct file *file)
  {
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
1000
  	return raw_seq_open(inode, file, &raw_v4_hashinfo, &raw_seq_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
1002
  static const struct file_operations raw_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
  	.owner	 = THIS_MODULE,
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1004
  	.open	 = raw_v4_seq_open,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1007
  	.release = seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
  };
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1009
  static __net_init int raw_init_net(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  {
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1011
  	if (!proc_net_fops_create(net, "raw", S_IRUGO, &raw_seq_fops))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
  		return -ENOMEM;
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1013

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
  	return 0;
  }
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  static __net_exit void raw_exit_net(struct net *net)
  {
  	proc_net_remove(net, "raw");
  }
  
  static __net_initdata struct pernet_operations raw_net_ops = {
  	.init = raw_init_net,
  	.exit = raw_exit_net,
  };
  
  int __init raw_proc_init(void)
  {
  	return register_pernet_subsys(&raw_net_ops);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
  void __init raw_proc_exit(void)
  {
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1032
  	unregister_pernet_subsys(&raw_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
  }
  #endif /* CONFIG_PROC_FS */