Blame view

net/ipv6/udp.c 36.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *	UDP over 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
   *
   *	Based on linux/ipv4/udp.c
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
   *	Fixes:
   *	Hideaki YOSHIFUJI	:	sin6_scope_id support
   *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
   *	Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
   *					a single port at the same time.
   *      Kazunori MIYAZAWA @USAGI:       change process style to use ip6_append_data
   *      YOSHIFUJI Hideaki @USAGI:	convert /proc/net/udp6 to seq_file.
   *
   *	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.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
  #include <linux/net.h>
  #include <linux/in6.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/ipv6.h>
  #include <linux/icmpv6.h>
  #include <linux/init.h>
1781f7f58   Herbert Xu   [UDP]: Restore mi...
34
  #include <linux/module.h>
3305b80c2   Herbert Xu   [IP]: Simplify an...
35
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
  #include <net/ndisc.h>
  #include <net/protocol.h>
  #include <net/transp_v6.h>
  #include <net/ip6_route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #include <net/raw.h>
c752f0739   Arnaldo Carvalho de Melo   [TCP]: Move the t...
43
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
  #include <net/ip6_checksum.h>
  #include <net/xfrm.h>
  
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
ba4e58eca   Gerrit Renker   [NET]: Supporting...
49
  #include "udp_impl.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

b2f5e7cd3   Vlad Yasevich   ipv6: Fix conflic...
51
52
53
54
  int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
  {
  	const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
  	const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
c720c7e83   Eric Dumazet   inet: rename some...
55
  	__be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr;
499923c7a   Vlad Yasevich   ipv6: Fix NULL po...
56
  	__be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
b2f5e7cd3   Vlad Yasevich   ipv6: Fix conflic...
57
58
59
60
61
62
63
  	int sk_ipv6only = ipv6_only_sock(sk);
  	int sk2_ipv6only = inet_v6_ipv6only(sk2);
  	int addr_type = ipv6_addr_type(sk_rcv_saddr6);
  	int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
  
  	/* if both are mapped, treat as IPv4 */
  	if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED)
499923c7a   Vlad Yasevich   ipv6: Fix NULL po...
64
  		return (!sk2_ipv6only &&
c720c7e83   Eric Dumazet   inet: rename some...
65
66
  			(!sk1_rcv_saddr || !sk2_rcv_saddr ||
  			  sk1_rcv_saddr == sk2_rcv_saddr));
b2f5e7cd3   Vlad Yasevich   ipv6: Fix conflic...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  
  	if (addr_type2 == IPV6_ADDR_ANY &&
  	    !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))
  		return 1;
  
  	if (addr_type == IPV6_ADDR_ANY &&
  	    !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
  		return 1;
  
  	if (sk2_rcv_saddr6 &&
  	    ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6))
  		return 1;
  
  	return 0;
  }
d4cada4ae   Eric Dumazet   udp: split sk_has...
82
83
84
85
86
87
88
89
  static unsigned int udp6_portaddr_hash(struct net *net,
  				       const struct in6_addr *addr6,
  				       unsigned int port)
  {
  	unsigned int hash, mix = net_hash_mix(net);
  
  	if (ipv6_addr_any(addr6))
  		hash = jhash_1word(0, mix);
856540ee3   Brian Haley   IPv6: use ipv6_ad...
90
  	else if (ipv6_addr_v4mapped(addr6))
0eae88f31   Eric Dumazet   net: Fix various ...
91
  		hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix);
d4cada4ae   Eric Dumazet   udp: split sk_has...
92
  	else
0eae88f31   Eric Dumazet   net: Fix various ...
93
  		hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix);
d4cada4ae   Eric Dumazet   udp: split sk_has...
94
95
96
  
  	return hash ^ port;
  }
6ba5a3c52   Pavel Emelyanov   [UDP]: Make full ...
97
  int udp_v6_get_port(struct sock *sk, unsigned short snum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  {
30fff9231   Eric Dumazet   udp: bind() optim...
99
100
101
102
  	unsigned int hash2_nulladdr =
  		udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum);
  	unsigned int hash2_partial = 
  		udp6_portaddr_hash(sock_net(sk), &inet6_sk(sk)->rcv_saddr, 0);
d4cada4ae   Eric Dumazet   udp: split sk_has...
103
  	/* precompute partial secondary hash */
30fff9231   Eric Dumazet   udp: bind() optim...
104
105
  	udp_sk(sk)->udp_portaddr_hash = hash2_partial;
  	return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  }
719f83585   Eric Dumazet   udp: add rehash o...
107
108
109
110
111
112
113
114
  static void udp_v6_rehash(struct sock *sk)
  {
  	u16 new_hash = udp6_portaddr_hash(sock_net(sk),
  					  &inet6_sk(sk)->rcv_saddr,
  					  inet_sk(sk)->inet_num);
  
  	udp_lib_rehash(sk, new_hash);
  }
645ca708f   Eric Dumazet   udp: introduce st...
115
116
117
118
119
120
121
  static inline int compute_score(struct sock *sk, struct net *net,
  				unsigned short hnum,
  				struct in6_addr *saddr, __be16 sport,
  				struct in6_addr *daddr, __be16 dport,
  				int dif)
  {
  	int score = -1;
d4cada4ae   Eric Dumazet   udp: split sk_has...
122
  	if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
645ca708f   Eric Dumazet   udp: introduce st...
123
124
125
126
127
  			sk->sk_family == PF_INET6) {
  		struct ipv6_pinfo *np = inet6_sk(sk);
  		struct inet_sock *inet = inet_sk(sk);
  
  		score = 0;
c720c7e83   Eric Dumazet   inet: rename some...
128
129
  		if (inet->inet_dport) {
  			if (inet->inet_dport != sport)
645ca708f   Eric Dumazet   udp: introduce st...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  				return -1;
  			score++;
  		}
  		if (!ipv6_addr_any(&np->rcv_saddr)) {
  			if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
  				return -1;
  			score++;
  		}
  		if (!ipv6_addr_any(&np->daddr)) {
  			if (!ipv6_addr_equal(&np->daddr, saddr))
  				return -1;
  			score++;
  		}
  		if (sk->sk_bound_dev_if) {
  			if (sk->sk_bound_dev_if != dif)
  				return -1;
  			score++;
  		}
  	}
  	return score;
  }
fddc17def   Eric Dumazet   ipv6: udp: optimi...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  #define SCORE2_MAX (1 + 1 + 1)
  static inline int compute_score2(struct sock *sk, struct net *net,
  				const struct in6_addr *saddr, __be16 sport,
  				const struct in6_addr *daddr, unsigned short hnum,
  				int dif)
  {
  	int score = -1;
  
  	if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
  			sk->sk_family == PF_INET6) {
  		struct ipv6_pinfo *np = inet6_sk(sk);
  		struct inet_sock *inet = inet_sk(sk);
  
  		if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
  			return -1;
  		score = 0;
  		if (inet->inet_dport) {
  			if (inet->inet_dport != sport)
  				return -1;
  			score++;
  		}
  		if (!ipv6_addr_any(&np->daddr)) {
  			if (!ipv6_addr_equal(&np->daddr, saddr))
  				return -1;
  			score++;
  		}
  		if (sk->sk_bound_dev_if) {
  			if (sk->sk_bound_dev_if != dif)
  				return -1;
  			score++;
  		}
  	}
  	return score;
  }
fddc17def   Eric Dumazet   ipv6: udp: optimi...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  
  /* called with read_rcu_lock() */
  static struct sock *udp6_lib_lookup2(struct net *net,
  		const struct in6_addr *saddr, __be16 sport,
  		const struct in6_addr *daddr, unsigned int hnum, int dif,
  		struct udp_hslot *hslot2, unsigned int slot2)
  {
  	struct sock *sk, *result;
  	struct hlist_nulls_node *node;
  	int score, badness;
  
  begin:
  	result = NULL;
  	badness = -1;
  	udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) {
  		score = compute_score2(sk, net, saddr, sport,
  				      daddr, hnum, dif);
  		if (score > badness) {
  			result = sk;
  			badness = score;
  			if (score == SCORE2_MAX)
  				goto exact_match;
  		}
  	}
  	/*
  	 * if the nulls value we got at the end of this lookup is
  	 * not the expected one, we must restart lookup.
  	 * We probably met an item that was moved to another chain.
  	 */
  	if (get_nulls_value(node) != slot2)
  		goto begin;
  
  	if (result) {
  exact_match:
  		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
  			result = NULL;
  		else if (unlikely(compute_score2(result, net, saddr, sport,
  				  daddr, hnum, dif) < badness)) {
  			sock_put(result);
  			goto begin;
  		}
  	}
  	return result;
  }
