Blame view

net/ipv6/raw.c 30.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *	RAW sockets for IPv6
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3
   *	Linux INET6 implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
6
   *	Pedro Roque		<roque@di.fc.ul.pt>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
   *
   *	Adapted from linux/net/ipv4/raw.c
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
   *	Fixes:
   *	Hideaki YOSHIFUJI	:	sin6_scope_id support
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
12
   *	YOSHIFUJI,H.@USAGI	:	raw checksum (RFC2292(bis) compliance)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
21
22
23
   *	Kazunori MIYAZAWA @USAGI:	change process style to use ip6_append_data
   *
   *	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.
   */
  
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/sockios.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
  #include <linux/net.h>
  #include <linux/in6.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/icmpv6.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv6.h>
3305b80c2   Herbert Xu   [IP]: Simplify an...
33
  #include <linux/skbuff.h>
e2d57766e   David S. Miller   net: Provide comp...
34
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include <asm/uaccess.h>
  #include <asm/ioctls.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
37
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
48
49
50
  #include <net/ip.h>
  #include <net/sock.h>
  #include <net/snmp.h>
  
  #include <net/ipv6.h>
  #include <net/ndisc.h>
  #include <net/protocol.h>
  #include <net/ip6_route.h>
  #include <net/ip6_checksum.h>
  #include <net/addrconf.h>
  #include <net/transp_v6.h>
  #include <net/udp.h>
  #include <net/inet_common.h>
c752f0739   Arnaldo Carvalho de Melo   [TCP]: Move the t...
51
  #include <net/tcp_states.h>
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
52
  #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
53
54
  #include <net/mip6.h>
  #endif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
55
  #include <linux/mroute6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
57
  #include <net/raw.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
  #include <net/rawv6.h>
  #include <net/xfrm.h>
  
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
63
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
65
  static struct raw_hashinfo raw_v6_hashinfo = {
938b93adb   Robert P. J. Day   [NET]: Add debugg...
66
  	.lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock),
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
67
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
69
  static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
b71d1d426   Eric Dumazet   inet: constify ip...
70
71
  		unsigned short num, const struct in6_addr *loc_addr,
  		const struct in6_addr *rmt_addr, int dif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
  {
  	struct hlist_node *node;
  	int is_multicast = ipv6_addr_is_multicast(loc_addr);
  
  	sk_for_each_from(sk, node)
c720c7e83   Eric Dumazet   inet: rename some...
77
  		if (inet_sk(sk)->inet_num == num) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  			struct ipv6_pinfo *np = inet6_sk(sk);
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
79
  			if (!net_eq(sock_net(sk), net))
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
80
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  			if (!ipv6_addr_any(&np->daddr) &&
  			    !ipv6_addr_equal(&np->daddr, rmt_addr))
  				continue;
0bd1b59b1   Andrew McDonald   [IPV6]: Check int...
84
85
  			if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  			if (!ipv6_addr_any(&np->rcv_saddr)) {
  				if (ipv6_addr_equal(&np->rcv_saddr, loc_addr))
  					goto found;
  				if (is_multicast &&
  				    inet6_mc_check(sk, loc_addr, rmt_addr))
  					goto found;
  				continue;
  			}
  			goto found;
  		}
  	sk = NULL;
  found:
  	return sk;
  }
  
  /*
   *	0 - deliver
   *	1 - block
   */
  static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
  {
  	struct icmp6hdr *icmph;
  	struct raw6_sock *rp = raw6_sk(sk);
  
  	if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) {
  		__u32 *data = &rp->filter.data[0];
  		int bit_nr;
  
  		icmph = (struct icmp6hdr *) skb->data;
  		bit_nr = icmph->icmp6_type;
  
  		return (data[bit_nr >> 5] & (1 << (bit_nr & 31))) != 0;
  	}
  	return 0;
  }
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
121
  #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
122
  typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
123

