Blame view

net/ipv6/raw.c 31.6 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>
29778bec1   Alex W Slater   ipv6: Replace "#i...
35
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #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>
07a936260   Amerigo Wang   ipv6: use IS_ENAB...
52
  #if IS_ENABLED(CONFIG_IPV6_MIP6)
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

d1c53c8e8   Werner Almesberger   icmpv6_filter: al...
65
  #define	ICMPV6_HDRLEN	4	/* ICMPv6 header, RFC 4443 Section 2.1 */
432490f9d   Cyrill Gorcunov   net: ip, diag -- ...
66
  struct raw_hashinfo raw_v6_hashinfo = {
938b93adb   Robert P. J. Day   [NET]: Add debugg...
67
  	.lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock),
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
68
  };
432490f9d   Cyrill Gorcunov   net: ip, diag -- ...
69
  EXPORT_SYMBOL_GPL(raw_v6_hashinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

432490f9d   Cyrill Gorcunov   net: ip, diag -- ...
71
  struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
b71d1d426   Eric Dumazet   inet: constify ip...
72
  		unsigned short num, const struct in6_addr *loc_addr,
5108ab4bf   David Ahern   net: ipv6: add se...
73
  		const struct in6_addr *rmt_addr, int dif, int sdif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  {
a50feda54   Eric Dumazet   ipv6: bool/const ...
75
  	bool is_multicast = ipv6_addr_is_multicast(loc_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

b67bfe0d4   Sasha Levin   hlist: drop the n...
77
  	sk_for_each_from(sk)
c720c7e83   Eric Dumazet   inet: rename some...
78
  		if (inet_sk(sk)->inet_num == num) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
80
  			if (!net_eq(sock_net(sk), net))
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
81
  				continue;
efe4208f4   Eric Dumazet   ipv6: make lookup...
82
83
  			if (!ipv6_addr_any(&sk->sk_v6_daddr) &&
  			    !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  				continue;
5108ab4bf   David Ahern   net: ipv6: add se...
85
86
87
  			if (sk->sk_bound_dev_if &&
  			    sk->sk_bound_dev_if != dif &&
  			    sk->sk_bound_dev_if != sdif)
0bd1b59b1   Andrew McDonald   [IPV6]: Check int...
88
  				continue;
efe4208f4   Eric Dumazet   ipv6: make lookup...
89
90
  			if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
  				if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
  					goto found;
  				if (is_multicast &&
  				    inet6_mc_check(sk, loc_addr, rmt_addr))
  					goto found;
  				continue;
  			}
  			goto found;
  		}
  	sk = NULL;
  found:
  	return sk;
  }
432490f9d   Cyrill Gorcunov   net: ip, diag -- ...
103
  EXPORT_SYMBOL_GPL(__raw_v6_lookup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
  
  /*
   *	0 - deliver
   *	1 - block
   */
1b05c4b50   Eric Dumazet   ipv6: raw: fix ic...
109
  static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  {
9cc08af3a   Werner Almesberger   icmpv6_filter: fi...
111
  	struct icmp6hdr _hdr;
1b05c4b50   Eric Dumazet   ipv6: raw: fix ic...
112
  	const struct icmp6hdr *hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

d1c53c8e8   Werner Almesberger   icmpv6_filter: al...
114
115
116
  	/* We require only the four bytes of the ICMPv6 header, not any
  	 * additional bytes of message body in "struct icmp6hdr".
  	 */
1b05c4b50   Eric Dumazet   ipv6: raw: fix ic...
117
  	hdr = skb_header_pointer(skb, skb_transport_offset(skb),
d1c53c8e8   Werner Almesberger   icmpv6_filter: al...
118
  				 ICMPV6_HDRLEN, &_hdr);
1b05c4b50   Eric Dumazet   ipv6: raw: fix ic...
119
120
121
  	if (hdr) {
  		const __u32 *data = &raw6_sk(sk)->filter.data[0];
  		unsigned int type = hdr->icmp6_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

1b05c4b50   Eric Dumazet   ipv6: raw: fix ic...
123
  		return (data[type >> 5] & (1U << (type & 31))) != 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  	}
1b05c4b50   Eric Dumazet   ipv6: raw: fix ic...
125
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  }
07a936260   Amerigo Wang   ipv6: use IS_ENAB...
127
  #if IS_ENABLED(CONFIG_IPV6_MIP6)
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
128
  typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
129

f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
130
131
132
  static mh_filter_t __rcu *mh_filter __read_mostly;
  
  int rawv6_mh_filter_register(mh_filter_t filter)
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
133
  {
cf778b00e   Eric Dumazet   net: reintroduce ...
134
  	rcu_assign_pointer(mh_filter, filter);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
135
136
137
  	return 0;
  }
  EXPORT_SYMBOL(rawv6_mh_filter_register);
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
138
  int rawv6_mh_filter_unregister(mh_filter_t filter)
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
139
  {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
140
  	RCU_INIT_POINTER(mh_filter, NULL);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
141
142
143
144
145
146
  	synchronize_rcu();
  	return 0;
  }
  EXPORT_SYMBOL(rawv6_mh_filter_unregister);
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
  /*
   *	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.
   */
a50feda54   Eric Dumazet   ipv6: bool/const ...
154
  static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  {
b71d1d426   Eric Dumazet   inet: constify ip...
156
157
  	const struct in6_addr *saddr;
  	const struct in6_addr *daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	struct sock *sk;
a50feda54   Eric Dumazet   ipv6: bool/const ...
159
  	bool delivered = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  	__u8 hash;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
161
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
163
  	saddr = &ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  	daddr = saddr + 1;
f9242b6b2   David S. Miller   inet: Sanitize in...
165
  	hash = nexthdr & (RAW_HTABLE_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
167
168
  	read_lock(&raw_v6_hashinfo.lock);
  	sk = sk_head(&raw_v6_hashinfo.ht[hash]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

63159f29b   Ian Morris   ipv6: coding styl...
170
  	if (!sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		goto out;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
172
  	net = dev_net(skb->dev);
5108ab4bf   David Ahern   net: ipv6: add se...
173
174
  	sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr,
  			     inet6_iif(skb), inet6_sdif(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
  
  	while (sk) {
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
177
  		int filtered;
a50feda54   Eric Dumazet   ipv6: bool/const ...
178
  		delivered = true;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
179
180
181
182
  		switch (nexthdr) {
  		case IPPROTO_ICMPV6:
  			filtered = icmpv6_filter(sk, skb);
  			break;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
183

07a936260   Amerigo Wang   ipv6: use IS_ENAB...
184
  #if IS_ENABLED(CONFIG_IPV6_MIP6)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
185
  		case IPPROTO_MH:
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
186
  		{
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
187
188
189
190
191
192
  			/* 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...
193
  			mh_filter_t *filter;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
194
195
  
  			filter = rcu_dereference(mh_filter);
f2eda47df   Eric Dumazet   ipv6: raw: rcu an...
196
  			filtered = filter ? (*filter)(sk, skb) : 0;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
197
  			break;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
198
  		}
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
199
200
201
202
203
204
205
206
207
  #endif
  		default:
  			filtered = 0;
  			break;
  		}
  
  		if (filtered < 0)
  			break;
  		if (filtered == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
  
  			/* Not releasing hash table! */
9fb9cbb10   Yasuyuki Kozakai   [NETFILTER]: Add ...
211
212
  			if (clone) {
  				nf_reset(clone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  				rawv6_rcv(sk, clone);
9fb9cbb10   Yasuyuki Kozakai   [NETFILTER]: Add ...
214
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  		}
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
216
  		sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr,
5108ab4bf   David Ahern   net: ipv6: add se...
217
  				     inet6_iif(skb), inet6_sdif(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  	}
  out:
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
220
  	read_unlock(&raw_v6_hashinfo.lock);
d13964f44   Patrick McHardy   [IPV4/6]: Check i...
221
  	return delivered;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  }
a50feda54   Eric Dumazet   ipv6: bool/const ...
223
  bool raw6_local_deliver(struct sk_buff *skb, int nexthdr)
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
224
225
  {
  	struct sock *raw_sk;
f9242b6b2   David S. Miller   inet: Sanitize in...
226
  	raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
227
228
229
230
231
  	if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
  		raw_sk = NULL;
  
  	return raw_sk != NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
  /* 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...
238
  	__be32 v4addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
  	int addr_type;
  	int err;
  
  	if (addr_len < SIN6_LEN_RFC2133)
  		return -EINVAL;
82b276cd2   Hannes Frederic Sowa   ipv6: protect pro...
244
245
246
  
  	if (addr->sin6_family != AF_INET6)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
  	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...
251
  		return -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
  
  	lock_sock(sk);
  
  	err = -EINVAL;
  	if (sk->sk_state != TCP_CLOSE)
  		goto out;
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
258
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
  	/* Check if the address belongs to the host. */
  	if (addr_type != IPV6_ADDR_ANY) {
  		struct net_device *dev = NULL;
842df0739   Hannes Frederic Sowa   ipv6: use newly i...
262
  		if (__ipv6_addr_needs_scope_id(addr_type)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
  			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...
270

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

fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
275
276
277
278
279
  			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
280
  		}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
281

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
  		/* ipv4 addr of the socket is invalid.  Only the
  		 * unspecified and mapped address have a v4 equivalent.
  		 */
  		v4addr = LOOPBACK4_IPV6;
35a256fee   Tom Herbert   ipv6: Nonlocal bind
286
287
  		if (!(addr_type & IPV6_ADDR_MULTICAST) &&
  		    !sock_net(sk)->ipv6.sysctl.ip_nonlocal_bind) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  			err = -EADDRNOTAVAIL;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
289
  			if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
bfeade087   Daniel Lezcano   [NETNS][IPV6]: in...
290
  					   dev, 0)) {
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
291
  				goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  	}
c720c7e83   Eric Dumazet   inet: rename some...
295
  	inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
efe4208f4   Eric Dumazet   ipv6: make lookup...
296
  	sk->sk_v6_rcv_saddr = addr->sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	if (!(addr_type & IPV6_ADDR_MULTICAST))
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
298
  		np->saddr = addr->sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	err = 0;
fd5c00276   Eric Dumazet   ipv6: avoid dev_h...
300
301
  out_unlock:
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
  out:
  	release_sock(sk);
  	return err;
  }
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
306
  static void rawv6_err(struct sock *sk, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  	       struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
308
  	       u8 type, u8 code, int offset, __be32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  {
  	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);
81aded246   David S. Miller   ipv6: Handle PMTU...
324
325
  	if (type == ICMPV6_PKT_TOOBIG) {
  		ip6_sk_update_pmtu(skb, sk, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  		harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
81aded246   David S. Miller   ipv6: Handle PMTU...
327
  	}
8d65b1190   Duan Jiong   net: raw: do not ...
328
  	if (type == NDISC_REDIRECT) {
ec18d9a26   David S. Miller   ipv6: Add redirec...
329
  		ip6_sk_redirect(skb, sk);
8d65b1190   Duan Jiong   net: raw: do not ...
330
331
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
339
340
341
342
343
  	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...
344
  void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
d5fdd6bab   Brian Haley   ipv6: Use correct...
345
  		u8 type, u8 code, int inner_offset, __be32 info)
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
346
347
348
  {
  	struct sock *sk;
  	int hash;
b71d1d426   Eric Dumazet   inet: constify ip...
349
  	const struct in6_addr *saddr, *daddr;
be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
350
  	struct net *net;
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
351

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

b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
354
355
  	read_lock(&raw_v6_hashinfo.lock);
  	sk = sk_head(&raw_v6_hashinfo.ht[hash]);
53b24b8f9   Ian Morris   ipv6: coding styl...
356
  	if (sk) {
05f175cdc   YOSHIFUJI Hideaki   [IPV6]: Fix IPV6_...
357
  		/* Note: ipv6_hdr(skb) != skb->data */
b71d1d426   Eric Dumazet   inet: constify ip...
358
  		const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
05f175cdc   YOSHIFUJI Hideaki   [IPV6]: Fix IPV6_...
359
360
  		saddr = &ip6h->saddr;
  		daddr = &ip6h->daddr;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
361
  		net = dev_net(skb->dev);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
362

be185884b   Pavel Emelyanov   [NETNS][RAW]: Mak...
363
  		while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr,
5108ab4bf   David Ahern   net: ipv6: add se...
364
  					     inet6_iif(skb), inet6_iif(skb)))) {
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
365
366
367
368
369
  			rawv6_err(sk, skb, NULL, type, code,
  					inner_offset, info);
  			sk = sk_next(sk);
  		}
  	}
b673e4dfc   Pavel Emelyanov   [RAW]: Introduce ...
370
  	read_unlock(&raw_v6_hashinfo.lock);
69d6da0b0   Pavel Emelyanov   [IPv6] RAW: Compa...
371
  }
33d480ce6   Eric Dumazet   net: cleanup some...
372
  static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  {
33d480ce6   Eric Dumazet   net: cleanup some...
374
  	if ((raw6_sk(sk)->checksum || rcu_access_pointer(sk->sk_filter)) &&
fb286bb29   Herbert Xu   [NET]: Detect har...
375
  	    skb_checksum_complete(skb)) {
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
376
  		atomic_inc(&sk->sk_drops);
fb286bb29   Herbert Xu   [NET]: Detect har...
377
  		kfree_skb(skb);
3cc76caa9   Yang Hongyang   ipv6: When we dro...
378
  		return NET_RX_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
  	}
  
  	/* Charge it to the socket. */
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
382
383
  	skb_dst_drop(skb);
  	if (sock_queue_rcv_skb(sk, skb) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  		kfree_skb(skb);
3cc76caa9   Yang Hongyang   ipv6: When we dro...
385
  		return NET_RX_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
389
390
391
  	}
  
  	return 0;
  }
  
  /*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
392
   *	This is next to useless...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
   *	if we demultiplex in network layer we don't need the extra call
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
394
395
   *	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
396
397
398
399
400
401
   *	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...
402
  	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) {
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
403
  		atomic_inc(&sk->sk_drops);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
404
405
406
  		kfree_skb(skb);
  		return NET_RX_DROP;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  
  	if (!rp->checksum)
  		skb->ip_summed = CHECKSUM_UNNECESSARY;
84fa7933a   Patrick McHardy   [NET]: Replace CH...
410
  	if (skb->ip_summed == CHECKSUM_COMPLETE) {
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
411
  		skb_postpull_rcsum(skb, skb_network_header(skb),
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
412
  				   skb_network_header_len(skb));
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
413
414
  		if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
  				     &ipv6_hdr(skb)->daddr,
c720c7e83   Eric Dumazet   inet: rename some...
415
  				     skb->len, inet->inet_num, skb->csum))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  			skb->ip_summed = CHECKSUM_UNNECESSARY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  	}
604763722   Herbert Xu   [NET]: Treat CHEC...
418
  	if (!skb_csum_unnecessary(skb))
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
419
420
421
  		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
  							 &ipv6_hdr(skb)->daddr,
  							 skb->len,
c720c7e83   Eric Dumazet   inet: rename some...
422
  							 inet->inet_num, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
  
  	if (inet->hdrincl) {
fb286bb29   Herbert Xu   [NET]: Detect har...
425
  		if (skb_checksum_complete(skb)) {
a92aa318b   Wang Chen   [IPV6]: Add raw6 ...
426
  			atomic_inc(&sk->sk_drops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  			kfree_skb(skb);
3cc76caa9   Yang Hongyang   ipv6: When we dro...
428
  			return NET_RX_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
439
440
  	}
  
  	rawv6_rcv_skb(sk, skb);
  	return 0;
  }
  
  
  /*
   *	This should be easy, if there is something there
   *	we return it, otherwise we block.
   */
1b7841404   Ying Xue   net: Remove iocb ...
441
442
  static int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
  			 int noblock, int flags, int *addr_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
342dfc306   Steffen Hurrle   net: add build-ti...
445
  	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
451
  	struct sk_buff *skb;
  	size_t copied;
  	int err;
  
  	if (flags & MSG_OOB)
  		return -EOPNOTSUPP;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
452

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  	if (flags & MSG_ERRQUEUE)
85fbaa750   Hannes Frederic Sowa   inet: fix addr_le...
454
  		return ipv6_recv_error(sk, msg, len, addr_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455

4b340ae20   Brian Haley   IPv6: Complete IP...
456
  	if (np->rxpmtu && np->rxopt.bits.rxpmtu)
85fbaa750   Hannes Frederic Sowa   inet: fix addr_le...
457
  		return ipv6_recv_rxpmtu(sk, msg, len, addr_len);
4b340ae20   Brian Haley   IPv6: Complete IP...
458

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
  	skb = skb_recv_datagram(sk, flags, noblock, &err);
  	if (!skb)
  		goto out;
  
  	copied = skb->len;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
464
465
466
467
  	if (copied > len) {
  		copied = len;
  		msg->msg_flags |= MSG_TRUNC;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468

604763722   Herbert Xu   [NET]: Treat CHEC...
469
  	if (skb_csum_unnecessary(skb)) {
51f3d02b9   David S. Miller   net: Add and use ...
470
  		err = skb_copy_datagram_msg(skb, 0, msg, copied);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  	} else if (msg->msg_flags&MSG_TRUNC) {
fb286bb29   Herbert Xu   [NET]: Detect har...
472
  		if (__skb_checksum_complete(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  			goto csum_copy_err;
51f3d02b9   David S. Miller   net: Add and use ...
474
  		err = skb_copy_datagram_msg(skb, 0, msg, copied);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  	} else {
227158db1   Al Viro   new helper: skb_c...
476
  		err = skb_copy_and_csum_datagram_msg(skb, 0, msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
  		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...
486
  		sin6->sin6_port = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
487
  		sin6->sin6_addr = ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  		sin6->sin6_flowinfo = 0;
842df0739   Hannes Frederic Sowa   ipv6: use newly i...
489
  		sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
4330487ac   Duan Jiong   net: use inet6_ii...
490
  							  inet6_iif(skb));
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
491
  		*addr_len = sizeof(*sin6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  	}
3b885787e   Neil Horman   net: Generalize s...
493
  	sock_recv_ts_and_drops(msg, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
  
  	if (np->rxopt.all)
73df66f8b   Tom Parkin   ipv6: rename data...
496
  		ip6_datagram_recv_ctl(sk, msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
504
505
506
507
  
  	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...
508
  	skb_kill_datagram(sk, skb, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
  
  	/* Error for blocking case is chosen to masquerade
  	   as some normal condition.
  	 */
  	err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
3305b80c2   Herbert Xu   [IP]: Simplify an...
514
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  }
4c9483b2f   David S. Miller   ipv6: Convert to ...
516
  static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
517
  				     struct raw6_sock *rp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
  {
  	struct sk_buff *skb;
  	int err = 0;
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
521
522
  	int offset;
  	int len;
679a87382   Herbert Xu   [IPV6]: Fix raw s...
523
  	int total_len;
868c86bcb   Al Viro   [NET]: annotate c...
524
525
  	__wsum tmp_csum;
  	__sum16 csum;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
  
  	if (!rp->checksum)
  		goto send;
43728fa5c   Fabian Frederick   ipv6: remove assi...
529
530
  	skb = skb_peek(&sk->sk_write_queue);
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  		goto out;
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
532
  	offset = rp->offset;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
533
  	total_len = inet_sk(sk)->cork.base.length;
679a87382   Herbert Xu   [IPV6]: Fix raw s...
534
  	if (offset >= total_len - 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  		err = -EINVAL;
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
536
  		ip6_flush_pending_frames(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
542
543
544
545
546
  		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...
547
  		struct sk_buff *csum_skb = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
  		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...
552
553
554
  
  			if (csum_skb)
  				continue;
ea2ae17d6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
555
  			len = skb->len - skb_transport_offset(skb);
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
556
557
558
559
560
561
  			if (offset >= len) {
  				offset -= len;
  				continue;
  			}
  
  			csum_skb = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
  		}
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
563
564
  
  		skb = csum_skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
  	}
ea2ae17d6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
566
  	offset += skb_transport_offset(skb);
a98f91758   Dave Jones   ipv6: handle -EFA...
567
568
569
570
571
  	err = skb_copy_bits(skb, offset, &csum, 2);
  	if (err < 0) {
  		ip6_flush_pending_frames(sk);
  		goto out;
  	}
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
572

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	/* in case cksum was not initialized */
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
574
  	if (unlikely(csum))
5f92a7388   Al Viro   [NET]: Annotate c...
575
  		tmp_csum = csum_sub(tmp_csum, csum_unfold(csum));
357b40a18   Herbert Xu   [IPV6]: IPV6_CHEC...
576

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

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

8242fc339   Himangi Saraogi   net: ipv6: Use BU...
583
  	BUG_ON(skb_store_bits(skb, offset, &csum, 2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
  send:
  	err = ip6_push_pending_frames(sk);
  out:
  	return err;
  }
c3c1a7dbe   Al Viro   ipv6: rawv6_send_...
590
  static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
4c9483b2f   David S. Miller   ipv6: Convert to ...
591
  			struct flowi6 *fl6, struct dst_entry **dstp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
  			unsigned int flags)
  {
3320da890   Herbert Xu   [IPV6]: Replace b...
594
  	struct ipv6_pinfo *np = inet6_sk(sk);
adb28c9d3   Eric W. Biederman   ipv6: Compute net...
595
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
  	struct ipv6hdr *iph;
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  	int err;
1789a640f   Eric Dumazet   raw: avoid two at...
599
  	struct rt6_info *rt = (struct rt6_info *)*dstp;
a7ae19922   Herbert Xu   ipv6: Remove all ...
600
601
  	int hlen = LL_RESERVED_SPACE(rt->dst.dev);
  	int tlen = rt->dst.dev->needed_tailroom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602

d8d1f30b9   Changli Gao   net-next: remove ...
603
  	if (length > rt->dst.dev->mtu) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
604
  		ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  		return -EMSGSIZE;
  	}
86f4c90a1   Alexander Potapenko   ipv4, ipv6: ensur...
607
608
  	if (length < sizeof(struct ipv6hdr))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  	if (flags&MSG_PROBE)
  		goto out;
f5184d267   Johannes Berg   net: Allow netdev...
611
  	skb = sock_alloc_send_skb(sk,
a7ae19922   Herbert Xu   ipv6: Remove all ...
612
  				  length + hlen + tlen + 15,
f5184d267   Johannes Berg   net: Allow netdev...
613
  				  flags & MSG_DONTWAIT, &err);
63159f29b   Ian Morris   ipv6: coding styl...
614
  	if (!skb)
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
615
  		goto error;
a7ae19922   Herbert Xu   ipv6: Remove all ...
616
  	skb_reserve(skb, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617

9c9c9ad5f   Hannes Frederic Sowa   ipv6: set skb->pr...
618
  	skb->protocol = htons(ETH_P_IPV6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
620
  	skb->mark = sk->sk_mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

1ced98e81   Arnaldo Carvalho de Melo   [SK_BUFF] ipv6: M...
622
623
  	skb_put(skb, length);
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
624
  	iph = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
  
  	skb->ip_summed = CHECKSUM_NONE;
0dec879f6   Julian Anastasov   net: use dst_conf...
627
628
  	if (flags & MSG_CONFIRM)
  		skb_set_dst_pending_confirm(skb, 1);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
629
  	skb->transport_header = skb->network_header;
21226abb4   Al Viro   net: switch memcp...
630
  	err = memcpy_from_msg(iph, msg, length);
48c14f2ea   Wei Wang   ipv6: take rcu lo...
631
632
633
634
635
636
637
638
  	if (err) {
  		err = -EFAULT;
  		kfree_skb(skb);
  		goto error;
  	}
  
  	skb_dst_set(skb, &rt->dst);
  	*dstp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639

a8e3e1a9f   David Ahern   net: l3mdev: Add ...
640
641
642
643
644
645
  	/* if egress device is enslaved to an L3 master device pass the
  	 * skb to its handler for processing
  	 */
  	skb = l3mdev_ip6_out(sk, skb);
  	if (unlikely(!skb))
  		return 0;
48c14f2ea   Wei Wang   ipv6: take rcu lo...
646
647
648
649
650
  	/* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev
  	 * in the error path. Since skb has been freed, the dst could
  	 * have been queued for deletion.
  	 */
  	rcu_read_lock();
adb28c9d3   Eric W. Biederman   ipv6: Compute net...
651
  	IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
29a26a568   Eric W. Biederman   netfilter: Pass s...
652
  	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb,
13206b6bf   Eric W. Biederman   net: Pass net int...
653
  		      NULL, rt->dst.dev, dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
655
  		err = net_xmit_errno(err);
48c14f2ea   Wei Wang   ipv6: take rcu lo...
656
657
658
659
660
661
  	if (err) {
  		IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
  		rcu_read_unlock();
  		goto error_check;
  	}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
  out:
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  error:
adb28c9d3   Eric W. Biederman   ipv6: Compute net...
665
  	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
48c14f2ea   Wei Wang   ipv6: take rcu lo...
666
  error_check:
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
667
668
  	if (err == -ENOBUFS && !np->recverr)
  		err = 0;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
669
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  }
19e3c66b5   Al Viro   ipv6 equivalent o...
671
672
673
674
675
676
677
  struct raw6_frag_vec {
  	struct msghdr *msg;
  	int hlen;
  	char c[4];
  };
  
  static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  {
19e3c66b5   Al Viro   ipv6 equivalent o...
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  	int err = 0;
  	switch (fl6->flowi6_proto) {
  	case IPPROTO_ICMPV6:
  		rfv->hlen = 2;
  		err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
  		if (!err) {
  			fl6->fl6_icmp_type = rfv->c[0];
  			fl6->fl6_icmp_code = rfv->c[1];
  		}
  		break;
  	case IPPROTO_MH:
  		rfv->hlen = 4;
  		err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
  		if (!err)
  			fl6->fl6_mh_type = rfv->c[2];
  	}
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697

19e3c66b5   Al Viro   ipv6 equivalent o...
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
  static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
  		       struct sk_buff *skb)
  {
  	struct raw6_frag_vec *rfv = from;
  
  	if (offset < rfv->hlen) {
  		int copy = min(rfv->hlen - offset, len);
  
  		if (skb->ip_summed == CHECKSUM_PARTIAL)
  			memcpy(to, rfv->c + offset, copy);
  		else
  			skb->csum = csum_block_add(
  				skb->csum,
  				csum_partial_copy_nocheck(rfv->c + offset,
  							  to, copy, 0),
  				odd);
  
  		odd = 0;
  		offset += copy;
  		to += copy;
  		len -= copy;
  
  		if (!len)
  			return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723

19e3c66b5   Al Viro   ipv6 equivalent o...
724
  	offset -= rfv->hlen;
6e8f4d48b   Masahide NAKAMURA   [IPV6] MIP6: Add ...
725

f69e6d131   Al Viro   ip_generic_getfra...
726
  	return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  }
1b7841404   Ying Xue   net: Remove iocb ...
728
  static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  {
45f6fad84   Eric Dumazet   ipv6: add complet...
730
  	struct ipv6_txoptions *opt_to_free = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	struct ipv6_txoptions opt_space;
342dfc306   Steffen Hurrle   net: add build-ti...
732
  	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
20c59de2e   Arnaud Ebalard   ipv6: Refactor up...
733
  	struct in6_addr *daddr, *final_p, final;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
739
  	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;
19e3c66b5   Al Viro   ipv6 equivalent o...
740
  	struct raw6_frag_vec rfv;
4c9483b2f   David S. Miller   ipv6: Convert to ...
741
  	struct flowi6 fl6;
ad1e46a83   Soheil Hassas Yeganeh   ipv6: process soc...
742
  	struct sockcm_cookie sockc;
26879da58   Wei Wang   ipv6: add new str...
743
  	struct ipcm6_cookie ipc6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  	int addr_len = msg->msg_namelen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
748
  	u16 proto;
  	int err;
  
  	/* Rough check on arithmetic overflow,
b59e139bb   YOSHIFUJI Hideaki   [IPv6]: Fix incor...
749
  	   better check is made in ip6_append_data().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  	 */
b59e139bb   YOSHIFUJI Hideaki   [IPv6]: Fix incor...
751
  	if (len > INT_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
  		return -EMSGSIZE;
  
  	/* Mirror BSD error message compatibility */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
755
  	if (msg->msg_flags & MSG_OOB)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
  		return -EOPNOTSUPP;
  
  	/*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
759
  	 *	Get and verify the address.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  	 */
4c9483b2f   David S. Miller   ipv6: Convert to ...
761
  	memset(&fl6, 0, sizeof(fl6));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762

4c9483b2f   David S. Miller   ipv6: Convert to ...
763
  	fl6.flowi6_mark = sk->sk_mark;
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
764
  	fl6.flowi6_uid = sk->sk_uid;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
765

26879da58   Wei Wang   ipv6: add new str...
766
767
768
769
  	ipc6.hlimit = -1;
  	ipc6.tclass = -1;
  	ipc6.dontfrag = -1;
  	ipc6.opt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	if (sin6) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
771
  		if (addr_len < SIN6_LEN_RFC2133)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  			return -EINVAL;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
773
  		if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
a02cec215   Eric Dumazet   net: return opera...
774
  			return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
  
  		/* port is the proto value [0..255] carried in nexthdr */
  		proto = ntohs(sin6->sin6_port);
  
  		if (!proto)
c720c7e83   Eric Dumazet   inet: rename some...
780
781
  			proto = inet->inet_num;
  		else if (proto != inet->inet_num)
a02cec215   Eric Dumazet   net: return opera...
782
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  
  		if (proto > 255)
a02cec215   Eric Dumazet   net: return opera...
785
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
  
  		daddr = &sin6->sin6_addr;
  		if (np->sndflow) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
789
790
791
  			fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
  			if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
  				flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
63159f29b   Ian Morris   ipv6: coding styl...
792
  				if (!flowlabel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  					return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
798
799
800
801
  			}
  		}
  
  		/*
  		 * Otherwise it will be difficult to maintain
  		 * sk->sk_dst_cache.
  		 */
  		if (sk->sk_state == TCP_ESTABLISHED &&
efe4208f4   Eric Dumazet   ipv6: make lookup...
802
803
  		    ipv6_addr_equal(daddr, &sk->sk_v6_daddr))
  			daddr = &sk->sk_v6_daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
  
  		if (addr_len >= sizeof(struct sockaddr_in6) &&
  		    sin6->sin6_scope_id &&
842df0739   Hannes Frederic Sowa   ipv6: use newly i...
807
  		    __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
4c9483b2f   David S. Miller   ipv6: Convert to ...
808
  			fl6.flowi6_oif = sin6->sin6_scope_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  	} else {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
810
  		if (sk->sk_state != TCP_ESTABLISHED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  			return -EDESTADDRREQ;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
812

c720c7e83   Eric Dumazet   inet: rename some...
813
  		proto = inet->inet_num;
efe4208f4   Eric Dumazet   ipv6: make lookup...
814
  		daddr = &sk->sk_v6_daddr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
815
  		fl6.flowlabel = np->flow_label;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
817
818
  	if (fl6.flowi6_oif == 0)
  		fl6.flowi6_oif = sk->sk_bound_dev_if;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819

c14ac9451   Soheil Hassas Yeganeh   sock: enable time...
820
  	sockc.tsflags = sk->sk_tsflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
823
824
  	if (msg->msg_controllen) {
  		opt = &opt_space;
  		memset(opt, 0, sizeof(struct ipv6_txoptions));
  		opt->tot_len = sizeof(struct ipv6_txoptions);
26879da58   Wei Wang   ipv6: add new str...
825
  		ipc6.opt = opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826

26879da58   Wei Wang   ipv6: add new str...
827
  		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
830
831
  		if (err < 0) {
  			fl6_sock_release(flowlabel);
  			return err;
  		}
4c9483b2f   David S. Miller   ipv6: Convert to ...
832
833
  		if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
  			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
63159f29b   Ian Morris   ipv6: coding styl...
834
  			if (!flowlabel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
839
  				return -EINVAL;
  		}
  		if (!(opt->opt_nflen|opt->opt_flen))
  			opt = NULL;
  	}
45f6fad84   Eric Dumazet   ipv6: add complet...
840
841
842
  	if (!opt) {
  		opt = txopt_get(np);
  		opt_to_free = opt;
26879da58   Wei Wang   ipv6: add new str...
843
  	}
df9890c31   YOSHIFUJI Hideaki   [IPV6]: Fix sendi...
844
845
846
  	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
847

4c9483b2f   David S. Miller   ipv6: Convert to ...
848
  	fl6.flowi6_proto = proto;
19e3c66b5   Al Viro   ipv6 equivalent o...
849
850
851
  	rfv.msg = msg;
  	rfv.hlen = 0;
  	err = rawv6_probe_proto_opt(&rfv, &fl6);
a27b58fed   Heiko Carstens   [NET]: fix uacces...
852
853
  	if (err)
  		goto out;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
854

876c7f419   Brian Haley   [IPv6]: Change IP...
855
  	if (!ipv6_addr_any(daddr))
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
856
  		fl6.daddr = *daddr;
876c7f419   Brian Haley   [IPv6]: Change IP...
857
  	else
4c9483b2f   David S. Miller   ipv6: Convert to ...
858
859
  		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_...
860
  		fl6.saddr = np->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861

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

4c9483b2f   David S. Miller   ipv6: Convert to ...
864
865
  	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
  		fl6.flowi6_oif = np->mcast_oif;
c4062dfc4   Erich E. Hoover   ipv6: Implement I...
866
867
  	else if (!fl6.flowi6_oif)
  		fl6.flowi6_oif = np->ucast_oif;
4c9483b2f   David S. Miller   ipv6: Convert to ...
868
  	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869

48e8aa6e3   Martin KaFai Lau   ipv6: Set FLOWI_F...
870
871
  	if (inet->hdrincl)
  		fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH;
38b7097b5   Hannes Frederic Sowa   ipv6: use TOS mar...
872
873
874
875
  	if (ipc6.tclass < 0)
  		ipc6.tclass = np->tclass;
  
  	fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
0e0d44ab4   Steffen Klassert   net: Remove FLOWI...
876
  	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
68d0c6d34   David S. Miller   ipv6: Consolidate...
877
878
  	if (IS_ERR(dst)) {
  		err = PTR_ERR(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  		goto out;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
880
  	}
26879da58   Wei Wang   ipv6: add new str...
881
882
  	if (ipc6.hlimit < 0)
  		ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883

26879da58   Wei Wang   ipv6: add new str...
884
885
  	if (ipc6.dontfrag < 0)
  		ipc6.dontfrag = np->dontfrag;
13b52cd44   Brian Haley   IPv6: Add dontfra...
886

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
888
889
890
  	if (msg->msg_flags&MSG_CONFIRM)
  		goto do_confirm;
  
  back_from_confirm:
1789a640f   Eric Dumazet   raw: avoid two at...
891
  	if (inet->hdrincl)
c3c1a7dbe   Al Viro   ipv6: rawv6_send_...
892
  		err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst, msg->msg_flags);
1789a640f   Eric Dumazet   raw: avoid two at...
893
  	else {
26879da58   Wei Wang   ipv6: add new str...
894
  		ipc6.opt = opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  		lock_sock(sk);
19e3c66b5   Al Viro   ipv6 equivalent o...
896
  		err = ip6_append_data(sk, raw6_getfrag, &rfv,
26879da58   Wei Wang   ipv6: add new str...
897
898
  			len, 0, &ipc6, &fl6, (struct rt6_info *)dst,
  			msg->msg_flags, &sockc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
  
  		if (err)
  			ip6_flush_pending_frames(sk);
  		else if (!(msg->msg_flags & MSG_MORE))
4c9483b2f   David S. Miller   ipv6: Convert to ...
903
  			err = rawv6_push_pending_frames(sk, &fl6, rp);
3ef9d943d   YOSHIFUJI Hideaki   [IPV6]: Fix unbal...
904
  		release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
  	}
  done:
6d3e85ecf   Nicolas DICHTEL   [IPV6] Don't stor...
907
  	dst_release(dst);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
908
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  	fl6_sock_release(flowlabel);
45f6fad84   Eric Dumazet   ipv6: add complet...
910
  	txopt_put(opt_to_free);
67ba4152e   Ian Morris   ipv6: White-space...
911
  	return err < 0 ? err : len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  do_confirm:
0dec879f6   Julian Anastasov   net: use dst_conf...
913
914
  	if (msg->msg_flags & MSG_PROBE)
  		dst_confirm_neigh(dst, &fl6.daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
917
918
919
  	if (!(msg->msg_flags & MSG_PROBE) || len)
  		goto back_from_confirm;
  	err = 0;
  	goto done;
  }
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
920
  static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
926
927
928
929
930
931
  			       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...
932
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
  
  	return 0;
  }
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
936
  static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
  			       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...
956
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
  
  	return 0;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
960
  static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
961
  			    char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
  {
  	struct raw6_sock *rp = raw6_sk(sk);
  	int val;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
965
  	if (get_user(val, (int __user *)optval))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
968
  		return -EFAULT;
  
  	switch (optname) {
715f504b1   Hannes Frederic Sowa   ipv6: add IPV6_HD...
969
970
971
972
973
  	case IPV6_HDRINCL:
  		if (sk->sk_type != SOCK_RAW)
  			return -EINVAL;
  		inet_sk(sk)->hdrincl = !!val;
  		return 0;
207ec0abb   Joe Perches   ipv6: Reduce swit...
974
975
976
977
978
979
980
981
982
983
984
985
986
  	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...
987

207ec0abb   Joe Perches   ipv6: Reduce swit...
988
989
990
991
992
993
994
995
996
997
  		/* 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
998

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

207ec0abb   Joe Perches   ipv6: Reduce swit...
1001
1002
  	default:
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
  	}
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1005
  static int rawv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
1006
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  {
207ec0abb   Joe Perches   ipv6: Reduce swit...
1008
1009
1010
  	switch (level) {
  	case SOL_RAW:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011

207ec0abb   Joe Perches   ipv6: Reduce swit...
1012
1013
1014
1015
1016
  	case SOL_ICMPV6:
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  			return -EOPNOTSUPP;
  		return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
715f504b1   Hannes Frederic Sowa   ipv6: add IPV6_HD...
1017
1018
  		if (optname == IPV6_CHECKSUM ||
  		    optname == IPV6_HDRINCL)
207ec0abb   Joe Perches   ipv6: Reduce swit...
1019
1020
1021
  			break;
  	default:
  		return ipv6_setsockopt(sk, level, optname, optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1022
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1023
1024
1025
1026
1027
  	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...
1028
  				   char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1029
  {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1030
1031
1032
1033
  	switch (level) {
  	case SOL_RAW:
  		break;
  	case SOL_ICMPV6:
c720c7e83   Eric Dumazet   inet: rename some...
1034
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1035
1036
1037
  			return -EOPNOTSUPP;
  		return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
715f504b1   Hannes Frederic Sowa   ipv6: add IPV6_HD...
1038
1039
  		if (optname == IPV6_CHECKSUM ||
  		    optname == IPV6_HDRINCL)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1040
  			break;
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1041
1042
1043
  	default:
  		return compat_ipv6_setsockopt(sk, level, optname,
  					      optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1044
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1045
1046
1047
1048
1049
1050
1051
1052
1053
  	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
1054

67ba4152e   Ian Morris   ipv6: White-space...
1055
  	if (get_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
  		return -EFAULT;
  
  	switch (optname) {
715f504b1   Hannes Frederic Sowa   ipv6: add IPV6_HD...
1059
1060
1061
  	case IPV6_HDRINCL:
  		val = inet_sk(sk)->hdrincl;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  	case IPV6_CHECKSUM:
1a98d05f5   YOSHIFUJI Hideaki   ipv6 RAW: Disallo...
1063
1064
1065
1066
1067
  		/*
  		 * 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
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  		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;
67ba4152e   Ian Morris   ipv6: White-space...
1082
  	if (copy_to_user(optval, &val, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
1085
  		return -EFAULT;
  	return 0;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1086
1087
1088
  static int rawv6_getsockopt(struct sock *sk, int level, int optname,
  			  char __user *optval, int __user *optlen)
  {
207ec0abb   Joe Perches   ipv6: Reduce swit...
1089
1090
1091
  	switch (level) {
  	case SOL_RAW:
  		break;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1092

207ec0abb   Joe Perches   ipv6: Reduce swit...
1093
1094
1095
1096
1097
  	case SOL_ICMPV6:
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  			return -EOPNOTSUPP;
  		return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
715f504b1   Hannes Frederic Sowa   ipv6: add IPV6_HD...
1098
1099
  		if (optname == IPV6_CHECKSUM ||
  		    optname == IPV6_HDRINCL)
207ec0abb   Joe Perches   ipv6: Reduce swit...
1100
1101
1102
  			break;
  	default:
  		return ipv6_getsockopt(sk, level, optname, optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1103
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1104
1105
1106
1107
1108
  	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...
1109
  				   char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1110
  {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1111
1112
1113
1114
  	switch (level) {
  	case SOL_RAW:
  		break;
  	case SOL_ICMPV6:
c720c7e83   Eric Dumazet   inet: rename some...
1115
  		if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1116
1117
1118
  			return -EOPNOTSUPP;
  		return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
  	case SOL_IPV6:
715f504b1   Hannes Frederic Sowa   ipv6: add IPV6_HD...
1119
1120
  		if (optname == IPV6_CHECKSUM ||
  		    optname == IPV6_HDRINCL)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1121
  			break;
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1122
1123
1124
  	default:
  		return compat_ipv6_getsockopt(sk, level, optname,
  					      optval, optlen);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1125
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1126
1127
1128
  	return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
  static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
207ec0abb   Joe Perches   ipv6: Reduce swit...
1131
1132
1133
  	switch (cmd) {
  	case SIOCOUTQ: {
  		int amount = sk_wmem_alloc_get(sk);
31e6d363a   Eric Dumazet   net: correct off-...
1134

207ec0abb   Joe Perches   ipv6: Reduce swit...
1135
1136
1137
1138
1139
1140
1141
1142
  		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);
53b24b8f9   Ian Morris   ipv6: coding styl...
1143
  		if (skb)
105f5528b   Jamie Bainbridge   ipv6: check raw p...
1144
  			amount = skb->len;
207ec0abb   Joe Perches   ipv6: Reduce swit...
1145
1146
1147
  		spin_unlock_bh(&sk->sk_receive_queue.lock);
  		return put_user(amount, (int __user *)arg);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148

207ec0abb   Joe Perches   ipv6: Reduce swit...
1149
  	default:
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1150
  #ifdef CONFIG_IPV6_MROUTE
207ec0abb   Joe Perches   ipv6: Reduce swit...
1151
  		return ip6mr_ioctl(sk, cmd, (void __user *)arg);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1152
  #else
207ec0abb   Joe Perches   ipv6: Reduce swit...
1153
  		return -ENOIOCTLCMD;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1154
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
  	}
  }
e2d57766e   David S. Miller   net: Provide comp...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  #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
1173
1174
  static void rawv6_close(struct sock *sk, long timeout)
  {
c720c7e83   Eric Dumazet   inet: rename some...
1175
  	if (inet_sk(sk)->inet_num == IPPROTO_RAW)
725a8ff04   Denis V. Lunev   ipv6: remove unus...
1176
  		ip6_ra_control(sk, -1);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1177
  	ip6mr_sk_done(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
  	sk_common_release(sk);
  }
7d06b2e05   Brian Haley   net: change proto...
1180
  static void raw6_destroy(struct sock *sk)
22dd48502   Denis V. Lunev   raw: Raw socket l...
1181
1182
1183
1184
  {
  	lock_sock(sk);
  	ip6_flush_pending_frames(sk);
  	release_sock(sk);
f23d60de7   David S. Miller   ipv6: Fix duplica...
1185

7d06b2e05   Brian Haley   net: change proto...
1186
  	inet6_destroy_sock(sk);
22dd48502   Denis V. Lunev   raw: Raw socket l...
1187
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
1189
  static int rawv6_init_sk(struct sock *sk)
  {
f48d5ff1e   Masahide NAKAMURA   [IPV6] RAW: Add c...
1190
  	struct raw6_sock *rp = raw6_sk(sk);
c720c7e83   Eric Dumazet   inet: rename some...
1191
  	switch (inet_sk(sk)->inet_num) {
f48d5ff1e   Masahide NAKAMURA   [IPV6] RAW: Add c...
1192
  	case IPPROTO_ICMPV6:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
  		rp->checksum = 1;
  		rp->offset   = 2;
f48d5ff1e   Masahide NAKAMURA   [IPV6] RAW: Add c...
1195
1196
1197
1198
1199
1200
1201
  		break;
  	case IPPROTO_MH:
  		rp->checksum = 1;
  		rp->offset   = 4;
  		break;
  	default:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
  	}
a02cec215   Eric Dumazet   net: return opera...
1203
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
  }
  
  struct proto rawv6_prot = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1207
1208
1209
  	.name		   = "RAWv6",
  	.owner		   = THIS_MODULE,
  	.close		   = rawv6_close,
22dd48502   Denis V. Lunev   raw: Raw socket l...
1210
  	.destroy	   = raw6_destroy,
82b276cd2   Hannes Frederic Sowa   ipv6: protect pro...
1211
  	.connect	   = ip6_datagram_connect_v6_only,
286c72dea   Eric Dumazet   udp: must lock th...
1212
  	.disconnect	   = __udp_disconnect,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1213
1214
  	.ioctl		   = rawv6_ioctl,
  	.init		   = rawv6_init_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1215
1216
1217
1218
1219
1220
  	.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...
1221
1222
  	.hash		   = raw_hash_sk,
  	.unhash		   = raw_unhash_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1223
  	.obj_size	   = sizeof(struct raw6_sock),
fc8717baa   Pavel Emelyanov   [RAW]: Add raw_ha...
1224
  	.h.raw_hash	   = &raw_v6_hashinfo,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1225
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1226
1227
  	.compat_setsockopt = compat_rawv6_setsockopt,
  	.compat_getsockopt = compat_rawv6_getsockopt,
e2d57766e   David S. Miller   net: Provide comp...
1228
  	.compat_ioctl	   = compat_rawv6_ioctl,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1229
  #endif
432490f9d   Cyrill Gorcunov   net: ip, diag -- ...
1230
  	.diag_destroy	   = raw_abort,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
1233
  };
  
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
  static int raw6_seq_show(struct seq_file *seq, void *v)
  {
17ef66afc   Lorenzo Colitti   net: ipv6: Unify ...
1236
1237
1238
1239
1240
1241
1242
1243
  	if (v == SEQ_START_TOKEN) {
  		seq_puts(seq, IPV6_SEQ_DGRAM_HEADER);
  	} else {
  		struct sock *sp = v;
  		__u16 srcp  = inet_sk(sp)->inet_num;
  		ip6_dgram_sock_seq_show(seq, v, srcp, 0,
  					raw_seq_private(seq)->bucket);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
  	return 0;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
1246
  static const struct seq_operations raw6_seq_ops = {
42a73808e   Pavel Emelyanov   [RAW]: Consolidat...
1247
1248
1249
  	.start =	raw_seq_start,
  	.next =		raw_seq_next,
  	.stop =		raw_seq_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
  	.show =		raw6_seq_show,
  };
  
  static int raw6_seq_open(struct inode *inode, struct file *file)
  {
3046d7674   Denis V. Lunev   [RAW]: Wrong cont...
1255
  	return raw_seq_open(inode, file, &raw_v6_hashinfo, &raw6_seq_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
1257
  static const struct file_operations raw6_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
1260
1261
  	.owner =	THIS_MODULE,
  	.open =		raw6_seq_open,
  	.read =		seq_read,
  	.llseek =	seq_lseek,
f51d599fb   Pavel Emelyanov   [NETNS][RAW]: Mak...
1262
  	.release =	seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
1264
  static int __net_init raw6_init_net(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
  {
d4beaa66a   Gao feng   net: proc: change...
1266
  	if (!proc_create("raw6", S_IRUGO, net->proc_net, &raw6_seq_fops))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
  		return -ENOMEM;
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1268

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
1270
  	return 0;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1271
  static void __net_exit raw6_exit_net(struct net *net)
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1272
  {
ece31ffd5   Gao feng   net: proc: change...
1273
  	remove_proc_entry("raw6", net->proc_net);
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
  }
  
  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
1285
1286
  void raw6_proc_exit(void)
  {
a308da162   Pavel Emelyanov   [NETNS][RAW]: Cre...
1287
  	unregister_pernet_subsys(&raw6_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
1289
  }
  #endif	/* CONFIG_PROC_FS */
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1290
1291
  
  /* Same as inet6_dgram_ops, sans udp_poll.  */
77d4b1d36   Eric Dumazet   net: ping: do not...
1292
  const struct proto_ops inet6_sockraw_ops = {
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
  	.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 ...
1322
1323
1324
1325
1326
  	.flags		= INET_PROTOSW_REUSE,
  };
  
  int __init rawv6_init(void)
  {
3d2f6d41d   Julia Lawall   ipv6: drop unneed...
1327
  	return inet6_register_protosw(&rawv6_protosw);
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1328
  }
09f7709f4   Daniel Lezcano   [IPV6]: fix secti...
1329
  void rawv6_exit(void)
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1330
1331
1332
  {
  	inet6_unregister_protosw(&rawv6_protosw);
  }