fa4d3c621   Pavel Emelyanov   [NETNS]: Udp sock...
229
230
  static struct sock *__udp6_lib_lookup(struct net *net,
  				      struct in6_addr *saddr, __be16 sport,
ba4e58eca   Gerrit Renker   [NET]: Supporting...
231
  				      struct in6_addr *daddr, __be16 dport,
645ca708f   Eric Dumazet   udp: introduce st...
232
  				      int dif, struct udp_table *udptable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  {
271b72c7f   Eric Dumazet   udp: RCU handling...
234
  	struct sock *sk, *result;
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
235
  	struct hlist_nulls_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  	unsigned short hnum = ntohs(dport);
fddc17def   Eric Dumazet   ipv6: udp: optimi...
237
238
  	unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
  	struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
271b72c7f   Eric Dumazet   udp: RCU handling...
239
  	int score, badness;
645ca708f   Eric Dumazet   udp: introduce st...
240

271b72c7f   Eric Dumazet   udp: RCU handling...
241
  	rcu_read_lock();
fddc17def   Eric Dumazet   ipv6: udp: optimi...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  	if (hslot->count > 10) {
  		hash2 = udp6_portaddr_hash(net, daddr, hnum);
  		slot2 = hash2 & udptable->mask;
  		hslot2 = &udptable->hash2[slot2];
  		if (hslot->count < hslot2->count)
  			goto begin;
  
  		result = udp6_lib_lookup2(net, saddr, sport,
  					  daddr, hnum, dif,
  					  hslot2, slot2);
  		if (!result) {
  			hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum);
  			slot2 = hash2 & udptable->mask;
  			hslot2 = &udptable->hash2[slot2];
  			if (hslot->count < hslot2->count)
  				goto begin;
1223c67c0   Jorge Boncompte [DTI2]   udp: fix for unic...
258
259
  			result = udp6_lib_lookup2(net, saddr, sport,
  						  &in6addr_any, hnum, dif,
fddc17def   Eric Dumazet   ipv6: udp: optimi...
260
261
262
263
264
  						  hslot2, slot2);
  		}
  		rcu_read_unlock();
  		return result;
  	}
271b72c7f   Eric Dumazet   udp: RCU handling...
265
266
267
  begin:
  	result = NULL;
  	badness = -1;
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
268
  	sk_nulls_for_each_rcu(sk, node, &hslot->head) {
645ca708f   Eric Dumazet   udp: introduce st...
269
270
271
272
  		score = compute_score(sk, net, hnum, saddr, sport, daddr, dport, dif);
  		if (score > badness) {
  			result = sk;
  			badness = score;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  		}
  	}
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
275
276
277
278
279
  	/*
  	 * if the nulls value we got at the end of this lookup is
  	 * not the expected one, we must restart lookup.
  	 * We probably met an item that was moved to another chain.
  	 */
fddc17def   Eric Dumazet   ipv6: udp: optimi...
280
  	if (get_nulls_value(node) != slot)
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
281
  		goto begin;
271b72c7f   Eric Dumazet   udp: RCU handling...
282
283
284
285
286
287
288
289
290
291
  	if (result) {
  		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
  			result = NULL;
  		else if (unlikely(compute_score(result, net, hnum, saddr, sport,
  					daddr, dport, dif) < badness)) {
  			sock_put(result);
  			goto begin;
  		}
  	}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  	return result;
  }
607c4aaf0   KOVACS Krisztian   inet: Add udplib_...
294
295
  static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
  					  __be16 sport, __be16 dport,
645ca708f   Eric Dumazet   udp: introduce st...
296
  					  struct udp_table *udptable)
607c4aaf0   KOVACS Krisztian   inet: Add udplib_...
297
  {
23542618d   KOVACS Krisztian   inet: Don't looku...
298
  	struct sock *sk;
607c4aaf0   KOVACS Krisztian   inet: Add udplib_...
299
  	struct ipv6hdr *iph = ipv6_hdr(skb);
23542618d   KOVACS Krisztian   inet: Don't looku...
300
301
  	if (unlikely(sk = skb_steal_sock(skb)))
  		return sk;
adf30907d   Eric Dumazet   net: skb->dst acc...
302
303
304
  	return __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport,
  				 &iph->daddr, dport, inet6_iif(skb),
  				 udptable);
607c4aaf0   KOVACS Krisztian   inet: Add udplib_...
305
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
   * 	This should be easy, if there is something there we
   * 	return it, otherwise we block.
   */
ba4e58eca   Gerrit Renker   [NET]: Supporting...
310
  int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
  		  struct msghdr *msg, size_t len,
  		  int noblock, int flags, int *addr_len)
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct inet_sock *inet = inet_sk(sk);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
316
  	struct sk_buff *skb;
81d54ec84   Gerrit Renker   udp: remove redun...
317
  	unsigned int ulen;
a59322be0   Herbert Xu   [UDP]: Only incre...
318
  	int peeked;
759e5d006   Herbert Xu   [UDP]: Clean up U...
319
320
  	int err;
  	int is_udplite = IS_UDPLITE(sk);
f26ba1751   Wei Yongjun   udp: Fix the SNMP...
321
  	int is_udp4;
8a74ad60a   Eric Dumazet   net: fix lock_soc...
322
  	bool slow;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
