Blame view

net/ipv4/raw.c 25.4 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>
f5220d639   Quentin Armitage   ipv4: Make IP_MUL...
61
  #include <linux/igmp.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
62
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  #include <net/dst.h>
  #include <net/sock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
  #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...
72
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
  #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...
81
  #include <linux/compat.h>
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
82
83
84
  #include <linux/uio.h>
  
  struct raw_frag_vec {
b61e9dcc5   Al Viro   raw.c: stick msgh...
85
  	struct msghdr *msg;
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
86
87
88
89
90
91
  	union {
  		struct icmphdr icmph;
  		char c[1];
  	} hdr;
  	int hlen;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

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

fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
97
  void raw_hash_sk(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  {
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
99
  	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
65b4c50b4   Pavel Emelyanov   [RAW]: Consolidat...
100
  	struct hlist_head *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

c720c7e83   Eric Dumazet   inet: rename some...
102
  	head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)];
65b4c50b4   Pavel Emelyanov   [RAW]: Consolidat...
103
104
  
  	write_lock_bh(&h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	sk_add_node(sk, head);
c29a0bc4d   Pavel Emelyanov   [SOCK][NETNS]: Ad...
106
  	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
65b4c50b4   Pavel Emelyanov   [RAW]: Consolidat...
107
108
109
  	write_unlock_bh(&h->lock);
  }
  EXPORT_SYMBOL_GPL(raw_hash_sk);
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
110
  void raw_unhash_sk(struct sock *sk)
ab70768ec   Pavel Emelyanov   [RAW]: Consolidat...
111
  {
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
112
  	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
ab70768ec   Pavel Emelyanov   [RAW]: Consolidat...
113
114
  	write_lock_bh(&h->lock);
  	if (sk_del_node_init(sk))
c29a0bc4d   Pavel Emelyanov   [SOCK][NETNS]: Ad...
115
  		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
ab70768ec   Pavel Emelyanov   [RAW]: Consolidat...
116
117
118
  	write_unlock_bh(&h->lock);
  }
  EXPORT_SYMBOL_GPL(raw_unhash_sk);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
119
120
  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
121
  {
b67bfe0d4   Sasha Levin   hlist: drop the n...
122
  	sk_for_each_from(sk) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  		struct inet_sock *inet = inet_sk(sk);
c720c7e83   Eric Dumazet   inet: rename some...
124
125
126
  		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
127
128
129
130
131
132
133
134
135
136
137
138
  		    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
  			goto found; /* gotcha */
  	}
  	sk = NULL;
  found:
  	return sk;
  }
  
  /*
   *	0 - deliver
   *	1 - block
   */