f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
124
125
126
  static mh_filter_t __rcu *mh_filter __read_mostly;
  
  int rawv6_mh_filter_register(mh_filter_t filter)
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
127
  {
cf778b00e   Eric Dumazet   net: reintroduce ...
128
  	rcu_assign_pointer(mh_filter, filter);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
129
130
131
  	return 0;
  }
  EXPORT_SYMBOL(rawv6_mh_filter_register);
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
132
  int rawv6_mh_filter_unregister(mh_filter_t filter)
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
133
  {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
134
  	RCU_INIT_POINTER(mh_filter, NULL);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
135
136
137
138
139
140
  	synchronize_rcu();
  	return 0;
  }
  EXPORT_SYMBOL(rawv6_mh_filter_unregister);
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
  /*
   *	demultiplex raw sockets.
   *	(should consider queueing the skb in the sock receive_queue
   *	without calling rawv6.c)
   *
   *	Caller owns SKB so we must make clones.
   */
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
148
  static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  {
b71d1d426   Eric Dumazet   inet: constify ip...
150
151
  	const struct in6_addr *saddr;
  	const struct in6_addr *daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	struct sock *sk;
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
153
  	int delivered = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	__u8 hash;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
155
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
157
  	saddr = &ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
  	daddr = saddr + 1;
  
  	hash = nexthdr & (MAX_INET_PROTOS - 1);
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
161
162
  	read_lock(&raw_v6_hashinfo.lock);
  	sk = sk_head(&raw_v6_hashinfo.ht[hash]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  	if (sk == NULL)
  		goto out;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
166
  	net = dev_net(skb->dev);
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
167
  	sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
  
  	while (sk) {
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
170
  		int filtered;
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
171
  		delivered = 1;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
172
173
174
175
  		switch (nexthdr) {
  		case IPPROTO_ICMPV6:
  			filtered = icmpv6_filter(sk, skb);
  			break;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
176
177
  
  #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
178
  		case IPPROTO_MH:
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
179
  		{
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
180
181
182
183
184
185
  			/* XXX: To validate MH only once for each packet,
  			 * this is placed here. It should be after checking
  			 * xfrm policy, however it doesn't. The checking xfrm
  			 * policy is placed in rawv6_rcv() because it is
  			 * required for each socket.
  			 */
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
186
  			mh_filter_t *filter;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
187
188
  
  			filter = rcu_dereference(mh_filter);
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
189
  			filtered = filter ? (*filter)(sk, skb) : 0;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
190
  			break;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
191
  		}
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
192
193
194
195
196
197
198
199
200
  #endif
  		default:
  			filtered = 0;
  			break;
  		}
  
  		if (filtered < 0)
  			break;
  		if (filtered == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
  			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
  
  			/* Not releasing hash table! */
9fb9cbb10   Yasuyuki Kozakai   [NETFILTER]: Add ...
204
205
  			if (clone) {
  				nf_reset(clone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  				rawv6_rcv(sk, clone);
9fb9cbb10   Yasuyuki Kozakai   [NETFILTER]: Add ...
207
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  		}
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
209
  		sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr,
2dac4b96b   YOSHIFUJI Hideaki   [IPV6]: Repair In...
210
  				     IP6CB(skb)->iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  	}
  out:
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
213
  	read_unlock(&raw_v6_hashinfo.lock);
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
214
  	return delivered;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  }
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
216
217
218
  int raw6_local_deliver(struct sk_buff *skb, int nexthdr)
  {
  	struct sock *raw_sk;
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
219
  	raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (MAX_INET_PROTOS - 1)]);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
220
221
222
223
224
  	if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
  		raw_sk = NULL;
  
  	return raw_sk != NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
  /* This cleans up af_inet6 a bit. -DaveM */
  static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
e69a4adc6   Al Viro   [IPV6]: Misc endi...
231
  	__be32 v4addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
239
240
  	int addr_type;
  	int err;
  
  	if (addr_len < SIN6_LEN_RFC2133)
  		return -EINVAL;
  	addr_type = ipv6_addr_type(&addr->sin6_addr);
  
  	/* Raw sockets are IPv6 only */
  	if (addr_type == IPV6_ADDR_MAPPED)
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
241
  		return -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
  
  	lock_sock(sk);
  
  	err = -EINVAL;
  	if (sk->sk_state != TCP_CLOSE)
  		goto out;
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
248
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
260
  	/* Check if the address belongs to the host. */
  	if (addr_type != IPV6_ADDR_ANY) {
  		struct net_device *dev = NULL;
  
  		if (addr_type & IPV6_ADDR_LINKLOCAL) {
  			if (addr_len >= sizeof(struct sockaddr_in6) &&
  			    addr->sin6_scope_id) {
  				/* Override any existing binding, if another
  				 * one is supplied by user.
  				 */
  				sk->sk_bound_dev_if = addr->sin6_scope_id;
  			}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
261

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
  			/* Binding to link-local address requires an interface */
  			if (!sk->sk_bound_dev_if)
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
264
  				goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
266
267
268
269
270
  			err = -ENODEV;
  			dev = dev_get_by_index_rcu(sock_net(sk),
  						   sk->sk_bound_dev_if);
  			if (!dev)
  				goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  		}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
272

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
  		/* ipv4 addr of the socket is invalid.  Only the
  		 * unspecified and mapped address have a v4 equivalent.
  		 */
  		v4addr = LOOPBACK4_IPV6;
  		if (!(addr_type & IPV6_ADDR_MULTICAST))	{
  			err = -EADDRNOTAVAIL;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
279
  			if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
bfeade087   Daniel Lezcano   [NETNS][IPV6]: in...
280
  					   dev, 0)) {
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
281
  				goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  	}
c720c7e83   Eric Dumazet   inet: rename some...
285
  	inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
286
  	np->rcv_saddr = addr->sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  	if (!(addr_type & IPV6_ADDR_MULTICAST))
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
288
  		np->saddr = addr->sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  	err = 0;
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
290
291
  out_unlock:
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
  out:
  	release_sock(sk);
  	return err;
  }
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
296
  static void rawv6_err(struct sock *sk, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	       struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
298
  	       u8 type, u8 code, int offset, __be32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	int err;
  	int harderr;
  
  	/* Report error on raw socket, if:
  	   1. User requested recverr.
  	   2. Socket is connected (otherwise the error indication
  	      is useless without recverr and error is hard.
  	 */
  	if (!np->recverr && sk->sk_state != TCP_ESTABLISHED)
  		return;
  
  	harderr = icmpv6_err_convert(type, code, &err);
  	if (type == ICMPV6_PKT_TOOBIG)
  		harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
  
  	if (np->recverr) {
  		u8 *payload = skb->data;
  		if (!inet->hdrincl)
  			payload += offset;
  		ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);
  	}
  
  	if (np->recverr || harderr) {
  		sk->sk_err = err;
  		sk->sk_error_report(sk);
  	}
  }
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
329
  void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
d5fdd6bab   Brian Haley   ipv6: Use correct...
330
  		u8 type, u8 code, int inner_offset, __be32 info)
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
331
332
333
  {
  	struct sock *sk;
  	int hash;
b71d1d426   Eric Dumazet   inet: constify ip...
334
  	const struct in6_addr *saddr, *daddr;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
335
  	struct net *net;
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
336

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
337
  	hash = nexthdr & (RAW_HTABLE_SIZE - 1);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
338

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
339
340
  	read_lock(&raw_v6_hashinfo.lock);
  	sk = sk_head(&raw_v6_hashinfo.ht[hash]);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
341
  	if (sk != NULL) {
05f175cdc   YOSHIFUJI Hideaki   [IPV6]: Fix IPV6_...
342
  		/* Note: ipv6_hdr(skb) != skb->data */
b71d1d426   Eric Dumazet   inet: constify ip...
343
  		const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
05f175cdc   YOSHIFUJI Hideaki   [IPV6]: Fix IPV6_...
344
345
  		saddr = &ip6h->saddr;
  		daddr = &ip6h->daddr;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
346
  		net = dev_net(skb->dev);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
347

be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
348
  		while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr,
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
349
350
351
352
353
354
  						IP6CB(skb)->iif))) {
  			rawv6_err(sk, skb, NULL, type, code,
  					inner_offset, info);
  			sk = sk_next(sk);
  		}
  	}
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
355
  	read_unlock(&raw_v6_hashinfo.lock);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
356
  }