324
325
  	if (addr_len)
  		*addr_len=sizeof(struct sockaddr_in6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
  	if (flags & MSG_ERRQUEUE)
  		return ipv6_recv_error(sk, msg, len);
4b340ae20   Brian Haley   IPv6: Complete IP...
328
329
  	if (np->rxpmtu && np->rxopt.bits.rxpmtu)
  		return ipv6_recv_rxpmtu(sk, msg, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  try_again:
a59322be0   Herbert Xu   [UDP]: Only incre...
331
332
  	skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
  				  &peeked, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  	if (!skb)
  		goto out;
759e5d006   Herbert Xu   [UDP]: Clean up U...
335
  	ulen = skb->len - sizeof(struct udphdr);
81d54ec84   Gerrit Renker   udp: remove redun...
336
337
338
  	if (len > ulen)
  		len = ulen;
  	else if (len < ulen)
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
339
  		msg->msg_flags |= MSG_TRUNC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

f26ba1751   Wei Yongjun   udp: Fix the SNMP...
341
  	is_udp4 = (skb->protocol == htons(ETH_P_IP));
ba4e58eca   Gerrit Renker   [NET]: Supporting...
342
  	/*
759e5d006   Herbert Xu   [UDP]: Clean up U...
343
344
345
  	 * If checksum is needed at all, try to do it while copying the
  	 * data.  If the data is truncated, or if we only want a partial
  	 * coverage checksum (UDP-Lite), do it before the copy.
ba4e58eca   Gerrit Renker   [NET]: Supporting...
346
  	 */
ba4e58eca   Gerrit Renker   [NET]: Supporting...
347

81d54ec84   Gerrit Renker   udp: remove redun...
348
  	if (len < ulen || UDP_SKB_CB(skb)->partial_cov) {
759e5d006   Herbert Xu   [UDP]: Clean up U...
349
  		if (udp_lib_checksum_complete(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  			goto csum_copy_err;
ba4e58eca   Gerrit Renker   [NET]: Supporting...
351
  	}
604763722   Herbert Xu   [NET]: Treat CHEC...
352
  	if (skb_csum_unnecessary(skb))
ba4e58eca   Gerrit Renker   [NET]: Supporting...
353
  		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
81d54ec84   Gerrit Renker   udp: remove redun...
354
  					      msg->msg_iov,len);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
355
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
360
361
  		err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
  		if (err == -EINVAL)
  			goto csum_copy_err;
  	}
  	if (err)
  		goto out_free;
f26ba1751   Wei Yongjun   udp: Fix the SNMP...
362
363
364
365
366
367
368
369
  	if (!peeked) {
  		if (is_udp4)
  			UDP_INC_STATS_USER(sock_net(sk),
  					UDP_MIB_INDATAGRAMS, is_udplite);
  		else
  			UDP6_INC_STATS_USER(sock_net(sk),
  					UDP_MIB_INDATAGRAMS, is_udplite);
  	}
cb75994ec   Wang Chen   [UDP]: Defer InDa...
370

3b885787e   Neil Horman   net: Generalize s...
371
  	sock_recv_ts_and_drops(msg, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
375
  
  	/* Copy the address. */
  	if (msg->msg_name) {
  		struct sockaddr_in6 *sin6;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
376

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  		sin6 = (struct sockaddr_in6 *) msg->msg_name;
  		sin6->sin6_family = AF_INET6;
4bedb4520   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
379
  		sin6->sin6_port = udp_hdr(skb)->source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  		sin6->sin6_flowinfo = 0;
  		sin6->sin6_scope_id = 0;
f26ba1751   Wei Yongjun   udp: Fix the SNMP...
382
  		if (is_udp4)
b301e82cf   Brian Haley   IPv6: use ipv6_ad...
383
384
  			ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
  					       &sin6->sin6_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  		else {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
386
387
  			ipv6_addr_copy(&sin6->sin6_addr,
  				       &ipv6_hdr(skb)->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
391
392
  			if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
  				sin6->sin6_scope_id = IP6CB(skb)->iif;
  		}
  
  	}
f26ba1751   Wei Yongjun   udp: Fix the SNMP...
393
  	if (is_udp4) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
  		if (inet->cmsg_flags)
  			ip_cmsg_recv(msg, skb);
  	} else {
  		if (np->rxopt.all)
  			datagram_recv_ctl(sk, msg, skb);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
399
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400

81d54ec84   Gerrit Renker   udp: remove redun...
401
  	err = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	if (flags & MSG_TRUNC)
759e5d006   Herbert Xu   [UDP]: Clean up U...
403
  		err = ulen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  
  out_free:
9d410c796   Eric Dumazet   net: fix sk_forwa...
406
  	skb_free_datagram_locked(sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
  out:
  	return err;
  
  csum_copy_err:
8a74ad60a   Eric Dumazet   net: fix lock_soc...
411
  	slow = lock_sock_fast(sk);
0856f9395   Wei Yongjun   udp: Fix the SNMP...
412
413
414
415
416
417
418
419
  	if (!skb_kill_datagram(sk, skb, flags)) {
  		if (is_udp4)
  			UDP_INC_STATS_USER(sock_net(sk),
  					UDP_MIB_INERRORS, is_udplite);
  		else
  			UDP6_INC_STATS_USER(sock_net(sk),
  					UDP_MIB_INERRORS, is_udplite);
  	}
8a74ad60a   Eric Dumazet   net: fix lock_soc...
420
  	unlock_sock_fast(sk, slow);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

7a0ff716c   Mitsuru Chinen   [IPv6] SNMP: Rest...
422
  	if (flags & MSG_DONTWAIT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  	goto try_again;
  }
ba4e58eca   Gerrit Renker   [NET]: Supporting...
426
  void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
427
  		    u8 type, u8 code, int offset, __be32 info,
645ca708f   Eric Dumazet   udp: introduce st...
428
  		    struct udp_table *udptable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
  {
  	struct ipv6_pinfo *np;
  	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
436
  	struct in6_addr *saddr = &hdr->saddr;
  	struct in6_addr *daddr = &hdr->daddr;
  	struct udphdr *uh = (struct udphdr*)(skb->data+offset);
  	struct sock *sk;
  	int err;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
437
  	sk = __udp6_lib_lookup(dev_net(skb->dev), daddr, uh->dest,
ba4e58eca   Gerrit Renker   [NET]: Supporting...
438
  			       saddr, uh->source, inet6_iif(skb), udptable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
447
448
  	if (sk == NULL)
  		return;
  
  	np = inet6_sk(sk);
  
  	if (!icmpv6_err_convert(type, code, &err) && !np->recverr)
  		goto out;
  
  	if (sk->sk_state != TCP_ESTABLISHED && !np->recverr)
  		goto out;
b1faf5666   Eric Dumazet   net: sock_queue_e...
449
  	if (np->recverr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  		ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
b1faf5666   Eric Dumazet   net: sock_queue_e...
451

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
456
  	sk->sk_err = err;
  	sk->sk_error_report(sk);
  out:
  	sock_put(sk);
  }
ba4e58eca   Gerrit Renker   [NET]: Supporting...
457
  static __inline__ void udpv6_err(struct sk_buff *skb,
d5fdd6bab   Brian Haley   ipv6: Use correct...
458
459
  				 struct inet6_skb_parm *opt, u8 type,
  				 u8 code, int offset, __be32 info     )
ba4e58eca   Gerrit Renker   [NET]: Supporting...
460
  {
645ca708f   Eric Dumazet   udp: introduce st...
461
  	__udp6_lib_err(skb, opt, type, code, offset, info, &udp_table);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
462
463
464
  }
  
  int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  {
ba4e58eca   Gerrit Renker   [NET]: Supporting...
466
  	struct udp_sock *up = udp_sk(sk);
a18135eb9   David S. Miller   [IPV6]: Add UDP_M...
467
  	int rc;
b2bf1e265   Wang Chen   [UDP]: Clean up f...
468
  	int is_udplite = IS_UDPLITE(sk);
a18135eb9   David S. Miller   [IPV6]: Add UDP_M...
469

ba4e58eca   Gerrit Renker   [NET]: Supporting...
470
471
  	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
  		goto drop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

ba4e58eca   Gerrit Renker   [NET]: Supporting...
473
474
475
  	/*
  	 * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c).
  	 */
b2bf1e265   Wang Chen   [UDP]: Clean up f...
476
  	if ((is_udplite & UDPLITE_RECV_CC)  &&  UDP_SKB_CB(skb)->partial_cov) {
ba4e58eca   Gerrit Renker   [NET]: Supporting...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  
  		if (up->pcrlen == 0) {          /* full coverage was set  */
  			LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage"
  				" %d while full coverage %d requested
  ",
  				UDP_SKB_CB(skb)->cscov, skb->len);
  			goto drop;
  		}
  		if (UDP_SKB_CB(skb)->cscov  <  up->pcrlen) {
  			LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d "
  						    "too small, need min %d
  ",
  				       UDP_SKB_CB(skb)->cscov, up->pcrlen);
  			goto drop;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  	}
1ab6eb62b   Herbert Xu   [UDP6]: Restore s...
493
494
495
496
  	if (sk->sk_filter) {
  		if (udp_lib_checksum_complete(skb))
  			goto drop;
  	}
ba4e58eca   Gerrit Renker   [NET]: Supporting...
497

f84af32cb   Eric Dumazet   net: ip_queue_rcv...
498
  	if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
a18135eb9   David S. Miller   [IPV6]: Add UDP_M...
499
  		/* Note that an ENOMEM error is charged twice */
766e9037c   Eric Dumazet   net: sk_drops con...
500
  		if (rc == -ENOMEM)
ef28d1a20   Pavel Emelyanov   MIB: add struct n...
501
502
  			UDP6_INC_STATS_BH(sock_net(sk),
  					UDP_MIB_RCVBUFERRORS, is_udplite);
8edf19c2f   Eric Dumazet   net: sk_drops con...
503
  		goto drop_no_sk_drops_inc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  	}
cb75994ec   Wang Chen   [UDP]: Defer InDa...
505

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	return 0;
ba4e58eca   Gerrit Renker   [NET]: Supporting...
507
  drop:
8edf19c2f   Eric Dumazet   net: sk_drops con...
508
509
  	atomic_inc(&sk->sk_drops);
  drop_no_sk_drops_inc:
ef28d1a20   Pavel Emelyanov   MIB: add struct n...
510
  	UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
511
512
  	kfree_skb(skb);
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  }
920a46115   Eric Dumazet   udp: multicast pa...
514
  static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
e69a4adc6   Al Viro   [IPV6]: Misc endi...
515
516
  				      __be16 loc_port, struct in6_addr *loc_addr,
  				      __be16 rmt_port, struct in6_addr *rmt_addr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  				      int dif)
  {
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
519
  	struct hlist_nulls_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  	struct sock *s = sk;
  	unsigned short num = ntohs(loc_port);
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
522
  	sk_nulls_for_each_from(s, node) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  		struct inet_sock *inet = inet_sk(s);
920a46115   Eric Dumazet   udp: multicast pa...
524
  		if (!net_eq(sock_net(s), net))
b8ad0cbc5   Daniel Lezcano   [NETNS][IPV6] mca...
525
  			continue;
d4cada4ae   Eric Dumazet   udp: split sk_has...
526
527
  		if (udp_sk(s)->udp_port_hash == num &&
  		    s->sk_family == PF_INET6) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  			struct ipv6_pinfo *np = inet6_sk(s);
c720c7e83   Eric Dumazet   inet: rename some...
529
530
  			if (inet->inet_dport) {
  				if (inet->inet_dport != rmt_port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
533
534
535
536
537
538
539
540
  					continue;
  			}
  			if (!ipv6_addr_any(&np->daddr) &&
  			    !ipv6_addr_equal(&np->daddr, rmt_addr))
  				continue;
  
  			if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)
  				continue;
  
  			if (!ipv6_addr_any(&np->rcv_saddr)) {
40796c5e8   David L Stevens   [IPV6]: Fix per-s...
541
542
  				if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr))
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  			}
add459aa1   Stephen Hemminger   [UDP]: ipv6 style...
544
  			if (!inet6_mc_check(s, loc_addr, rmt_addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
550
  				continue;
  			return s;
  		}
  	}
  	return NULL;
  }
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
551
552
553
554
555
556
557
558
559
  static void flush_stack(struct sock **stack, unsigned int count,
  			struct sk_buff *skb, unsigned int final)
  {
  	unsigned int i;
  	struct sock *sk;
  	struct sk_buff *skb1;
  
  	for (i = 0; i < count; i++) {
  		skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
f6b8f32ca   Eric Dumazet   udp: multicast RX...
560
  		sk = stack[i];
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
561
  		if (skb1) {
c377411f2   Eric Dumazet   net: sk_add_backl...
562
563
564
565
  			if (sk_rcvqueues_full(sk, skb)) {
  				kfree_skb(skb1);
  				goto drop;
  			}
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
566
567
568
  			bh_lock_sock(sk);
  			if (!sock_owned_by_user(sk))
  				udpv6_queue_rcv_skb(sk, skb1);
a3a858ff1   Zhu Yi   net: backlog func...
569
  			else if (sk_add_backlog(sk, skb1)) {
55349790d   Zhu Yi   udp: use limited ...
570
571
572
573
  				kfree_skb(skb1);
  				bh_unlock_sock(sk);
  				goto drop;
  			}
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
574
  			bh_unlock_sock(sk);
55349790d   Zhu Yi   udp: use limited ...
575
  			continue;
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
576
  		}
55349790d   Zhu Yi   udp: use limited ...
577
578
579
580
581
582
  drop:
  		atomic_inc(&sk->sk_drops);
  		UDP6_INC_STATS_BH(sock_net(sk),
  				UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk));
  		UDP6_INC_STATS_BH(sock_net(sk),
  				UDP_MIB_INERRORS, IS_UDPLITE(sk));
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
583
584
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
  /*
   * Note: called only from the BH handler context,
   * so we don't need to lock the hashes.
   */
e31634931   Pavel Emelyanov   udp: provide a st...
589
590
  static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
  		struct in6_addr *saddr, struct in6_addr *daddr,
645ca708f   Eric Dumazet   udp: introduce st...
591
  		struct udp_table *udptable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  {
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
593
  	struct sock *sk, *stack[256 / sizeof(struct sock *)];
4bedb4520   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
594
  	const struct udphdr *uh = udp_hdr(skb);
f86dcc5aa   Eric Dumazet   udp: dynamically ...
595
  	struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  	int dif;
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
597
  	unsigned int i, count = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598

645ca708f   Eric Dumazet   udp: introduce st...
599
  	spin_lock(&hslot->lock);
88ab1932e   Eric Dumazet   udp: Use hlist_nu...
600
  	sk = sk_nulls_head(&hslot->head);
f2776ff04   YOSHIFUJI Hideaki   [IPV6]: Fix addre...
601
  	dif = inet6_iif(skb);
920a46115   Eric Dumazet   udp: multicast pa...
602
  	sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
603
604
605
606
607
608
609
610
611
  	while (sk) {
  		stack[count++] = sk;
  		sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr,
  				       uh->source, saddr, dif);
  		if (unlikely(count == ARRAY_SIZE(stack))) {
  			if (!sk)
  				break;
  			flush_stack(stack, count, skb, ~0);
  			count = 0;
95766fff6   Hideo Aoki   [UDP]: Add memory...
612
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  	}
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
614
615
616
617
618
  	/*
  	 * before releasing the lock, we must take reference on sockets
  	 */
  	for (i = 0; i < count; i++)
  		sock_hold(stack[i]);
645ca708f   Eric Dumazet   udp: introduce st...
619
  	spin_unlock(&hslot->lock);
a1ab77f97   Eric Dumazet   ipv6: udp: Optimi...
620
621
622
623
624
625
626
627
628
  
  	if (count) {
  		flush_stack(stack, count, skb, count - 1);
  
  		for (i = 0; i < count; i++)
  			sock_put(stack[i]);
  	} else {
  		kfree_skb(skb);
  	}
ba4e58eca   Gerrit Renker   [NET]: Supporting...
629
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  }
759e5d006   Herbert Xu   [UDP]: Clean up U...
631
632
  static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
  				 int proto)
ba4e58eca   Gerrit Renker   [NET]: Supporting...
633
  {
759e5d006   Herbert Xu   [UDP]: Clean up U...
634
635
636
637
  	int err;
  
  	UDP_SKB_CB(skb)->partial_cov = 0;
  	UDP_SKB_CB(skb)->cscov = skb->len;
db8dac20d   David S. Miller   [UDP]: Revert udp...
638
  	if (proto == IPPROTO_UDPLITE) {
759e5d006   Herbert Xu   [UDP]: Clean up U...
639
640
641
642
  		err = udplite_checksum_init(skb, uh);
  		if (err)
  			return err;
  	}
ba4e58eca   Gerrit Renker   [NET]: Supporting...
643
644
645
646
647
648
649
650
651
  	if (uh->check == 0) {
  		/* RFC 2460 section 8.1 says that we SHOULD log
  		   this error. Well, it is reasonable.
  		 */
  		LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0
  ");
  		return 1;
  	}
  	if (skb->ip_summed == CHECKSUM_COMPLETE &&
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
652
  	    !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
759e5d006   Herbert Xu   [UDP]: Clean up U...
653
  			     skb->len, proto, skb->csum))
ba4e58eca   Gerrit Renker   [NET]: Supporting...
654
  		skb->ip_summed = CHECKSUM_UNNECESSARY;
604763722   Herbert Xu   [NET]: Treat CHEC...
655
  	if (!skb_csum_unnecessary(skb))
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
656
657
  		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
  							 &ipv6_hdr(skb)->daddr,
759e5d006   Herbert Xu   [UDP]: Clean up U...
658
  							 skb->len, proto, 0));