ab43ed8b7   Eric Dumazet   ipv4: raw: fix ic...
139
  static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  {
ab43ed8b7   Eric Dumazet   ipv4: raw: fix ic...
141
142
  	struct icmphdr _hdr;
  	const struct icmphdr *hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

ab43ed8b7   Eric Dumazet   ipv4: raw: fix ic...
144
145
146
  	hdr = skb_header_pointer(skb, skb_transport_offset(skb),
  				 sizeof(_hdr), &_hdr);
  	if (!hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  		return 1;
ab43ed8b7   Eric Dumazet   ipv4: raw: fix ic...
148
  	if (hdr->type < 32) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  		__u32 data = raw_sk(sk)->filter.data;
ab43ed8b7   Eric Dumazet   ipv4: raw: fix ic...
150
  		return ((1U << hdr->type) & data) != 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
156
157
158
159
160
161
162
  	}
  
  	/* 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...
163
  static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
  {
  	struct sock *sk;
  	struct hlist_head *head;
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
167
  	int delivered = 0;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
168
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
170
171
  	read_lock(&raw_v4_hashinfo.lock);
  	head = &raw_v4_hashinfo.ht[hash];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
  	if (hlist_empty(head))
  		goto out;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
174

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
175
  	net = dev_net(skb->dev);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
176
  	sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
  			     iph->saddr, iph->daddr,
  			     skb->dev->ifindex);
  
  	while (sk) {
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
181
  		delivered = 1;
f5220d639   Quentin Armitage   ipv4: Make IP_MUL...
182
183
184
  		if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) &&
  		    ip_mc_sf_allow(sk, iph->daddr, iph->saddr,
  				   skb->dev->ifindex)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
  			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...
191
  		sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
  				     iph->saddr, iph->daddr,
  				     skb->dev->ifindex);
  	}
  out:
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
196
  	read_unlock(&raw_v4_hashinfo.lock);
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
197
  	return delivered;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  }
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
199
200
201
202
  int raw_local_deliver(struct sk_buff *skb, int protocol)
  {
  	int hash;
  	struct sock *raw_sk;
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
203
204
  	hash = protocol & (RAW_HTABLE_SIZE - 1);
  	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
205
206
207
208
209
210
211
212
213
214
215
216
  
  	/* 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
217
218
  {
  	struct inet_sock *inet = inet_sk(sk);
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
219
220
  	const int type = icmp_hdr(skb)->type;
  	const int code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
  	int err = 0;
  	int harderr = 0;
363933955   David S. Miller   ipv4: Handle PMTU...
223
224
  	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
  		ipv4_sk_update_pmtu(skb, sk, info);
8d65b1190   Duan Jiong   net: raw: do not ...
225
  	else if (type == ICMP_REDIRECT) {
55be7a9c6   David S. Miller   ipv4: Add redirec...
226
  		ipv4_sk_redirect(skb, sk);
8d65b1190   Duan Jiong   net: raw: do not ...
227
228
  		return;
  	}
363933955   David S. Miller   ipv4: Handle PMTU...
229

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  	/* 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...
262
  		const struct iphdr *iph = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
270
271
272
273
274
  		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...
275
276
277
278
  void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
  {
  	int hash;
  	struct sock *raw_sk;
b71d1d426   Eric Dumazet   inet: constify ip...
279
  	const struct iphdr *iph;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
280
  	struct net *net;
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
281

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

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
284
285
  	read_lock(&raw_v4_hashinfo.lock);
  	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
286
  	if (raw_sk != NULL) {
b71d1d426   Eric Dumazet   inet: constify ip...
287
  		iph = (const struct iphdr *)skb->data;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
288
  		net = dev_net(skb->dev);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
289
290
291
  
  		while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol,
  						iph->daddr, iph->saddr,
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
292
293
294
  						skb->dev->ifindex)) != NULL) {
  			raw_err(raw_sk, skb, info);
  			raw_sk = sk_next(raw_sk);
b71d1d426   Eric Dumazet   inet: constify ip...
295
  			iph = (const struct iphdr *)skb->data;
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
296
297
  		}
  	}
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
298
  	read_unlock(&raw_v4_hashinfo.lock);
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
299
  }
5e73ea1a3   Daniel Baluta   ipv4: fix checkpa...
300
  static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
  {
  	/* Charge it to the socket. */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
303

fbf8866d6   Shawn Bohrer   net: ipv4 only po...
304
  	ipv4_pktinfo_prepare(sk, skb);
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
305
  	if (sock_queue_rcv_skb(sk, skb) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
  		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...
316
  		atomic_inc(&sk->sk_drops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
  		kfree_skb(skb);
  		return NET_RX_DROP;
  	}
b59c27010   Patrick McHardy   [NETFILTER]: Keep...
320
  	nf_reset(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321

d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
322
  	skb_push(skb, skb->data - skb_network_header(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
  
  	raw_rcv_skb(sk, skb);
  	return 0;
  }
77968b782   David S. Miller   ipv4: Pass flow k...
327
328
329
330
  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
331
332
  {
  	struct inet_sock *inet = inet_sk(sk);
0388b0042   Pavel Emelyanov   icmp: add struct ...
333
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  	struct iphdr *iph;
  	struct sk_buff *skb;
f844c74fe   Herbert Xu   [IPV4] raw: Stren...
336
  	unsigned int iphlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	int err;
1789a640f   Eric Dumazet   raw: avoid two at...
338
  	struct rtable *rt = *rtp;
660882432   Herbert Xu   ipv4: Remove all ...
339
  	int hlen, tlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

d8d1f30b9   Changli Gao   net-next: remove ...
341
  	if (length > rt->dst.dev->mtu) {
77968b782   David S. Miller   ipv4: Pass flow k...
342
  		ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
d8d1f30b9   Changli Gao   net-next: remove ...
343
  			       rt->dst.dev->mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
  		return -EMSGSIZE;
  	}
  	if (flags&MSG_PROBE)
  		goto out;
660882432   Herbert Xu   ipv4: Remove all ...
348
349
  	hlen = LL_RESERVED_SPACE(rt->dst.dev);
  	tlen = rt->dst.dev->needed_tailroom;
f5184d267   Johannes Berg   net: Allow netdev...
350
  	skb = sock_alloc_send_skb(sk,
660882432   Herbert Xu   ipv4: Remove all ...
351
  				  length + hlen + tlen + 15,
f5184d267   Johannes Berg   net: Allow netdev...
352
  				  flags & MSG_DONTWAIT, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  	if (skb == NULL)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
354
  		goto error;
660882432   Herbert Xu   ipv4: Remove all ...
355
  	skb_reserve(skb, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
  
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
358
  	skb->mark = sk->sk_mark;
d8d1f30b9   Changli Gao   net-next: remove ...
359
  	skb_dst_set(skb, &rt->dst);
1789a640f   Eric Dumazet   raw: avoid two at...
360
  	*rtp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361

7e28ecc28   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
362
  	skb_reset_network_header(skb);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
363
  	iph = ip_hdr(skb);
7e28ecc28   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
364
  	skb_put(skb, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
  
  	skb->ip_summed = CHECKSUM_NONE;
11878b40e   Willem de Bruijn   net-timestamp: SO...
367
  	sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
368
  	skb->transport_header = skb->network_header;
55888dfb6   Neil Horman   AF_RAW: Augment r...
369
370
371
  	err = -EFAULT;
  	if (memcpy_fromiovecend((void *)iph, from, 0, length))
  		goto error_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

f844c74fe   Herbert Xu   [IPV4] raw: Stren...
373
  	iphlen = iph->ihl * 4;
55888dfb6   Neil Horman   AF_RAW: Augment r...
374
375
376
377
378
379
380
381
382
383
384
385
386
  
  	/*
  	 * 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
387
  		if (!iph->saddr)
77968b782   David S. Miller   ipv4: Pass flow k...
388
  			iph->saddr = fl4->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  		iph->check   = 0;
  		iph->tot_len = htons(length);
  		if (!iph->id)
73f156a6e   Eric Dumazet   inetpeer: get rid...
392
  			ip_select_ident(skb, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  
  		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
  	}
96793b482   David L Stevens   [IPV4]: Add ICMPM...
396
  	if (iph->protocol == IPPROTO_ICMP)
0388b0042   Pavel Emelyanov   icmp: add struct ...
397
  		icmp_out_count(net, ((struct icmphdr *)
96793b482   David L Stevens   [IPV4]: Add ICMPM...
398
  			skb_transport_header(skb))->type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

9bbc768aa   Jan Engelhardt   netfilter: ipv4: ...
400
  	err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
d8d1f30b9   Changli Gao   net-next: remove ...
401
  		      rt->dst.dev, dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
403
  		err = net_xmit_errno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
  	if (err)
  		goto error;
  out:
  	return 0;
55888dfb6   Neil Horman   AF_RAW: Augment r...
408
  error_free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  	kfree_skb(skb);
  error:
5e38e2704   Pavel Emelyanov   mib: add net to I...
411
  	IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
412
413
  	if (err == -ENOBUFS && !inet->recverr)
  		err = 0;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
414
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  }
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
416
  static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  {
32b5913a9   Herbert Xu   ipv4: Use standar...
418
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

32b5913a9   Herbert Xu   ipv4: Use standar...
420
  	if (fl4->flowi4_proto != IPPROTO_ICMP)
a27b58fed   Heiko Carstens   [NET]: fix uacces...
421
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

32b5913a9   Herbert Xu   ipv4: Use standar...
423
  	/* We only need the first two bytes. */
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
424
  	rfv->hlen = 2;
b61e9dcc5   Al Viro   raw.c: stick msgh...
425
  	err = memcpy_from_msg(rfv->hdr.c, rfv->msg, rfv->hlen);
32b5913a9   Herbert Xu   ipv4: Use standar...
426
427
  	if (err)
  		return err;
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
428
429
  	fl4->fl4_icmp_type = rfv->hdr.icmph.type;
  	fl4->fl4_icmp_code = rfv->hdr.icmph.code;
32b5913a9   Herbert Xu   ipv4: Use standar...
430

a27b58fed   Heiko Carstens   [NET]: fix uacces...
431
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  }
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
  		       struct sk_buff *skb)
  {
  	struct raw_frag_vec *rfv = from;
  
  	if (offset < rfv->hlen) {
  		int copy = min(rfv->hlen - offset, len);
  
  		if (skb->ip_summed == CHECKSUM_PARTIAL)
  			memcpy(to, rfv->hdr.c + offset, copy);
  		else
  			skb->csum = csum_block_add(
  				skb->csum,
  				csum_partial_copy_nocheck(rfv->hdr.c + offset,
  							  to, copy, 0),
  				odd);
  
  		odd = 0;
  		offset += copy;
  		to += copy;
  		len -= copy;
  
  		if (!len)
  			return 0;
  	}
  
  	offset -= rfv->hlen;
f69e6d131   Al Viro   ip_generic_getfra...
460
  	return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
461
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
  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...
468
  	struct flowi4 fl4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  	int free = 0;
3ca3c68e7   Al Viro   [IPV4]: struct ip...
470
  	__be32 daddr;
c1d18f9fa   Al Viro   [IPV4]: struct ip...
471
  	__be32 saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
  	u8  tos;
  	int err;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
474
  	struct ip_options_data opt_copy;
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
475
  	struct raw_frag_vec rfv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  
  	err = -EMSGSIZE;
926d4b812   Jesper Juhl   [IPV4]: [2/4] sig...
478
  	if (len > 0xFFFF)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
485
486
487
  		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...
488

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	/*
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
490
  	 *	Get and verify the address.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
  	 */
  
  	if (msg->msg_namelen) {
342dfc306   Steffen Hurrle   net: add build-ti...
494
  		DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
  		err = -EINVAL;
  		if (msg->msg_namelen < sizeof(*usin))
  			goto out;
  		if (usin->sin_family != AF_INET) {
058bd4d2a   Joe Perches   net: Convert prin...
499
500
501
  			pr_info_once("%s: %s forgot to set AF_INET. Fix it!
  ",
  				     __func__, current->comm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
504
505
506
507
508
509
510
511
512
  			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...
513
  		if (sk->sk_state != TCP_ESTABLISHED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  			goto out;
c720c7e83   Eric Dumazet   inet: rename some...
515
  		daddr = inet->inet_daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  	}
c720c7e83   Eric Dumazet   inet: rename some...
517
  	ipc.addr = inet->inet_saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  	ipc.opt = NULL;
2244d07bf   Oliver Hartkopp   net: simplify fla...
519
  	ipc.tx_flags = 0;
aa6615814   Francesco Fusco   ipv4: processing ...
520
521
  	ipc.ttl = 0;
  	ipc.tos = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
  	ipc.oif = sk->sk_bound_dev_if;
  
  	if (msg->msg_controllen) {
c8e6ad082   Hannes Frederic Sowa   ipv6: honor IPV6_...
525
  		err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
531
532
533
  		if (err)
  			goto out;
  		if (ipc.opt)
  			free = 1;
  	}
  
  	saddr = ipc.addr;
  	ipc.addr = daddr;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
534
535
536
537
538
539
540
541
542
543
544
545
  	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
546
547
548
549
550
551
552
553
  
  	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...
554
  		if (ipc.opt->opt.srr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  			if (!daddr)
  				goto done;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
557
  			daddr = ipc.opt->opt.faddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
  		}
  	}
aa6615814   Francesco Fusco   ipv4: processing ...
560
  	tos = get_rtconn_flags(&ipc, sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
  	if (msg->msg_flags & MSG_DONTROUTE)
  		tos |= RTO_ONLINK;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
563
  	if (ipv4_is_multicast(daddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
  		if (!ipc.oif)
  			ipc.oif = inet->mc_index;
  		if (!saddr)
  			saddr = inet->mc_addr;
76e21053b   Erich E. Hoover   ipv4: Implement I...
568
569
  	} else if (!ipc.oif)
  		ipc.oif = inet->uc_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

77968b782   David S. Miller   ipv4: Pass flow k...
571
572
573
  	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
  			   RT_SCOPE_UNIVERSE,
  			   inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
0e0d44ab4   Steffen Klassert   net: Remove FLOWI...
574
  			   inet_sk_flowi_flags(sk) |
c27c9322d   Chris Clark   ipv4: sendto/hdri...
575
  			    (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
47670b767   Julian Anastasov   ipv4: route non-l...
576
  			   daddr, saddr, 0, 0);
ef164ae35   David S. Miller   ipv4: Use flowi4_...
577

77968b782   David S. Miller   ipv4: Pass flow k...
578
  	if (!inet->hdrincl) {
b61e9dcc5   Al Viro   raw.c: stick msgh...
579
  		rfv.msg = msg;
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
580
581
582
  		rfv.hlen = 0;
  
  		err = raw_probe_proto_opt(&rfv, &fl4);
77968b782   David S. Miller   ipv4: Pass flow k...
583
  		if (err)
b23dd4fe4   David S. Miller   ipv4: Make output...
584
  			goto done;
77968b782   David S. Miller   ipv4: Pass flow k...
585
586
587
588
589
590
591
592
  	}
  
  	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
593
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
599
600
601
602
603
  
  	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)
c0371da60   Al Viro   put iov_iter into...
604
605
  		/* XXX: stripping const */
  		err = raw_send_hdrinc(sk, &fl4, (struct iovec *)msg->msg_iter.iov, len,
77968b782   David S. Miller   ipv4: Pass flow k...
606
  				      &rt, msg->msg_flags);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
607

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  	 else {
11878b40e   Willem de Bruijn   net-timestamp: SO...
609
  		sock_tx_timestamp(sk, &ipc.tx_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  		if (!ipc.addr)
77968b782   David S. Miller   ipv4: Pass flow k...
611
  			ipc.addr = fl4.daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  		lock_sock(sk);
c008ba5bd   Herbert Xu   ipv4: Avoid readi...
613
614
  		err = ip_append_data(sk, &fl4, raw_getfrag,
  				     &rfv, len, 0,
77968b782   David S. Miller   ipv4: Pass flow k...
615
  				     &ipc, &rt, msg->msg_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
  		if (err)
  			ip_flush_pending_frames(sk);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
618
  		else if (!(msg->msg_flags & MSG_MORE)) {
77968b782   David S. Miller   ipv4: Pass flow k...
619
  			err = ip_push_pending_frames(sk, &fl4);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
620
621
622
  			if (err == -ENOBUFS && !inet->recverr)
  				err = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
627
628
  		release_sock(sk);
  	}
  done:
  	if (free)
  		kfree(ipc.opt);
  	ip_rt_put(rt);
5418c6926   Jesper Juhl   [IPV4]: [1/4] sig...
629
630
631
632
  out:
  	if (err < 0)
  		return err;
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
  
  do_confirm:
d8d1f30b9   Changli Gao   net-next: remove ...
635
  	dst_confirm(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
640
641
642
643
  	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...
644
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
645
  	 * Raw sockets may have direct kernel references. Kill them.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
649
650
  	 */
  	ip_ra_control(sk, 0, NULL);
  
  	sk_common_release(sk);
  }
7d06b2e05   Brian Haley   net: change proto...
651
  static void raw_destroy(struct sock *sk)
22dd48502   Denis V. Lunev   raw: Raw socket l...
652
653
654
655
  {
  	lock_sock(sk);
  	ip_flush_pending_frames(sk);
  	release_sock(sk);
22dd48502   Denis V. Lunev   raw: Raw socket l...
656
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
661
662
663
664
665
666
  /* 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...
667
  	chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
  	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...
672
  	inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
c720c7e83   Eric Dumazet   inet: rename some...
674
  		inet->inet_saddr = 0;  /* Use device */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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;
342dfc306   Steffen Hurrle   net: add build-ti...
691
  	DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
  	struct sk_buff *skb;
  
  	if (flags & MSG_OOB)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  	if (flags & MSG_ERRQUEUE) {
85fbaa750   Hannes Frederic Sowa   inet: fix addr_le...
697
  		err = ip_recv_error(sk, msg, len, addr_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
707
708
709
  		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;
  	}
51f3d02b9   David S. Miller   net: Add and use ...
710
  	err = skb_copy_datagram_msg(skb, 0, msg, copied);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
  	if (err)
  		goto done;
3b885787e   Neil Horman   net: Generalize s...
713
  	sock_recv_ts_and_drops(msg, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
  
  	/* Copy the address. */
  	if (sin) {
  		sin->sin_family = AF_INET;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
718
  		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
f59fc7f30   Tetsuo Handa   [IPV4/IPV6]: Sett...
719
  		sin->sin_port = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
721
  		*addr_len = sizeof(*sin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
727
728
  	}
  	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...
729
730
731
732
  out:
  	if (err)
  		return err;
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
737
  }
  
  static int raw_init(struct sock *sk)
  {
  	struct raw_sock *rp = raw_sk(sk);
c720c7e83   Eric Dumazet   inet: rename some...
738
  	if (inet_sk(sk)->inet_num == IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  		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...
770
  static int do_raw_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
771
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  	if (optname == ICMP_FILTER) {
c720c7e83   Eric Dumazet   inet: rename some...
774
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
780
  			return -EOPNOTSUPP;
  		else
  			return raw_seticmpfilter(sk, optval, optlen);
  	}
  	return -ENOPROTOOPT;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
781
  static int raw_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
782
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  {
  	if (level != SOL_RAW)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
785
786
787
  		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
788

3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
789
790
  #ifdef CONFIG_COMPAT
  static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
791
  				 char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
792
793
  {
  	if (level != SOL_RAW)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
794
  		return compat_ip_setsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
795
796
797
798
799
800
801
  	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
802
  	if (optname == ICMP_FILTER) {
c720c7e83   Eric Dumazet   inet: rename some...
803
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
809
  			return -EOPNOTSUPP;
  		else
  			return raw_geticmpfilter(sk, optval, optlen);
  	}
  	return -ENOPROTOOPT;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
810
811
812
813
814
815
816
817
818
819
  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...
820
  				 char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
821
822
  {
  	if (level != SOL_RAW)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
823
  		return compat_ip_getsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
824
825
826
  	return do_raw_getsockopt(sk, level, optname, optval, optlen);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
  static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
  	switch (cmd) {
4500ebf8d   Joe Perches   ipv4: Reduce swit...
830
831
  	case SIOCOUTQ: {
  		int amount = sk_wmem_alloc_get(sk);
31e6d363a   Eric Dumazet   net: correct off-...
832

4500ebf8d   Joe Perches   ipv4: Reduce swit...
833
834
835
836
837
838
839
840
841
842
843
844
845
  		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
846

4500ebf8d   Joe Perches   ipv4: Reduce swit...
847
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  #ifdef CONFIG_IP_MROUTE
4500ebf8d   Joe Perches   ipv4: Reduce swit...
849
  		return ipmr_ioctl(sk, cmd, (void __user *)arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  #else
4500ebf8d   Joe Perches   ipv4: Reduce swit...
851
  		return -ENOIOCTLCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
  #endif
  	}
  }
709b46e8d   Eric W. Biederman   net: Add compat i...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  #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
871
  struct proto raw_prot = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
872
873
874
  	.name		   = "RAW",
  	.owner		   = THIS_MODULE,
  	.close		   = raw_close,
22dd48502   Denis V. Lunev   raw: Raw socket l...
875
  	.destroy	   = raw_destroy,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
876
877
878
879
880
881
882
883
884
885
  	.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,
8141ed9fc   Steffen Klassert   ipv4: Add a socke...
886
  	.release_cb	   = ip4_datagram_release_cb,
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
887
888
  	.hash		   = raw_hash_sk,
  	.unhash		   = raw_unhash_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
889
  	.obj_size	   = sizeof(struct raw_sock),
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
890
  	.h.raw_hash	   = &raw_v4_hashinfo,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
891
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
892
893
  	.compat_setsockopt = compat_raw_setsockopt,
  	.compat_getsockopt = compat_raw_getsockopt,
709b46e8d   Eric W. Biederman   net: Add compat i...
894
  	.compat_ioctl	   = compat_raw_ioctl,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
895
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
  };
  
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
  static struct sock *raw_get_first(struct seq_file *seq)
  {
  	struct sock *sk;
5a5f3a8db   Jianjun Kong   net: clean up net...
902
  	struct raw_iter_state *state = raw_seq_private(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
904
905
  	for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE;
  			++state->bucket) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
906
  		sk_for_each(sk, &state->h->ht[state->bucket])
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
907
  			if (sock_net(sk) == seq_file_net(seq))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
913
914
915
916
  				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...
917
  	struct raw_iter_state *state = raw_seq_private(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
921
922
  
  	do {
  		sk = sk_next(sk);
  try_again:
  		;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
923
  	} while (sk && sock_net(sk) != seq_file_net(seq));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
925
  	if (!sk && ++state->bucket < RAW_HTABLE_SIZE) {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
926
  		sk = sk_head(&state->h->ht[state->bucket]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
931
932
933
934
935
936
937
938
939
940
  		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...
941
  void *raw_seq_start(struct seq_file *seq, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
943
944
945
  	struct raw_iter_state *state = raw_seq_private(seq);
  
  	read_lock(&state->h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
  	return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
  }
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
948
  EXPORT_SYMBOL_GPL(raw_seq_start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949

42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
950
  void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
955
956
957
958
959
960
  {
  	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...
961
  EXPORT_SYMBOL_GPL(raw_seq_next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962

42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
963
  void raw_seq_stop(struct seq_file *seq, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
965
966
967
  	struct raw_iter_state *state = raw_seq_private(seq);
  
  	read_unlock(&state->h->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  }
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
969
  EXPORT_SYMBOL_GPL(raw_seq_stop);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970

8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
971
  static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
  {
  	struct inet_sock *inet = inet_sk(sp);
c720c7e83   Eric Dumazet   inet: rename some...
974
975
  	__be32 dest = inet->inet_daddr,
  	       src = inet->inet_rcv_saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
  	__u16 destp = 0,
c720c7e83   Eric Dumazet   inet: rename some...
977
  	      srcp  = inet->inet_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978

8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
979
  	seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
d14c5ab6b   Francesco Fusco   net: proc_fs: tri...
980
981
  		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d
  ",
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
982
  		i, src, srcp, dest, destp, sp->sk_state,
31e6d363a   Eric Dumazet   net: correct off-...
983
984
  		sk_wmem_alloc_get(sp),
  		sk_rmem_alloc_get(sp),
a7cb5a49b   Eric W. Biederman   userns: Print out...
985
986
987
  		0, 0L, 0,
  		from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
  		0, sock_i_ino(sp),
33c732c36   Wang Chen   [IPV4]: Add raw d...
988
  		atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
991
992
  }
  
  static int raw_seq_show(struct seq_file *seq, void *v)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
  	if (v == SEQ_START_TOKEN)
8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
994
995
  		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...
996
997
  				"inode ref pointer drops
  ");
8cd850efa   Denis V. Lunev   [RAW]: Cleanup IP...
998
999
  	else
  		raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
1002
  static const struct seq_operations raw_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
1005
1006
1007
  	.start = raw_seq_start,
  	.next  = raw_seq_next,
  	.stop  = raw_seq_stop,
  	.show  = raw_seq_show,
  };
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
1008
1009
  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
1010
  {
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1011
  	int err;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1012
  	struct raw_iter_state *i;
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
1013
  	err = seq_open_net(ino, file, ops, sizeof(struct raw_iter_state));
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1014
1015
  	if (err < 0)
  		return err;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1016

f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1017
  	i = raw_seq_private((struct seq_file *)file->private_data);
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1018
  	i->h = h;
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1019
1020
1021
1022
1023
1024
  	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...
1025
  	return raw_seq_open(inode, file, &raw_v4_hashinfo, &raw_seq_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
1027
  static const struct file_operations raw_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
  	.owner	 = THIS_MODULE,
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1029
  	.open	 = raw_v4_seq_open,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1032
  	.release = seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  };
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1034
  static __net_init int raw_init_net(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  {
d4beaa66a   Gao feng   net: proc: change...
1036
  	if (!proc_create("raw", S_IRUGO, net->proc_net, &raw_seq_fops))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
  		return -ENOMEM;
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1038

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
  	return 0;
  }
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1041
1042
  static __net_exit void raw_exit_net(struct net *net)
  {
ece31ffd5   Gao feng   net: proc: change...
1043
  	remove_proc_entry("raw", net->proc_net);
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  }
  
  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
1055
1056
  void __init raw_proc_exit(void)
  {
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1057
  	unregister_pernet_subsys(&raw_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
  }
  #endif /* CONFIG_PROC_FS */