33d480ce6   Eric Dumazet   net: cleanup some...
357
  static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  {
33d480ce6   Eric Dumazet   net: cleanup some...
359
  	if ((raw6_sk(sk)->checksum || rcu_access_pointer(sk->sk_filter)) &&
fb286bb29   Herbert Xu   [NET]: Detect har...
360
  	    skb_checksum_complete(skb)) {
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
361
  		atomic_inc(&sk->sk_drops);
fb286bb29   Herbert Xu   [NET]: Detect har...
362
  		kfree_skb(skb);
3cc76caa9   Yang Hongyang   ipv6: When we dro...
363
  		return NET_RX_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
  	}
  
  	/* Charge it to the socket. */
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
367
368
  	skb_dst_drop(skb);
  	if (sock_queue_rcv_skb(sk, skb) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  		kfree_skb(skb);
3cc76caa9   Yang Hongyang   ipv6: When we dro...
370
  		return NET_RX_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
  	}
  
  	return 0;
  }
  
  /*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
377
   *	This is next to useless...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
   *	if we demultiplex in network layer we don't need the extra call
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
379
380
   *	just to queue the skb...
   *	maybe we could have the network decide upon a hint if it
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
   *	should call raw_rcv for demultiplexing
   */
  int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct raw6_sock *rp = raw6_sk(sk);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
387
  	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) {
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
388
  		atomic_inc(&sk->sk_drops);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
389
390
391
  		kfree_skb(skb);
  		return NET_RX_DROP;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
  
  	if (!rp->checksum)
  		skb->ip_summed = CHECKSUM_UNNECESSARY;
84fa7933a   Patrick McHardy   [NET]: Replace CH...
395
  	if (skb->ip_summed == CHECKSUM_COMPLETE) {
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
396
  		skb_postpull_rcsum(skb, skb_network_header(skb),
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
397
  				   skb_network_header_len(skb));
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
398
399
  		if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
  				     &ipv6_hdr(skb)->daddr,
c720c7e83   Eric Dumazet   inet: rename some...
400
  				     skb->len, inet->inet_num, skb->csum))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  			skb->ip_summed = CHECKSUM_UNNECESSARY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	}
604763722   Herbert Xu   [NET]: Treat CHEC...
403
  	if (!skb_csum_unnecessary(skb))
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
404
405
406
  		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
  							 &ipv6_hdr(skb)->daddr,
  							 skb->len,
c720c7e83   Eric Dumazet   inet: rename some...
407
  							 inet->inet_num, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
  
  	if (inet->hdrincl) {
fb286bb29   Herbert Xu   [NET]: Detect har...
410
  		if (skb_checksum_complete(skb)) {
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
411
  			atomic_inc(&sk->sk_drops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  			kfree_skb(skb);
3cc76caa9   Yang Hongyang   ipv6: When we dro...
413
  			return NET_RX_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  	}
  
  	rawv6_rcv_skb(sk, skb);
  	return 0;
  }
  
  
  /*
   *	This should be easy, if there is something there
   *	we return it, otherwise we block.
   */
  
  static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
  		  struct msghdr *msg, size_t len,
  		  int noblock, int flags, int *addr_len)
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)msg->msg_name;
  	struct sk_buff *skb;
  	size_t copied;
  	int err;
  
  	if (flags & MSG_OOB)
  		return -EOPNOTSUPP;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