ba4e58eca   Gerrit Renker   [NET]: Supporting...
659

759e5d006   Herbert Xu   [UDP]: Clean up U...
660
  	return 0;
ba4e58eca   Gerrit Renker   [NET]: Supporting...
661
  }
645ca708f   Eric Dumazet   udp: introduce st...
662
  int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
759e5d006   Herbert Xu   [UDP]: Clean up U...
663
  		   int proto)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  {
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
665
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  	struct sock *sk;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
667
  	struct udphdr *uh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
  	struct in6_addr *saddr, *daddr;
  	u32 ulen = 0;
  
  	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
d6bc0149d   Bjørn Mork   ipv6: udp: make s...
672
  		goto discard;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
674
675
  	saddr = &ipv6_hdr(skb)->saddr;
  	daddr = &ipv6_hdr(skb)->daddr;
4bedb4520   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
676
  	uh = udp_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
  
  	ulen = ntohs(uh->len);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
679
680
  	if (ulen > skb->len)
  		goto short_packet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681

759e5d006   Herbert Xu   [UDP]: Clean up U...
682
683
  	if (proto == IPPROTO_UDP) {
  		/* UDP validates ulen. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684

ba4e58eca   Gerrit Renker   [NET]: Supporting...
685
686
687
  		/* Check for jumbo payload */
  		if (ulen == 0)
  			ulen = skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

ba4e58eca   Gerrit Renker   [NET]: Supporting...
689
690
  		if (ulen < sizeof(*uh))
  			goto short_packet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691

ba4e58eca   Gerrit Renker   [NET]: Supporting...
692
693
694
  		if (ulen < skb->len) {
  			if (pskb_trim_rcsum(skb, ulen))
  				goto short_packet;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
695
696
  			saddr = &ipv6_hdr(skb)->saddr;
  			daddr = &ipv6_hdr(skb)->daddr;
4bedb4520   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
697
  			uh = udp_hdr(skb);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
698
  		}
ba4e58eca   Gerrit Renker   [NET]: Supporting...
699
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700

759e5d006   Herbert Xu   [UDP]: Clean up U...
701
702
  	if (udp6_csum_init(skb, uh, proto))
  		goto discard;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
703
704
  	/*
  	 *	Multicast receive code
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  	 */
ba4e58eca   Gerrit Renker   [NET]: Supporting...
706
  	if (ipv6_addr_is_multicast(daddr))
e31634931   Pavel Emelyanov   udp: provide a st...
707
708
  		return __udp6_lib_mcast_deliver(net, skb,
  				saddr, daddr, udptable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
  
  	/* Unicast */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
711
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
  	 * check socket cache ... must talk to Alan about his plans
  	 * for sock caches... i'll skip this for now.
  	 */
607c4aaf0   KOVACS Krisztian   inet: Add udplib_...
715
  	sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
  
  	if (sk == NULL) {
  		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
  			goto discard;
ba4e58eca   Gerrit Renker   [NET]: Supporting...
720
  		if (udp_lib_checksum_complete(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  			goto discard;
ef28d1a20   Pavel Emelyanov   MIB: add struct n...
722
723
  		UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS,
  				proto == IPPROTO_UDPLITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724

3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
725
  		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
  
  		kfree_skb(skb);
add459aa1   Stephen Hemminger   [UDP]: ipv6 style...
728
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  	}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
730

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	/* deliver */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
732

c377411f2   Eric Dumazet   net: sk_add_backl...
733
734
735
736
  	if (sk_rcvqueues_full(sk, skb)) {
  		sock_put(sk);
  		goto discard;
  	}
d97106ea5   Herbert Xu   udp: Drop socket ...
737
  	bh_lock_sock(sk);
95766fff6   Hideo Aoki   [UDP]: Add memory...
738
739
  	if (!sock_owned_by_user(sk))
  		udpv6_queue_rcv_skb(sk, skb);
a3a858ff1   Zhu Yi   net: backlog func...
740
  	else if (sk_add_backlog(sk, skb)) {
55349790d   Zhu Yi   udp: use limited ...
741
742
743
744
745
  		atomic_inc(&sk->sk_drops);
  		bh_unlock_sock(sk);
  		sock_put(sk);
  		goto discard;
  	}
95766fff6   Hideo Aoki   [UDP]: Add memory...
746
  	bh_unlock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	sock_put(sk);
add459aa1   Stephen Hemminger   [UDP]: ipv6 style...
748
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
750
  short_packet:
d6bc0149d   Bjørn Mork   ipv6: udp: make s...
751
752
  	LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u
  ",
db8dac20d   David S. Miller   [UDP]: Revert udp...
753
  		       proto == IPPROTO_UDPLITE ? "-Lite" : "",
d6bc0149d   Bjørn Mork   ipv6: udp: make s...
754
755
756
757
758
759
  		       saddr,
  		       ntohs(uh->source),
  		       ulen,
  		       skb->len,
  		       daddr,
  		       ntohs(uh->dest));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  
  discard:
ef28d1a20   Pavel Emelyanov   MIB: add struct n...
762
  	UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  	kfree_skb(skb);
add459aa1   Stephen Hemminger   [UDP]: ipv6 style...
764
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  }
ba4e58eca   Gerrit Renker   [NET]: Supporting...
766

e5bbef20e   Herbert Xu   [IPV6]: Replace s...
767
  static __inline__ int udpv6_rcv(struct sk_buff *skb)
ba4e58eca   Gerrit Renker   [NET]: Supporting...
768
  {
645ca708f   Eric Dumazet   udp: introduce st...
769
  	return __udp6_lib_rcv(skb, &udp_table, IPPROTO_UDP);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
770
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
775
776
  /*
   * Throw away all pending data and cancel the corking. Socket is locked.
   */
  static void udp_v6_flush_pending_frames(struct sock *sk)
  {
  	struct udp_sock *up = udp_sk(sk);
36d926b94   Denis V. Lunev   [IPV6]: inet_sk(s...
777
778
779
  	if (up->pending == AF_INET)
  		udp_flush_pending_frames(sk);
  	else if (up->pending) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
  		up->len = 0;
  		up->pending = 0;
  		ip6_flush_pending_frames(sk);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
783
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  }
493c6be3f   Sridhar Samudrala   udpv6: Fix HW che...
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
  /**
   * 	udp6_hwcsum_outgoing  -  handle outgoing HW checksumming
   * 	@sk: 	socket we are sending on
   * 	@skb: 	sk_buff containing the filled-in UDP header
   * 	        (checksum field must be zeroed out)
   */
  static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
  				 const struct in6_addr *saddr,
  				 const struct in6_addr *daddr, int len)
  {
  	unsigned int offset;
  	struct udphdr *uh = udp_hdr(skb);
  	__wsum csum = 0;
  
  	if (skb_queue_len(&sk->sk_write_queue) == 1) {
  		/* Only one fragment on the socket.  */
  		skb->csum_start = skb_transport_header(skb) - skb->head;
  		skb->csum_offset = offsetof(struct udphdr, check);
  		uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0);
  	} else {
  		/*
  		 * HW-checksum won't work as there are two or more
  		 * fragments on the socket so that all csums of sk_buffs
  		 * should be together
  		 */
  		offset = skb_transport_offset(skb);
  		skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
  
  		skb->ip_summed = CHECKSUM_NONE;
  
  		skb_queue_walk(&sk->sk_write_queue, skb) {
  			csum = csum_add(csum, skb->csum);
  		}
  
  		uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
  					    csum);
  		if (uh->check == 0)
  			uh->check = CSUM_MANGLED_0;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
  /*
   *	Sending
   */
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
828
  static int udp_v6_push_pending_frames(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
  {
  	struct sk_buff *skb;
  	struct udphdr *uh;
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
832
  	struct udp_sock  *up = udp_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
  	struct inet_sock *inet = inet_sk(sk);
  	struct flowi *fl = &inet->cork.fl;
  	int err = 0;
b2bf1e265   Wang Chen   [UDP]: Clean up f...
836
  	int is_udplite = IS_UDPLITE(sk);
868c86bcb   Al Viro   [NET]: annotate c...
837
  	__wsum csum = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
841
842
843
844
845
  
  	/* Grab the skbuff where UDP header space exists. */
  	if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
  		goto out;
  
  	/*
  	 * Create a UDP header
  	 */
4bedb4520   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
846
  	uh = udp_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
849
850
  	uh->source = fl->fl_ip_sport;
  	uh->dest = fl->fl_ip_dport;
  	uh->len = htons(up->len);
  	uh->check = 0;
b2bf1e265   Wang Chen   [UDP]: Clean up f...
851
  	if (is_udplite)
ba4e58eca   Gerrit Renker   [NET]: Supporting...
852
  		csum = udplite_csum_outgoing(sk, skb);
493c6be3f   Sridhar Samudrala   udpv6: Fix HW che...
853
854
855
856
857
  	else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
  		udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst,
  				     up->len);
  		goto send;
  	} else
ba4e58eca   Gerrit Renker   [NET]: Supporting...
858
  		csum = udp_csum_outgoing(sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859

ba4e58eca   Gerrit Renker   [NET]: Supporting...
860
861
862
  	/* add protocol-dependent pseudo-header */
  	uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst,
  				    up->len, fl->proto, csum   );
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  	if (uh->check == 0)
f6ab02880   Al Viro   [NET]: Make mangl...
864
  		uh->check = CSUM_MANGLED_0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865

493c6be3f   Sridhar Samudrala   udpv6: Fix HW che...
866
  send:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  	err = ip6_push_pending_frames(sk);
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
868
869
870
871
872
873
874
875
876
  	if (err) {
  		if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
  			UDP6_INC_STATS_USER(sock_net(sk),
  					    UDP_MIB_SNDBUFERRORS, is_udplite);
  			err = 0;
  		}
  	} else
  		UDP6_INC_STATS_USER(sock_net(sk),
  				    UDP_MIB_OUTDATAGRAMS, is_udplite);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
880
881
  out:
  	up->len = 0;
  	up->pending = 0;
  	return err;
  }
ba4e58eca   Gerrit Renker   [NET]: Supporting...
882
  int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
885
886
887
888
889
  		  struct msghdr *msg, size_t len)
  {
  	struct ipv6_txoptions opt_space;
  	struct udp_sock *up = udp_sk(sk);
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
20c59de2e   Arnaud Ebalard   ipv6: Refactor up...
890
  	struct in6_addr *daddr, *final_p, final;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
  	struct ipv6_txoptions *opt = NULL;
  	struct ip6_flowlabel *flowlabel = NULL;
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
893
  	struct flowi fl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
  	struct dst_entry *dst;
  	int addr_len = msg->msg_namelen;
  	int ulen = len;
  	int hlimit = -1;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
898
  	int tclass = -1;
13b52cd44   Brian Haley   IPv6: Add dontfra...
899
  	int dontfrag = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
  	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
  	int err;
987905ded   Mitsuru KANDA   [IPV6]: Check con...
902
  	int connected = 0;
b2bf1e265   Wang Chen   [UDP]: Clean up f...
903
  	int is_udplite = IS_UDPLITE(sk);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
904
  	int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
  
  	/* destination address check */
  	if (sin6) {
  		if (addr_len < offsetof(struct sockaddr, sa_data))
  			return -EINVAL;
  
  		switch (sin6->sin6_family) {
  		case AF_INET6:
  			if (addr_len < SIN6_LEN_RFC2133)
  				return -EINVAL;
  			daddr = &sin6->sin6_addr;
  			break;
  		case AF_INET:
  			goto do_udp_sendmsg;
  		case AF_UNSPEC:
  			msg->msg_name = sin6 = NULL;
  			msg->msg_namelen = addr_len = 0;
  			daddr = NULL;
  			break;
  		default:
  			return -EINVAL;
  		}
  	} else if (!up->pending) {
  		if (sk->sk_state != TCP_ESTABLISHED)
  			return -EDESTADDRREQ;
  		daddr = &np->daddr;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
931
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
  		daddr = NULL;
  
  	if (daddr) {
e773e4faa   Brian Haley   [IPV6]: Add v4map...
935
  		if (ipv6_addr_v4mapped(daddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  			struct sockaddr_in sin;
  			sin.sin_family = AF_INET;
c720c7e83   Eric Dumazet   inet: rename some...
938
  			sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
942
943
944
945
946
947
948
949
950
951
952
  			sin.sin_addr.s_addr = daddr->s6_addr32[3];
  			msg->msg_name = &sin;
  			msg->msg_namelen = sizeof(sin);
  do_udp_sendmsg:
  			if (__ipv6_only_sock(sk))
  				return -ENETUNREACH;
  			return udp_sendmsg(iocb, sk, msg, len);
  		}
  	}
  
  	if (up->pending == AF_INET)
  		return udp_sendmsg(iocb, sk, msg, len);
  
  	/* Rough check on arithmetic overflow,
b59e139bb   YOSHIFUJI Hideaki   [IPv6]: Fix incor...
953
  	   better check is made in ip6_append_data().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
  	   */
  	if (len > INT_MAX - sizeof(struct udphdr))
  		return -EMSGSIZE;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
957

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  	if (up->pending) {
  		/*
  		 * There are pending frames.
  		 * The socket lock must be held while it's corked.
  		 */
  		lock_sock(sk);
  		if (likely(up->pending)) {
  			if (unlikely(up->pending != AF_INET6)) {
  				release_sock(sk);
  				return -EAFNOSUPPORT;
  			}
  			dst = NULL;
  			goto do_append_data;
  		}
  		release_sock(sk);
  	}
  	ulen += sizeof(struct udphdr);
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
975
  	memset(&fl, 0, sizeof(fl));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
  
  	if (sin6) {
  		if (sin6->sin6_port == 0)
  			return -EINVAL;
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
980
  		fl.fl_ip_dport = sin6->sin6_port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
982
983
  		daddr = &sin6->sin6_addr;
  
  		if (np->sndflow) {
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
984
985
986
  			fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
  			if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
  				flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
  				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)
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1004
  			fl.oif = sin6->sin6_scope_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
1007
  	} else {
  		if (sk->sk_state != TCP_ESTABLISHED)
  			return -EDESTADDRREQ;
c720c7e83   Eric Dumazet   inet: rename some...
1008
  		fl.fl_ip_dport = inet->inet_dport;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
  		daddr = &np->daddr;
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1010
  		fl.fl6_flowlabel = np->flow_label;
987905ded   Mitsuru KANDA   [IPV6]: Check con...
1011
  		connected = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
  	}
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1013
1014
  	if (!fl.oif)
  		fl.oif = sk->sk_bound_dev_if;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015

9f690db7f   Yang Hongyang   ipv6: fix the out...
1016
1017
  	if (!fl.oif)
  		fl.oif = np->sticky_pktinfo.ipi6_ifindex;
51953d5bc   Brian Haley   Use sk_mark for I...
1018
  	fl.mark = sk->sk_mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
1021
1022
  	if (msg->msg_controllen) {
  		opt = &opt_space;
  		memset(opt, 0, sizeof(struct ipv6_txoptions));
  		opt->tot_len = sizeof(*opt);
13b52cd44   Brian Haley   IPv6: Add dontfra...
1023
1024
  		err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit,
  					&tclass, &dontfrag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
1028
  		if (err < 0) {
  			fl6_sock_release(flowlabel);
  			return err;
  		}
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1029
1030
  		if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
  			flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
1033
1034
1035
  			if (flowlabel == NULL)
  				return -EINVAL;
  		}
  		if (!(opt->opt_nflen|opt->opt_flen))
  			opt = NULL;
987905ded   Mitsuru KANDA   [IPV6]: Check con...
1036
  		connected = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
  	}
  	if (opt == NULL)
  		opt = np->opt;
df9890c31   YOSHIFUJI Hideaki   [IPV6]: Fix sendi...
1040
1041
1042
  	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
1043

ba4e58eca   Gerrit Renker   [NET]: Supporting...
1044
  	fl.proto = sk->sk_protocol;
876c7f419   Brian Haley   [IPv6]: Change IP...
1045
1046
1047
1048
  	if (!ipv6_addr_any(daddr))
  		ipv6_addr_copy(&fl.fl6_dst, daddr);
  	else
  		fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1049
1050
  	if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
  		ipv6_addr_copy(&fl.fl6_src, &np->saddr);
c720c7e83   Eric Dumazet   inet: rename some...
1051
  	fl.fl_ip_sport = inet->inet_sport;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1052

20c59de2e   Arnaud Ebalard   ipv6: Refactor up...
1053
1054
  	final_p = fl6_update_dst(&fl, opt, &final);
  	if (final_p)
987905ded   Mitsuru KANDA   [IPV6]: Check con...
1055
  		connected = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056

132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1057
1058
  	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
  		fl.oif = np->mcast_oif;
987905ded   Mitsuru KANDA   [IPV6]: Check con...
1059
1060
  		connected = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061

132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1062
  	security_sk_classify_flow(sk, &fl);
beb8d13be   Venkat Yekkirala   [MLSXFRM]: Add fl...
1063

132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1064
  	err = ip6_sk_dst_lookup(sk, &dst, &fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
1067
  	if (err)
  		goto out;
  	if (final_p)
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1068
  		ipv6_addr_copy(&fl.fl6_dst, final_p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069

52479b623   Alexey Dobriyan   netns xfrm: looku...
1070
1071
  	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
  	if (err < 0) {
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1072
1073
1074
1075
1076
  		if (err == -EREMOTE)
  			err = ip6_dst_blackhole(sk, &dst, &fl);
  		if (err < 0)
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
  
  	if (hlimit < 0) {
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1079
  		if (ipv6_addr_is_multicast(&fl.fl6_dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
1081
1082
1083
  			hlimit = np->mcast_hops;
  		else
  			hlimit = np->hop_limit;
  		if (hlimit < 0)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
1084
  			hlimit = ip6_dst_hoplimit(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
  	}
e651f03af   Gerrit Renker   inet6: Conversion...
1086
  	if (tclass < 0)
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1087
  		tclass = np->tclass;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1088

13b52cd44   Brian Haley   IPv6: Add dontfra...
1089
1090
  	if (dontfrag < 0)
  		dontfrag = np->dontfrag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
1093
1094
1095
1096
1097
1098
1099
  	if (msg->msg_flags&MSG_CONFIRM)
  		goto do_confirm;
  back_from_confirm:
  
  	lock_sock(sk);
  	if (unlikely(up->pending)) {
  		/* The socket is already corked while preparing it. */
  		/* ... which is an evident application bug. --ANK */
  		release_sock(sk);
64ce20730   Patrick McHardy   [NET]: Make NETDE...
1100
1101
  		LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
1105
1106
1107
1108
1109
  		err = -EINVAL;
  		goto out;
  	}
  
  	up->pending = AF_INET6;
  
  do_append_data:
  	up->len += ulen;
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1110
1111
  	getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
  	err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1112
  		sizeof(struct udphdr), hlimit, tclass, opt, &fl,
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1113
  		(struct rt6_info*)dst,
13b52cd44   Brian Haley   IPv6: Add dontfra...
1114
  		corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
1117
  	if (err)
  		udp_v6_flush_pending_frames(sk);
  	else if (!corkreq)
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
1118
  		err = udp_v6_push_pending_frames(sk);
1e0c14f49   Herbert Xu   [UDP]: Fix MSG_PR...
1119
1120
  	else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
  		up->pending = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121

a5e7c210f   David S. Miller   [IPV6]: Fix leak ...
1122
1123
1124
  	if (dst) {
  		if (connected) {
  			ip6_dst_store(sk, dst,
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1125
  				      ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
1126
1127
  				      &np->daddr : NULL,
  #ifdef CONFIG_IPV6_SUBTREES
132a55f3c   Herbert Xu   [UDP6]: Fix flowi...
1128
  				      ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
1129
1130
1131
  				      &np->saddr :
  #endif
  				      NULL);
a5e7c210f   David S. Miller   [IPV6]: Fix leak ...
1132
1133
1134
  		} else {
  			dst_release(dst);
  		}
a3c960899   YOSHIFUJI Hideaki   [IPV6] UDP: Possi...
1135
  		dst = NULL;
a5e7c210f   David S. Miller   [IPV6]: Fix leak ...
1136
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
1140
  	if (err > 0)
  		err = np->recverr ? net_xmit_errno(err) : 0;
  	release_sock(sk);
  out:
a3c960899   YOSHIFUJI Hideaki   [IPV6] UDP: Possi...
1141
  	dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	fl6_sock_release(flowlabel);
cd562c985   YOSHIFUJI Hideaki   [IPV6]: Just incr...
1143
  	if (!err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
  		return len;
a18135eb9   David S. Miller   [IPV6]: Add UDP_M...
1145
1146
1147
1148
1149
1150
1151
1152
  	/*
  	 * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space.  Reporting
  	 * ENOBUFS might not be good (it's not tunable per se), but otherwise
  	 * we don't have a good statistic (IpOutDiscards but it can be too many
  	 * things).  We could add another new stat but at least for now that
  	 * seems like overkill.
  	 */
  	if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
235b9f7ac   Pavel Emelyanov   MIB: add struct n...
1153
1154
  		UDP6_INC_STATS_USER(sock_net(sk),
  				UDP_MIB_SNDBUFERRORS, is_udplite);
a18135eb9   David S. Miller   [IPV6]: Add UDP_M...
1155
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
1160
1161
1162
1163
1164
  	return err;
  
  do_confirm:
  	dst_confirm(dst);
  	if (!(msg->msg_flags&MSG_PROBE) || len)
  		goto back_from_confirm;
  	err = 0;
  	goto out;
  }
7d06b2e05   Brian Haley   net: change proto...
1165
  void udpv6_destroy_sock(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
1169
1170
1171
  {
  	lock_sock(sk);
  	udp_v6_flush_pending_frames(sk);
  	release_sock(sk);
  
  	inet6_destroy_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
1176
  }
  
  /*
   *	Socket option code for UDP
   */
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1177
  int udpv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
1178
  		     char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1179
  {
db8dac20d   David S. Miller   [UDP]: Revert udp...
1180
  	if (level == SOL_UDP  ||  level == SOL_UDPLITE)
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
1181
1182
  		return udp_lib_setsockopt(sk, level, optname, optval, optlen,
  					  udp_v6_push_pending_frames);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1183
  	return ipv6_setsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1184
1185
1186
  }
  
  #ifdef CONFIG_COMPAT
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1187
  int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
1188
  			    char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1189
  {
db8dac20d   David S. Miller   [UDP]: Revert udp...
1190
  	if (level == SOL_UDP  ||  level == SOL_UDPLITE)
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
1191
1192
  		return udp_lib_setsockopt(sk, level, optname, optval, optlen,
  					  udp_v6_push_pending_frames);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1193
  	return compat_ipv6_setsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1194
1195
  }
  #endif
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1196
1197
  int udpv6_getsockopt(struct sock *sk, int level, int optname,
  		     char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1198
  {
db8dac20d   David S. Miller   [UDP]: Revert udp...
1199
  	if (level == SOL_UDP  ||  level == SOL_UDPLITE)
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
1200
  		return udp_lib_getsockopt(sk, level, optname, optval, optlen);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1201
  	return ipv6_getsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1202
1203
1204
  }
  
  #ifdef CONFIG_COMPAT
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1205
1206
  int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
  			    char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1207
  {
db8dac20d   David S. Miller   [UDP]: Revert udp...
1208
  	if (level == SOL_UDP  ||  level == SOL_UDPLITE)
4c0a6cb0d   Gerrit Renker   [UDP(-Lite)]: con...
1209
  		return udp_lib_getsockopt(sk, level, optname, optval, optlen);
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1210
  	return compat_ipv6_getsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1211
1212
  }
  #endif
ba7354258   Sridhar Samudrala   udpv6: Handle lar...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
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
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  static int udp6_ufo_send_check(struct sk_buff *skb)
  {
  	struct ipv6hdr *ipv6h;
  	struct udphdr *uh;
  
  	if (!pskb_may_pull(skb, sizeof(*uh)))
  		return -EINVAL;
  
  	ipv6h = ipv6_hdr(skb);
  	uh = udp_hdr(skb);
  
  	uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
  				     IPPROTO_UDP, 0);
  	skb->csum_start = skb_transport_header(skb) - skb->head;
  	skb->csum_offset = offsetof(struct udphdr, check);
  	skb->ip_summed = CHECKSUM_PARTIAL;
  	return 0;
  }
  
  static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features)
  {
  	struct sk_buff *segs = ERR_PTR(-EINVAL);
  	unsigned int mss;
  	unsigned int unfrag_ip6hlen, unfrag_len;
  	struct frag_hdr *fptr;
  	u8 *mac_start, *prevhdr;
  	u8 nexthdr;
  	u8 frag_hdr_sz = sizeof(struct frag_hdr);
  	int offset;
  	__wsum csum;
  
  	mss = skb_shinfo(skb)->gso_size;
  	if (unlikely(skb->len <= mss))
  		goto out;
  
  	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
  		/* Packet is from an untrusted source, reset gso_segs. */
  		int type = skb_shinfo(skb)->gso_type;
  
  		if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
  			     !(type & (SKB_GSO_UDP))))
  			goto out;
  
  		skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
  
  		segs = NULL;
  		goto out;
  	}
  
  	/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
  	 * do checksum of UDP packets sent as multiple IP fragments.
  	 */
  	offset = skb->csum_start - skb_headroom(skb);
  	csum = skb_checksum(skb, offset, skb->len- offset, 0);
  	offset += skb->csum_offset;
  	*(__sum16 *)(skb->data + offset) = csum_fold(csum);
  	skb->ip_summed = CHECKSUM_NONE;
  
  	/* Check if there is enough headroom to insert fragment header. */
  	if ((skb_headroom(skb) < frag_hdr_sz) &&
  	    pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
  		goto out;
  
  	/* Find the unfragmentable header and shift it left by frag_hdr_sz
  	 * bytes to insert fragment header.
  	 */
  	unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
  	nexthdr = *prevhdr;
  	*prevhdr = NEXTHDR_FRAGMENT;
  	unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
  		     unfrag_ip6hlen;
  	mac_start = skb_mac_header(skb);
  	memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
  
  	skb->mac_header -= frag_hdr_sz;
  	skb->network_header -= frag_hdr_sz;
  
  	fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
  	fptr->nexthdr = nexthdr;
  	fptr->reserved = 0;
  	ipv6_select_ident(fptr);
  
  	/* Fragment the skb. ipv6 header and the remaining fields of the
  	 * fragment header are updated in ipv6_gso_segment()
  	 */
  	segs = skb_segment(skb, features);
  
  out:
  	return segs;
  }
41135cc83   Alexey Dobriyan   net: constify str...
1303
  static const struct inet6_protocol udpv6_protocol = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
  	.handler	=	udpv6_rcv,
  	.err_handler	=	udpv6_err,
ba7354258   Sridhar Samudrala   udpv6: Handle lar...
1306
1307
  	.gso_send_check =	udp6_ufo_send_check,
  	.gso_segment	=	udp6_ufo_fragment,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
  	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
  };
  
  /* ------------------------------------------------------------------------ */
  #ifdef CONFIG_PROC_FS
  
  static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket)
  {
  	struct inet_sock *inet = inet_sk(sp);
  	struct ipv6_pinfo *np = inet6_sk(sp);
  	struct in6_addr *dest, *src;
  	__u16 destp, srcp;
  
  	dest  = &np->daddr;
  	src   = &np->rcv_saddr;
c720c7e83   Eric Dumazet   inet: rename some...
1323
1324
  	destp = ntohs(inet->inet_dport);
  	srcp  = ntohs(inet->inet_sport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
  	seq_printf(seq,
f86dcc5aa   Eric Dumazet   udp: dynamically ...
1326
  		   "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
cb61cb9b8   Eric Dumazet   udp: sk_drops han...
1327
1328
  		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
1330
1331
1332
1333
  		   bucket,
  		   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...
1334
  		   sp->sk_state,
31e6d363a   Eric Dumazet   net: correct off-...
1335
1336
  		   sk_wmem_alloc_get(sp),
  		   sk_rmem_alloc_get(sp),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
1339
  		   0, 0L, 0,
  		   sock_i_uid(sp), 0,
  		   sock_i_ino(sp),
cb61cb9b8   Eric Dumazet   udp: sk_drops han...
1340
1341
  		   atomic_read(&sp->sk_refcnt), sp,
  		   atomic_read(&sp->sk_drops));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
  }
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1343
  int udp6_seq_show(struct seq_file *seq, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
1347
1348
1349
1350
  {
  	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...
1351
1352
  			   "   uid  timeout inode ref pointer drops
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
1354
1355
1356
  	else
  		udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
  static struct udp_seq_afinfo udp6_seq_afinfo = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
  	.name		= "udp6",
  	.family		= AF_INET6,
645ca708f   Eric Dumazet   udp: introduce st...
1360
  	.udp_table	= &udp_table,
4ad96d39a   Denis V. Lunev   [UDP]: Remove own...
1361
1362
1363
  	.seq_fops	= {
  		.owner	=	THIS_MODULE,
  	},
dda61925f   Denis V. Lunev   [UDP]: Move seq_o...
1364
1365
1366
  	.seq_ops	= {
  		.show		= udp6_seq_show,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
1368
  int __net_init udp6_proc_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
  {
0c96d8c50   Daniel Lezcano   [NETNS][IPV6] udp...
1370
  	return udp_proc_register(net, &udp6_seq_afinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
  }
0c96d8c50   Daniel Lezcano   [NETNS][IPV6] udp...
1372
1373
  void udp6_proc_exit(struct net *net) {
  	udp_proc_unregister(net, &udp6_seq_afinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
1376
1377
1378
1379
  }
  #endif /* CONFIG_PROC_FS */
  
  /* ------------------------------------------------------------------------ */
  
  struct proto udpv6_prot = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1380
1381
  	.name		   = "UDPv6",
  	.owner		   = THIS_MODULE,
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1382
  	.close		   = udp_lib_close,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1383
1384
1385
1386
1387
1388
1389
1390
1391
  	.connect	   = ip6_datagram_connect,
  	.disconnect	   = udp_disconnect,
  	.ioctl		   = udp_ioctl,
  	.destroy	   = udpv6_destroy_sock,
  	.setsockopt	   = udpv6_setsockopt,
  	.getsockopt	   = udpv6_getsockopt,
  	.sendmsg	   = udpv6_sendmsg,
  	.recvmsg	   = udpv6_recvmsg,
  	.backlog_rcv	   = udpv6_queue_rcv_skb,
ba4e58eca   Gerrit Renker   [NET]: Supporting...
1392
1393
  	.hash		   = udp_lib_hash,
  	.unhash		   = udp_lib_unhash,
719f83585   Eric Dumazet   udp: add rehash o...
1394
  	.rehash		   = udp_v6_rehash,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1395
  	.get_port	   = udp_v6_get_port,
95766fff6   Hideo Aoki   [UDP]: Add memory...
1396
1397
1398
1399
  	.memory_allocated  = &udp_memory_allocated,
  	.sysctl_mem	   = sysctl_udp_mem,
  	.sysctl_wmem	   = &sysctl_udp_wmem_min,
  	.sysctl_rmem	   = &sysctl_udp_rmem_min,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1400
  	.obj_size	   = sizeof(struct udp6_sock),
271b72c7f   Eric Dumazet   udp: RCU handling...
1401
  	.slab_flags	   = SLAB_DESTROY_BY_RCU,
645ca708f   Eric Dumazet   udp: introduce st...
1402
  	.h.udp_table	   = &udp_table,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1403
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1404
1405
  	.compat_setsockopt = compat_udpv6_setsockopt,
  	.compat_getsockopt = compat_udpv6_getsockopt,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1406
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
1411
1412
  static struct inet_protosw udpv6_protosw = {
  	.type =      SOCK_DGRAM,
  	.protocol =  IPPROTO_UDP,
  	.prot =      &udpv6_prot,
  	.ops =       &inet6_dgram_ops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
1414
1415
  	.no_check =  UDP_CSUM_DEFAULT,
  	.flags =     INET_PROTOSW_PERMANENT,
  };
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1416
  int __init udpv6_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417
  {
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
  	int ret;
  
  	ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
  	if (ret)
  		goto out;
  
  	ret = inet6_register_protosw(&udpv6_protosw);
  	if (ret)
  		goto out_udpv6_protocol;
  out:
  	return ret;
  
  out_udpv6_protocol:
  	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
  	goto out;
  }
09f7709f4   Daniel Lezcano   [IPV6]: fix secti...
1434
  void udpv6_exit(void)
7f4e4868f   Daniel Lezcano   [IPV6]: make the ...
1435
1436
1437
  {
  	inet6_unregister_protosw(&udpv6_protosw);
  	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
  }