439
440
  
  	if (addr_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
  		*addr_len=sizeof(*sin6);
  
  	if (flags & MSG_ERRQUEUE)
  		return ipv6_recv_error(sk, msg, len);
4b340ae20   Brian Haley   IPv6: Complete IP...
445
446
  	if (np->rxpmtu && np->rxopt.bits.rxpmtu)
  		return ipv6_recv_rxpmtu(sk, msg, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
449
450
451
  	skb = skb_recv_datagram(sk, flags, noblock, &err);
  	if (!skb)
  		goto out;
  
  	copied = skb->len;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
452
453
454
455
  	if (copied > len) {
  		copied = len;
  		msg->msg_flags |= MSG_TRUNC;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456

604763722   Herbert Xu   [NET]: Treat CHEC...
457
  	if (skb_csum_unnecessary(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
  		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
  	} else if (msg->msg_flags&MSG_TRUNC) {
fb286bb29   Herbert Xu   [NET]: Detect har...
460
  		if (__skb_checksum_complete(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
468
469
470
471
472
473
  			goto csum_copy_err;
  		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
  	} else {
  		err = skb_copy_and_csum_datagram_iovec(skb, 0, msg->msg_iov);
  		if (err == -EINVAL)
  			goto csum_copy_err;
  	}
  	if (err)
  		goto out_free;
  
  	/* Copy the address. */
  	if (sin6) {
  		sin6->sin6_family = AF_INET6;
f59fc7f30   Tetsuo Handa   [IPV4/IPV6]: Sett...
474
  		sin6->sin6_port = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
475
  		sin6->sin6_addr = ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
479
480
  		sin6->sin6_flowinfo = 0;
  		sin6->sin6_scope_id = 0;
  		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
  			sin6->sin6_scope_id = IP6CB(skb)->iif;
  	}
3b885787e   Neil Horman   net: Generalize s...
481
  	sock_recv_ts_and_drops(msg, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  
  	if (np->rxopt.all)
  		datagram_recv_ctl(sk, msg, skb);
  
  	err = copied;
  	if (flags & MSG_TRUNC)
  		err = skb->len;
  
  out_free:
  	skb_free_datagram(sk, skb);
  out:
  	return err;
  
  csum_copy_err:
3305b80c2   Herbert Xu   [IP]: Simplify an...
496
  	skb_kill_datagram(sk, skb, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
  
  	/* Error for blocking case is chosen to masquerade
  	   as some normal condition.
  	 */
  	err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
3305b80c2   Herbert Xu   [IP]: Simplify an...
502
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  }
4c9483b2f   David S. Miller   ipv6: Convert to ...
504
  static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
505
  				     struct raw6_sock *rp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
  {
  	struct sk_buff *skb;
  	int err = 0;
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
509
510
  	int offset;
  	int len;
679a87382   Herbert Xu   [IPV6]: Fix raw s...
511
  	int total_len;
868c86bcb   Al Viro   [NET]: annotate c...
512
513
  	__wsum tmp_csum;
  	__sum16 csum;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
  
  	if (!rp->checksum)
  		goto send;
  
  	if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
  		goto out;
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
520
  	offset = rp->offset;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
521
  	total_len = inet_sk(sk)->cork.base.length;
679a87382   Herbert Xu   [IPV6]: Fix raw s...
522
  	if (offset >= total_len - 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  		err = -EINVAL;
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
524
  		ip6_flush_pending_frames(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
530
531
532
533
534
  		goto out;
  	}
  
  	/* should be check HW csum miyazawa */
  	if (skb_queue_len(&sk->sk_write_queue) == 1) {
  		/*
  		 * Only one fragment on the socket.
  		 */
  		tmp_csum = skb->csum;
  	} else {
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
535
  		struct sk_buff *csum_skb = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
  		tmp_csum = 0;
  
  		skb_queue_walk(&sk->sk_write_queue, skb) {
  			tmp_csum = csum_add(tmp_csum, skb->csum);
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
540
541
542
  
  			if (csum_skb)
  				continue;
ea2ae17d6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
543
  			len = skb->len - skb_transport_offset(skb);
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
544
545
546
547
548
549
  			if (offset >= len) {
  				offset -= len;
  				continue;
  			}
  
  			csum_skb = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  		}
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
551
552
  
  		skb = csum_skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	}
ea2ae17d6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
554
  	offset += skb_transport_offset(skb);
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
555
556
  	if (skb_copy_bits(skb, offset, &csum, 2))
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	/* in case cksum was not initialized */
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
558
  	if (unlikely(csum))
5f92a7388   Al Viro   [NET]: Annotate c...
559
  		tmp_csum = csum_sub(tmp_csum, csum_unfold(csum));
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
560

4c9483b2f   David S. Miller   ipv6: Convert to ...
561
562
  	csum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
  			       total_len, fl6->flowi6_proto, tmp_csum);
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
563

4c9483b2f   David S. Miller   ipv6: Convert to ...
564
  	if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP)
f6ab02880   Al Viro   [NET]: Make mangl...
565
  		csum = CSUM_MANGLED_0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566

357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
567
568
  	if (skb_store_bits(skb, offset, &csum, 2))
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
575
576
  send:
  	err = ip6_push_pending_frames(sk);
  out:
  	return err;
  }
  
  static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
4c9483b2f   David S. Miller   ipv6: Convert to ...
577
  			struct flowi6 *fl6, struct dst_entry **dstp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
  			unsigned int flags)
  {
3320da890   Herbert Xu   [IPV6]: Replace b...
580
  	struct ipv6_pinfo *np = inet6_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
  	struct ipv6hdr *iph;
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  	int err;
1789a640f   Eric Dumazet   raw: avoid two at...
584
  	struct rt6_info *rt = (struct rt6_info *)*dstp;
a7ae19922   Herbert Xu   ipv6: Remove all ...
585
586
  	int hlen = LL_RESERVED_SPACE(rt->dst.dev);
  	int tlen = rt->dst.dev->needed_tailroom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587

d8d1f30b9   Changli Gao   net-next: remove ...
588
  	if (length > rt->dst.dev->mtu) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
589
  		ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
593
  		return -EMSGSIZE;
  	}
  	if (flags&MSG_PROBE)
  		goto out;
f5184d267   Johannes Berg   net: Allow netdev...
594
  	skb = sock_alloc_send_skb(sk,
a7ae19922   Herbert Xu   ipv6: Remove all ...
595
  				  length + hlen + tlen + 15,
f5184d267   Johannes Berg   net: Allow netdev...
596
  				  flags & MSG_DONTWAIT, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  	if (skb == NULL)
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
598
  		goto error;
a7ae19922   Herbert Xu   ipv6: Remove all ...
599
  	skb_reserve(skb, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
  
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
602
  	skb->mark = sk->sk_mark;
d8d1f30b9   Changli Gao   net-next: remove ...
603
  	skb_dst_set(skb, &rt->dst);
1789a640f   Eric Dumazet   raw: avoid two at...
604
  	*dstp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605

1ced98e81   Arnaldo Carvalho de Melo   [SK_BUFF] ipv6: M...
606
607
  	skb_put(skb, length);
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
608
  	iph = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  
  	skb->ip_summed = CHECKSUM_NONE;
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
611
  	skb->transport_header = skb->network_header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
  	err = memcpy_fromiovecend((void *)iph, from, 0, length);
  	if (err)
  		goto error_fault;
edf391ff1   Neil Horman   snmp: add missing...
615
  	IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
616
  	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
d8d1f30b9   Changli Gao   net-next: remove ...
617
  		      rt->dst.dev, dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
619
  		err = net_xmit_errno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
626
627
628
  	if (err)
  		goto error;
  out:
  	return 0;
  
  error_fault:
  	err = -EFAULT;
  	kfree_skb(skb);
  error:
3bd653c84   Denis V. Lunev   netns: add net pa...
629
  	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
630
631
  	if (err == -ENOBUFS && !np->recverr)
  		err = 0;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
632
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
  }
4c9483b2f   David S. Miller   ipv6: Convert to ...
634
  static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
  {
  	struct iovec *iov;
  	u8 __user *type = NULL;
  	u8 __user *code = NULL;
6e8f4d48b   Masahide NAKAMURA   [IPV6] MIP6: Add ...
639
  	u8 len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
  	int probed = 0;
  	int i;
  
  	if (!msg->msg_iov)
a27b58fed   Heiko Carstens   [NET]: fix uacces...
644
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
  
  	for (i = 0; i < msg->msg_iovlen; i++) {
  		iov = &msg->msg_iov[i];
  		if (!iov)
  			continue;
4c9483b2f   David S. Miller   ipv6: Convert to ...
650
  		switch (fl6->flowi6_proto) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  		case IPPROTO_ICMPV6:
  			/* 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) {
1958b856c   David S. Miller   net: Put fl6_* ma...
665
666
  				if (get_user(fl6->fl6_icmp_type, type) ||
  				    get_user(fl6->fl6_icmp_code, code))
a27b58fed   Heiko Carstens   [NET]: fix uacces...
667
  					return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
  				probed = 1;
  			}
  			break;
6e8f4d48b   Masahide NAKAMURA   [IPV6] MIP6: Add ...
671
672
673
674
675
676
  		case IPPROTO_MH:
  			if (iov->iov_base && iov->iov_len < 1)
  				break;
  			/* check if type field is readable or not. */
  			if (iov->iov_len > 2 - len) {
  				u8 __user *p = iov->iov_base;
1958b856c   David S. Miller   net: Put fl6_* ma...
677
  				if (get_user(fl6->fl6_mh_type, &p[2 - len]))
a27b58fed   Heiko Carstens   [NET]: fix uacces...
678
  					return -EFAULT;
6e8f4d48b   Masahide NAKAMURA   [IPV6] MIP6: Add ...
679
680
681
682
683
  				probed = 1;
  			} else
  				len += iov->iov_len;
  
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
689
690
  		default:
  			probed = 1;
  			break;
  		}
  		if (probed)
  			break;
  	}
a27b58fed   Heiko Carstens   [NET]: fix uacces...
691
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
697
698
  }
  
  static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
  		   struct msghdr *msg, size_t len)
  {
  	struct ipv6_txoptions opt_space;
  	struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
20c59de2e   Arnaud Ebalard   ipv6: Refactor up...
699
  	struct in6_addr *daddr, *final_p, final;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
705
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct raw6_sock *rp = raw6_sk(sk);
  	struct ipv6_txoptions *opt = NULL;
  	struct ip6_flowlabel *flowlabel = NULL;
  	struct dst_entry *dst = NULL;
4c9483b2f   David S. Miller   ipv6: Convert to ...
706
  	struct flowi6 fl6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
  	int addr_len = msg->msg_namelen;
  	int hlimit = -1;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
709
  	int tclass = -1;
13b52cd44   Brian Haley   IPv6: Add dontfra...
710
  	int dontfrag = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
  	u16 proto;
  	int err;
  
  	/* Rough check on arithmetic overflow,
b59e139bb   YOSHIFUJI Hideaki   [IPv6]: Fix incor...
715
  	   better check is made in ip6_append_data().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
  	 */
b59e139bb   YOSHIFUJI Hideaki   [IPv6]: Fix incor...
717
  	if (len > INT_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
  		return -EMSGSIZE;
  
  	/* Mirror BSD error message compatibility */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
721
  	if (msg->msg_flags & MSG_OOB)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
  		return -EOPNOTSUPP;
  
  	/*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
725
  	 *	Get and verify the address.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	 */
4c9483b2f   David S. Miller   ipv6: Convert to ...
727
  	memset(&fl6, 0, sizeof(fl6));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728

4c9483b2f   David S. Miller   ipv6: Convert to ...
729
  	fl6.flowi6_mark = sk->sk_mark;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
730

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	if (sin6) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
732
  		if (addr_len < SIN6_LEN_RFC2133)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  			return -EINVAL;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
734
  		if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
a02cec215   Eric Dumazet   net: return opera...
735
  			return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
  
  		/* port is the proto value [0..255] carried in nexthdr */
  		proto = ntohs(sin6->sin6_port);
  
  		if (!proto)
c720c7e83   Eric Dumazet   inet: rename some...
741
742
  			proto = inet->inet_num;
  		else if (proto != inet->inet_num)
a02cec215   Eric Dumazet   net: return opera...
743
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
  
  		if (proto > 255)
a02cec215   Eric Dumazet   net: return opera...
746
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
  
  		daddr = &sin6->sin6_addr;
  		if (np->sndflow) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
750
751
752
  			fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
  			if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
  				flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  				if (flowlabel == NULL)
  					return -EINVAL;
  				daddr = &flowlabel->dst;
  			}
  		}
  
  		/*
  		 * Otherwise it will be difficult to maintain
  		 * sk->sk_dst_cache.
  		 */
  		if (sk->sk_state == TCP_ESTABLISHED &&
  		    ipv6_addr_equal(daddr, &np->daddr))
  			daddr = &np->daddr;
  
  		if (addr_len >= sizeof(struct sockaddr_in6) &&
  		    sin6->sin6_scope_id &&
  		    ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
4c9483b2f   David S. Miller   ipv6: Convert to ...
770
  			fl6.flowi6_oif = sin6->sin6_scope_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	} else {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
772
  		if (sk->sk_state != TCP_ESTABLISHED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  			return -EDESTADDRREQ;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
774

c720c7e83   Eric Dumazet   inet: rename some...
775
  		proto = inet->inet_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  		daddr = &np->daddr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
777
  		fl6.flowlabel = np->flow_label;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
779
780
  	if (fl6.flowi6_oif == 0)
  		fl6.flowi6_oif = sk->sk_bound_dev_if;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
  
  	if (msg->msg_controllen) {
  		opt = &opt_space;
  		memset(opt, 0, sizeof(struct ipv6_txoptions));
  		opt->tot_len = sizeof(struct ipv6_txoptions);
ec0506dbe   Maciej Å»enczykowski   net: relax PKTINF...
786
787
  		err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
  					&hlimit, &tclass, &dontfrag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
790
791
  		if (err < 0) {
  			fl6_sock_release(flowlabel);
  			return err;
  		}
4c9483b2f   David S. Miller   ipv6: Convert to ...
792
793
  		if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
  			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
798
799
800
801
  			if (flowlabel == NULL)
  				return -EINVAL;
  		}
  		if (!(opt->opt_nflen|opt->opt_flen))
  			opt = NULL;
  	}
  	if (opt == NULL)
  		opt = np->opt;
df9890c31   YOSHIFUJI Hideaki   [IPV6]: Fix sendi...
802
803
804
  	if (flowlabel)
  		opt = fl6_merge_options(&opt_space, flowlabel, opt);
  	opt = ipv6_fixup_options(&opt_space, opt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805

4c9483b2f   David S. Miller   ipv6: Convert to ...
806
807
  	fl6.flowi6_proto = proto;
  	err = rawv6_probe_proto_opt(&fl6, msg);
a27b58fed   Heiko Carstens   [NET]: fix uacces...
808
809
  	if (err)
  		goto out;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
810

876c7f419   Brian Haley   [IPv6]: Change IP...
811
  	if (!ipv6_addr_any(daddr))
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
812
  		fl6.daddr = *daddr;
876c7f419   Brian Haley   [IPv6]: Change IP...
813
  	else
4c9483b2f   David S. Miller   ipv6: Convert to ...
814
815
  		fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
  	if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
816
  		fl6.saddr = np->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817

4c9483b2f   David S. Miller   ipv6: Convert to ...
818
  	final_p = fl6_update_dst(&fl6, opt, &final);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819

4c9483b2f   David S. Miller   ipv6: Convert to ...
820
821
822
  	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
  		fl6.flowi6_oif = np->mcast_oif;
  	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823

4c9483b2f   David S. Miller   ipv6: Convert to ...
824
  	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
68d0c6d34   David S. Miller   ipv6: Consolidate...
825
826
  	if (IS_ERR(dst)) {
  		err = PTR_ERR(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  		goto out;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
828
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  	if (hlimit < 0) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
830
  		if (ipv6_addr_is_multicast(&fl6.daddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
  			hlimit = np->mcast_hops;
  		else
  			hlimit = np->hop_limit;
  		if (hlimit < 0)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
835
  			hlimit = ip6_dst_hoplimit(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
  	}
e651f03af   Gerrit Renker   inet6: Conversion...
837
  	if (tclass < 0)
e012d51cb   YOSHIFUJI Hideaki   [IPV6]: Fix tclas...
838
  		tclass = np->tclass;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
839

13b52cd44   Brian Haley   IPv6: Add dontfra...
840
841
  	if (dontfrag < 0)
  		dontfrag = np->dontfrag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
845
  	if (msg->msg_flags&MSG_CONFIRM)
  		goto do_confirm;
  
  back_from_confirm:
1789a640f   Eric Dumazet   raw: avoid two at...
846
  	if (inet->hdrincl)
4c9483b2f   David S. Miller   ipv6: Convert to ...
847
  		err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags);
1789a640f   Eric Dumazet   raw: avoid two at...
848
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  		lock_sock(sk);
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
850
  		err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
4c9483b2f   David S. Miller   ipv6: Convert to ...
851
  			len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst,
13b52cd44   Brian Haley   IPv6: Add dontfra...
852
  			msg->msg_flags, dontfrag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
  
  		if (err)
  			ip6_flush_pending_frames(sk);
  		else if (!(msg->msg_flags & MSG_MORE))
4c9483b2f   David S. Miller   ipv6: Convert to ...
857
  			err = rawv6_push_pending_frames(sk, &fl6, rp);
3ef9d943d   YOSHIFUJI Hideaki   [IPV6]: Fix unbal...
858
  		release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  	}
  done:
6d3e85ecf   Nicolas DICHTEL   [IPV6] Don't stor...
861
  	dst_release(dst);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
862
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
866
867
868
869
870
871
  	fl6_sock_release(flowlabel);
  	return err<0?err:len;
  do_confirm:
  	dst_confirm(dst);
  	if (!(msg->msg_flags & MSG_PROBE) || len)
  		goto back_from_confirm;
  	err = 0;
  	goto done;
  }
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
872
  static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
878
879
880
881
882
883
  			       char __user *optval, int optlen)
  {
  	switch (optname) {
  	case ICMPV6_FILTER:
  		if (optlen > sizeof(struct icmp6_filter))
  			optlen = sizeof(struct icmp6_filter);
  		if (copy_from_user(&raw6_sk(sk)->filter, optval, optlen))
  			return -EFAULT;
  		return 0;
  	default:
  		return -ENOPROTOOPT;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
884
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
  
  	return 0;
  }
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
888
  static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
  			       char __user *optval, int __user *optlen)
  {
  	int len;
  
  	switch (optname) {
  	case ICMPV6_FILTER:
  		if (get_user(len, optlen))
  			return -EFAULT;
  		if (len < 0)
  			return -EINVAL;
  		if (len > sizeof(struct icmp6_filter))
  			len = sizeof(struct icmp6_filter);
  		if (put_user(len, optlen))
  			return -EFAULT;
  		if (copy_to_user(optval, &raw6_sk(sk)->filter, len))
  			return -EFAULT;
  		return 0;
  	default:
  		return -ENOPROTOOPT;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
908
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
  
  	return 0;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
912
  static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
913
  			    char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
  {
  	struct raw6_sock *rp = raw6_sk(sk);
  	int val;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
917
  	if (get_user(val, (int __user *)optval))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
  		return -EFAULT;
  
  	switch (optname) {
207ec0abb   Joe Perches   ipv6: Reduce swit...
921
922
923
924
925
926
927
928
929
930
931
932
933
  	case IPV6_CHECKSUM:
  		if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 &&
  		    level == IPPROTO_IPV6) {
  			/*
  			 * RFC3542 tells that IPV6_CHECKSUM socket
  			 * option in the IPPROTO_IPV6 level is not
  			 * allowed on ICMPv6 sockets.
  			 * If you want to set it, use IPPROTO_RAW
  			 * level IPV6_CHECKSUM socket option
  			 * (Linux extension).
  			 */
  			return -EINVAL;
  		}
1a98d05f5   YOSHIFUJI Hideaki   ipv6 RAW: Disallo...
934

207ec0abb   Joe Perches   ipv6: Reduce swit...
935
936
937
938
939
940
941
942
943
944
  		/* You may get strange result with a positive odd offset;
  		   RFC2292bis agrees with me. */
  		if (val > 0 && (val&1))
  			return -EINVAL;
  		if (val < 0) {
  			rp->checksum = 0;
  		} else {
  			rp->checksum = 1;
  			rp->offset = val;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945

207ec0abb   Joe Perches   ipv6: Reduce swit...
946
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

207ec0abb   Joe Perches   ipv6: Reduce swit...
948
949
  	default:
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
  	}
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
952
  static int rawv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
953
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
  {
207ec0abb   Joe Perches   ipv6: Reduce swit...
955
956
957
  	switch (level) {
  	case SOL_RAW:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958

207ec0abb   Joe Perches   ipv6: Reduce swit...
959
960
961
962
963
964
965
966
967
  	case SOL_ICMPV6:
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  			return -EOPNOTSUPP;
  		return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
  		if (optname == IPV6_CHECKSUM)
  			break;
  	default:
  		return ipv6_setsockopt(sk, level, optname, optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
968
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
969
970
971
972
973
  	return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
  }
  
  #ifdef CONFIG_COMPAT
  static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
974
  				   char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
975
  {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
976
977
978
979
  	switch (level) {
  	case SOL_RAW:
  		break;
  	case SOL_ICMPV6:
c720c7e83   Eric Dumazet   inet: rename some...
980
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
981
982
983
984
  			return -EOPNOTSUPP;
  		return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
  		if (optname == IPV6_CHECKSUM)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
985
  			break;
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
986
987
988
  	default:
  		return compat_ipv6_setsockopt(sk, level, optname,
  					      optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
989
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
990
991
992
993
994
995
996
997
998
  	return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
  }
  #endif
  
  static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
  			    char __user *optval, int __user *optlen)
  {
  	struct raw6_sock *rp = raw6_sk(sk);
  	int val, len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
1003
1004
  
  	if (get_user(len,optlen))
  		return -EFAULT;
  
  	switch (optname) {
  	case IPV6_CHECKSUM:
1a98d05f5   YOSHIFUJI Hideaki   ipv6 RAW: Disallo...
1005
1006
1007
1008
1009
  		/*
  		 * We allow getsockopt() for IPPROTO_IPV6-level
  		 * IPV6_CHECKSUM socket option on ICMPv6 sockets
  		 * since RFC3542 is silent about it.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
  		if (rp->checksum == 0)
  			val = -1;
  		else
  			val = rp->offset;
  		break;
  
  	default:
  		return -ENOPROTOOPT;
  	}
  
  	len = min_t(unsigned int, sizeof(int), len);
  
  	if (put_user(len, optlen))
  		return -EFAULT;
  	if (copy_to_user(optval,&val,len))
  		return -EFAULT;
  	return 0;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1028
1029
1030
  static int rawv6_getsockopt(struct sock *sk, int level, int optname,
  			  char __user *optval, int __user *optlen)
  {
207ec0abb   Joe Perches   ipv6: Reduce swit...
1031
1032
1033
  	switch (level) {
  	case SOL_RAW:
  		break;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1034

207ec0abb   Joe Perches   ipv6: Reduce swit...
1035
1036
1037
1038
1039
1040
1041
1042
1043
  	case SOL_ICMPV6:
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  			return -EOPNOTSUPP;
  		return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
  		if (optname == IPV6_CHECKSUM)
  			break;
  	default:
  		return ipv6_getsockopt(sk, level, optname, optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1044
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1045
1046
1047
1048
1049
  	return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
  }
  
  #ifdef CONFIG_COMPAT
  static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1050
  				   char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1051
  {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1052
1053
1054
1055
  	switch (level) {
  	case SOL_RAW:
  		break;
  	case SOL_ICMPV6:
c720c7e83   Eric Dumazet   inet: rename some...
1056
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1057
1058
1059
1060
  			return -EOPNOTSUPP;
  		return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
  		if (optname == IPV6_CHECKSUM)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1061
  			break;
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1062
1063
1064
  	default:
  		return compat_ipv6_getsockopt(sk, level, optname,
  					      optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1065
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1066
1067
1068
  	return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
  static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
207ec0abb   Joe Perches   ipv6: Reduce swit...
1071
1072
1073
  	switch (cmd) {
  	case SIOCOUTQ: {
  		int amount = sk_wmem_alloc_get(sk);
31e6d363a   Eric Dumazet   net: correct off-...
1074

207ec0abb   Joe Perches   ipv6: Reduce swit...
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  		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->tail - skb->transport_header;
  		spin_unlock_bh(&sk->sk_receive_queue.lock);
  		return put_user(amount, (int __user *)arg);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088

207ec0abb   Joe Perches   ipv6: Reduce swit...
1089
  	default:
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1090
  #ifdef CONFIG_IPV6_MROUTE
207ec0abb   Joe Perches   ipv6: Reduce swit...
1091
  		return ip6mr_ioctl(sk, cmd, (void __user *)arg);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1092
  #else
207ec0abb   Joe Perches   ipv6: Reduce swit...
1093
  		return -ENOIOCTLCMD;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1094
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
  	}
  }
e2d57766e   David S. Miller   net: Provide comp...
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  #ifdef CONFIG_COMPAT
  static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
  {
  	switch (cmd) {
  	case SIOCOUTQ:
  	case SIOCINQ:
  		return -ENOIOCTLCMD;
  	default:
  #ifdef CONFIG_IPV6_MROUTE
  		return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));
  #else
  		return -ENOIOCTLCMD;
  #endif
  	}
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
  static void rawv6_close(struct sock *sk, long timeout)
  {
c720c7e83   Eric Dumazet   inet: rename some...
1115
  	if (inet_sk(sk)->inet_num == IPPROTO_RAW)
725a8ff04   Denis V. Lunev   ipv6: remove unus...
1116
  		ip6_ra_control(sk, -1);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1117
  	ip6mr_sk_done(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
  	sk_common_release(sk);
  }
7d06b2e05   Brian Haley   net: change proto...
1120
  static void raw6_destroy(struct sock *sk)
22dd48502   Denis V. Lunev   raw: Raw socket l...
1121
1122
1123
1124
  {
  	lock_sock(sk);
  	ip6_flush_pending_frames(sk);
  	release_sock(sk);
f23d60de7   David S. Miller   ipv6: Fix duplica...
1125

7d06b2e05   Brian Haley   net: change proto...
1126
  	inet6_destroy_sock(sk);
22dd48502   Denis V. Lunev   raw: Raw socket l...
1127
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
  static int rawv6_init_sk(struct sock *sk)
  {
f48d5ff1e   Masahide NAKAMURA   [IPV6] RAW: Add c...
1130
  	struct raw6_sock *rp = raw6_sk(sk);
c720c7e83   Eric Dumazet   inet: rename some...
1131
  	switch (inet_sk(sk)->inet_num) {
f48d5ff1e   Masahide NAKAMURA   [IPV6] RAW: Add c...
1132
  	case IPPROTO_ICMPV6:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
  		rp->checksum = 1;
  		rp->offset   = 2;
f48d5ff1e   Masahide NAKAMURA   [IPV6] RAW: Add c...
1135
1136
1137
1138
1139
1140
1141
  		break;
  	case IPPROTO_MH:
  		rp->checksum = 1;
  		rp->offset   = 4;
  		break;
  	default:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	}
a02cec215   Eric Dumazet   net: return opera...
1143
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
1145
1146
  }
  
  struct proto rawv6_prot = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1147
1148
1149
  	.name		   = "RAWv6",
  	.owner		   = THIS_MODULE,
  	.close		   = rawv6_close,
22dd48502   Denis V. Lunev   raw: Raw socket l...
1150
  	.destroy	   = raw6_destroy,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1151
1152
1153
1154
  	.connect	   = ip6_datagram_connect,
  	.disconnect	   = udp_disconnect,
  	.ioctl		   = rawv6_ioctl,
  	.init		   = rawv6_init_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1155
1156
1157
1158
1159
1160
  	.setsockopt	   = rawv6_setsockopt,
  	.getsockopt	   = rawv6_getsockopt,
  	.sendmsg	   = rawv6_sendmsg,
  	.recvmsg	   = rawv6_recvmsg,
  	.bind		   = rawv6_bind,
  	.backlog_rcv	   = rawv6_rcv_skb,
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
1161
1162
  	.hash		   = raw_hash_sk,
  	.unhash		   = raw_unhash_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1163
  	.obj_size	   = sizeof(struct raw6_sock),
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
1164
  	.h.raw_hash	   = &raw_v6_hashinfo,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1165
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1166
1167
  	.compat_setsockopt = compat_rawv6_setsockopt,
  	.compat_getsockopt = compat_rawv6_getsockopt,
e2d57766e   David S. Miller   net: Provide comp...
1168
  	.compat_ioctl	   = compat_rawv6_ioctl,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1169
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
  };
  
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
1175
  static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
  {
  	struct ipv6_pinfo *np = inet6_sk(sp);
b71d1d426   Eric Dumazet   inet: constify ip...
1176
  	const struct in6_addr *dest, *src;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
1178
1179
1180
1181
  	__u16 destp, srcp;
  
  	dest  = &np->daddr;
  	src   = &np->rcv_saddr;
  	destp = 0;
c720c7e83   Eric Dumazet   inet: rename some...
1182
  	srcp  = inet_sk(sp)->inet_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
1184
  	seq_printf(seq,
  		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
71338aa7d   Dan Rosenberg   net: convert %p u...
1185
1186
  		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
1191
  		   i,
  		   src->s6_addr32[0], src->s6_addr32[1],
  		   src->s6_addr32[2], src->s6_addr32[3], srcp,
  		   dest->s6_addr32[0], dest->s6_addr32[1],
  		   dest->s6_addr32[2], dest->s6_addr32[3], destp,
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1192
  		   sp->sk_state,
31e6d363a   Eric Dumazet   net: correct off-...
1193
1194
  		   sk_wmem_alloc_get(sp),
  		   sk_rmem_alloc_get(sp),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
1197
  		   0, 0L, 0,
  		   sock_i_uid(sp), 0,
  		   sock_i_ino(sp),
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
1198
  		   atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  }
  
  static int raw6_seq_show(struct seq_file *seq, void *v)
  {
  	if (v == SEQ_START_TOKEN)
  		seq_printf(seq,
  			   "  sl  "
  			   "local_address                         "
  			   "remote_address                        "
  			   "st tx_queue rx_queue tr tm->when retrnsmt"
cb61cb9b8   Eric Dumazet   udp: sk_drops han...
1209
1210
  			   "   uid  timeout inode ref pointer drops
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
  	else
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1212
  		raw6_sock_seq_show(seq, v, raw_seq_private(seq)->bucket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
1214
  	return 0;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
1215
  static const struct seq_operations raw6_seq_ops = {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1216
1217
1218
  	.start =	raw_seq_start,
  	.next =		raw_seq_next,
  	.stop =		raw_seq_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
1221
1222
1223
  	.show =		raw6_seq_show,
  };
  
  static int raw6_seq_open(struct inode *inode, struct file *file)
  {
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
1224
  	return raw_seq_open(inode, file, &raw_v6_hashinfo, &raw6_seq_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
1226
  static const struct file_operations raw6_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
1229
1230
  	.owner =	THIS_MODULE,
  	.open =		raw6_seq_open,
  	.read =		seq_read,
  	.llseek =	seq_lseek,
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1231
  	.release =	seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
1233
  static int __net_init raw6_init_net(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
  {
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1235
  	if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
  		return -ENOMEM;
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1237

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
  	return 0;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1240
  static void __net_exit raw6_exit_net(struct net *net)
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  {
  	proc_net_remove(net, "raw6");
  }
  
  static struct pernet_operations raw6_net_ops = {
  	.init = raw6_init_net,
  	.exit = raw6_exit_net,
  };
  
  int __init raw6_proc_init(void)
  {
  	return register_pernet_subsys(&raw6_net_ops);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
  void raw6_proc_exit(void)
  {
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1256
  	unregister_pernet_subsys(&raw6_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
1258
  }
  #endif	/* CONFIG_PROC_FS */
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
  
  /* Same as inet6_dgram_ops, sans udp_poll.  */
  static const struct proto_ops inet6_sockraw_ops = {
  	.family		   = PF_INET6,
  	.owner		   = THIS_MODULE,
  	.release	   = inet6_release,
  	.bind		   = inet6_bind,
  	.connect	   = inet_dgram_connect,	/* ok		*/
  	.socketpair	   = sock_no_socketpair,	/* a do nothing	*/
  	.accept		   = sock_no_accept,		/* a do nothing	*/
  	.getname	   = inet6_getname,
  	.poll		   = datagram_poll,		/* ok		*/
  	.ioctl		   = inet6_ioctl,		/* must change  */
  	.listen		   = sock_no_listen,		/* ok		*/
  	.shutdown	   = inet_shutdown,		/* ok		*/
  	.setsockopt	   = sock_common_setsockopt,	/* ok		*/
  	.getsockopt	   = sock_common_getsockopt,	/* ok		*/
  	.sendmsg	   = inet_sendmsg,		/* ok		*/
  	.recvmsg	   = sock_common_recvmsg,	/* ok		*/
  	.mmap		   = sock_no_mmap,
  	.sendpage	   = sock_no_sendpage,
  #ifdef CONFIG_COMPAT
  	.compat_setsockopt = compat_sock_common_setsockopt,
  	.compat_getsockopt = compat_sock_common_getsockopt,
  #endif
  };
  
  static struct inet_protosw rawv6_protosw = {
  	.type		= SOCK_RAW,
  	.protocol	= IPPROTO_IP,	/* wild card */
  	.prot		= &rawv6_prot,
  	.ops		= &inet6_sockraw_ops,
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
  	.no_check	= UDP_CSUM_DEFAULT,
  	.flags		= INET_PROTOSW_REUSE,
  };
  
  int __init rawv6_init(void)
  {
  	int ret;
  
  	ret = inet6_register_protosw(&rawv6_protosw);
  	if (ret)
  		goto out;
  out:
  	return ret;
  }
09f7709f4   Daniel Lezcano   [IPV6]: fix secti...
1305
  void rawv6_exit(void)
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1306
1307
1308
  {
  	inet6_unregister_protosw(&rawv6_protosw);
  }