Blame view

net/ipv6/ip6_output.c 41.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *	IPv6 output functions
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
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   *	Based on linux/net/ipv4/ip_output.c
   *
   *	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.
   *
   *	Changes:
   *	A.N.Kuznetsov	:	airthmetics in fragmentation.
   *				extension headers are implemented.
   *				route changes now work.
   *				ip6_forward does not confuse sniffers.
   *				etc.
   *
   *      H. von Brand    :       Added missing #include <linux/string.h>
   *	Imran Patel	: 	frag id should be in NBO
   *      Kazunori MIYAZAWA @USAGI
   *			:       add ip6_append_data and related functions
   *				for datagram xmit
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/errno.h>
ef76bc23e   Herbert Xu   [IPV6]: Add ip6_l...
29
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
  #include <linux/string.h>
  #include <linux/socket.h>
  #include <linux/net.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/in6.h>
  #include <linux/tcp.h>
  #include <linux/route.h>
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
38
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv6.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/addrconf.h>
  #include <net/rawv6.h>
  #include <net/icmp.h>
  #include <net/xfrm.h>
  #include <net/checksum.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
56
  #include <linux/mroute6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

ad0081e43   David Stevens   ipv6: Fragment lo...
58
  int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

ef76bc23e   Herbert Xu   [IPV6]: Add ip6_l...
60
61
62
63
64
65
66
67
  int __ip6_local_out(struct sk_buff *skb)
  {
  	int len;
  
  	len = skb->len - sizeof(struct ipv6hdr);
  	if (len > IPV6_MAXPLEN)
  		len = 0;
  	ipv6_hdr(skb)->payload_len = htons(len);
b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
68
69
  	return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
  		       skb_dst(skb)->dev, dst_output);
ef76bc23e   Herbert Xu   [IPV6]: Add ip6_l...
70
71
72
73
74
75
76
77
78
79
80
81
82
  }
  
  int ip6_local_out(struct sk_buff *skb)
  {
  	int err;
  
  	err = __ip6_local_out(skb);
  	if (likely(err == 1))
  		err = dst_output(skb);
  
  	return err;
  }
  EXPORT_SYMBOL_GPL(ip6_local_out);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
  /* dev_loopback_xmit for use with netfilter. */
  static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
  {
459a98ed8   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
86
  	skb_reset_mac_header(newskb);
bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
87
  	__skb_pull(newskb, skb_network_offset(newskb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
  	newskb->pkt_type = PACKET_LOOPBACK;
  	newskb->ip_summed = CHECKSUM_UNNECESSARY;
adf30907d   Eric Dumazet   net: skb->dst acc...
90
  	WARN_ON(!skb_dst(newskb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

e30b38c29   Eric Dumazet   ip: Fix ip_dev_lo...
92
  	netif_rx_ni(newskb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  	return 0;
  }
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
95
  static int ip6_finish_output2(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
97
  	struct dst_entry *dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  	struct net_device *dev = dst->dev;
f6b72b621   David S. Miller   net: Embed hh_cac...
99
  	struct neighbour *neigh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
  
  	skb->protocol = htons(ETH_P_IPV6);
  	skb->dev = dev;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
103
  	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
adf30907d   Eric Dumazet   net: skb->dst acc...
104
  		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

7ad6848c7   Octavian Purdila   ip: fix mc_loop c...
106
  		if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
107
  		    ((mroute6_socket(dev_net(dev), skb) &&
bd91b8bf3   Benjamin Thery   netns: ip6mr: all...
108
  		     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
109
110
  		     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
  					 &ipv6_hdr(skb)->saddr))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
  			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
  
  			/* Do not check for IFF_ALLMULTI; multicast routing
  			   is not supported in any case.
  			 */
  			if (newskb)
b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
117
118
  				NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
  					newskb, NULL, newskb->dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  					ip6_dev_loopback_xmit);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
120
  			if (ipv6_hdr(skb)->hop_limit == 0) {
3bd653c84   Denis V. Lunev   netns: add net pa...
121
122
  				IP6_INC_STATS(dev_net(dev), idev,
  					      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
  				kfree_skb(skb);
  				return 0;
  			}
  		}
edf391ff1   Neil Horman   snmp: add missing...
127
128
  		IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST,
  				skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  	}
f2c31e32b   Eric Dumazet   net: fix NULL der...
130
  	rcu_read_lock();
272174550   David Miller   net: Rename dst_g...
131
  	neigh = dst_get_neighbour_noref(dst);
f2c31e32b   Eric Dumazet   net: fix NULL der...
132
133
  	if (neigh) {
  		int res = neigh_output(neigh, skb);
05e3aa094   David S. Miller   net: Create and u...
134

f2c31e32b   Eric Dumazet   net: fix NULL der...
135
136
137
138
  		rcu_read_unlock();
  		return res;
  	}
  	rcu_read_unlock();
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
139
140
141
142
  	IP6_INC_STATS_BH(dev_net(dst->dev),
  			 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
  	kfree_skb(skb);
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  }
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
144
145
146
147
148
149
150
151
  static int ip6_finish_output(struct sk_buff *skb)
  {
  	if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
  	    dst_allfrag(skb_dst(skb)))
  		return ip6_fragment(skb, ip6_finish_output2);
  	else
  		return ip6_finish_output2(skb);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  int ip6_output(struct sk_buff *skb)
  {
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
154
  	struct net_device *dev = skb_dst(skb)->dev;
adf30907d   Eric Dumazet   net: skb->dst acc...
155
  	struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
778d80be5   YOSHIFUJI Hideaki   ipv6: Add disable...
156
  	if (unlikely(idev->cnf.disable_ipv6)) {
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
157
  		IP6_INC_STATS(dev_net(dev), idev,
3bd653c84   Denis V. Lunev   netns: add net pa...
158
  			      IPSTATS_MIB_OUTDISCARDS);
778d80be5   YOSHIFUJI Hideaki   ipv6: Add disable...
159
160
161
  		kfree_skb(skb);
  		return 0;
  	}
9c6eb28ac   Jan Engelhardt   netfilter: ipv6: ...
162
163
164
  	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
  			    ip6_finish_output,
  			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  /*
b5d439982   Shan Wei   ipv6: fix the com...
167
   *	xmit an sk_buff (used by TCP, SCTP and DCCP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
   */
4c9483b2f   David S. Miller   ipv6: Convert to ...
169
  int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
b903d324b   Eric Dumazet   ipv6: tcp: fix TC...
170
  	     struct ipv6_txoptions *opt, int tclass)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  {
3bd653c84   Denis V. Lunev   netns: add net pa...
172
  	struct net *net = sock_net(sk);
b30bd282c   Patrick McHardy   [IPV6]: ip6_xmit:...
173
  	struct ipv6_pinfo *np = inet6_sk(sk);
4c9483b2f   David S. Miller   ipv6: Convert to ...
174
  	struct in6_addr *first_hop = &fl6->daddr;
adf30907d   Eric Dumazet   net: skb->dst acc...
175
  	struct dst_entry *dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  	struct ipv6hdr *hdr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
177
  	u8  proto = fl6->flowi6_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	int seg_len = skb->len;
e651f03af   Gerrit Renker   inet6: Conversion...
179
  	int hlimit = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  	u32 mtu;
  
  	if (opt) {
c2636b4d9   Chuck Lever   [NET]: Treat the ...
183
  		unsigned int head_room;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
  
  		/* First: exthdrs may take lots of space (~8K for now)
  		   MAX_HEADER is not enough.
  		 */
  		head_room = opt->opt_nflen + opt->opt_flen;
  		seg_len += head_room;
  		head_room += sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
  
  		if (skb_headroom(skb) < head_room) {
  			struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
194
  			if (skb2 == NULL) {
adf30907d   Eric Dumazet   net: skb->dst acc...
195
  				IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
196
197
  					      IPSTATS_MIB_OUTDISCARDS);
  				kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
  				return -ENOBUFS;
  			}
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
200
201
  			kfree_skb(skb);
  			skb = skb2;
83d7eb297   Dan Carpenter   ipv6: cleanup: re...
202
  			skb_set_owner_w(skb, sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
  		}
  		if (opt->opt_flen)
  			ipv6_push_frag_opts(skb, opt, &proto);
  		if (opt->opt_nflen)
  			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
  	}
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
209
210
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
211
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
  
  	/*
  	 *	Fill in the IPv6 header
  	 */
b903d324b   Eric Dumazet   ipv6: tcp: fix TC...
216
  	if (np)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  		hlimit = np->hop_limit;
  	if (hlimit < 0)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
219
  		hlimit = ip6_dst_hoplimit(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

4c9483b2f   David S. Miller   ipv6: Convert to ...
221
  	*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
222

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  	hdr->payload_len = htons(seg_len);
  	hdr->nexthdr = proto;
  	hdr->hop_limit = hlimit;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
226
227
  	hdr->saddr = fl6->saddr;
  	hdr->daddr = *first_hop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
229
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
230
  	skb->mark = sk->sk_mark;
a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
231

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	mtu = dst_mtu(dst);
283d07ac2   Wei Yongjun   ipv6: Do not drop...
233
  	if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
adf30907d   Eric Dumazet   net: skb->dst acc...
234
  		IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
edf391ff1   Neil Horman   snmp: add missing...
235
  			      IPSTATS_MIB_OUT, skb->len);
b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
236
237
  		return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
  			       dst->dev, dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
  	}
  
  	if (net_ratelimit())
  		printk(KERN_DEBUG "IPv6: sending pkt_too_big to self
  ");
  	skb->dev = dst->dev;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
244
  	icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
adf30907d   Eric Dumazet   net: skb->dst acc...
245
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
  	kfree_skb(skb);
  	return -EMSGSIZE;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
249
  EXPORT_SYMBOL(ip6_xmit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
257
  /*
   *	To avoid extra problems ND packets are send through this
   *	routine. It's code duplication but I really want to avoid
   *	extra checks since ipv6_build_header is used by TCP (which
   *	is for us performance critical)
   */
  
  int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
258
  	       const struct in6_addr *saddr, const struct in6_addr *daddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
  	       int proto, int len)
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct ipv6hdr *hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
  
  	skb->protocol = htons(ETH_P_IPV6);
  	skb->dev = dev;
55f79cc0c   Arnaldo Carvalho de Melo   [IPV6]: Reset the...
266
267
  	skb_reset_network_header(skb);
  	skb_put(skb, sizeof(struct ipv6hdr));
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
268
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

ae08e1f09   Al Viro   [IPV6]: ip6_outpu...
270
  	*(__be32*)hdr = htonl(0x60000000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
  
  	hdr->payload_len = htons(len);
  	hdr->nexthdr = proto;
  	hdr->hop_limit = np->hop_limit;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
275
276
  	hdr->saddr = *saddr;
  	hdr->daddr = *daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
282
283
284
285
286
287
288
  
  	return 0;
  }
  
  static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
  {
  	struct ip6_ra_chain *ra;
  	struct sock *last = NULL;
  
  	read_lock(&ip6_ra_lock);
  	for (ra = ip6_ra_chain; ra; ra = ra->next) {
  		struct sock *sk = ra->sk;
0bd1b59b1   Andrew McDonald   [IPV6]: Check int...
289
290
291
  		if (sk && ra->sel == sel &&
  		    (!sk->sk_bound_dev_if ||
  		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  			if (last) {
  				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
  				if (skb2)
  					rawv6_rcv(last, skb2);
  			}
  			last = sk;
  		}
  	}
  
  	if (last) {
  		rawv6_rcv(last, skb);
  		read_unlock(&ip6_ra_lock);
  		return 1;
  	}
  	read_unlock(&ip6_ra_lock);
  	return 0;
  }
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
309
310
  static int ip6_forward_proxy_check(struct sk_buff *skb)
  {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
311
  	struct ipv6hdr *hdr = ipv6_hdr(skb);
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
312
  	u8 nexthdr = hdr->nexthdr;
75f2811c6   Jesse Gross   ipv6: Add fragmen...
313
  	__be16 frag_off;
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
314
315
316
  	int offset;
  
  	if (ipv6_ext_hdr(nexthdr)) {
75f2811c6   Jesse Gross   ipv6: Add fragmen...
317
  		offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off);
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
318
319
320
321
322
323
324
  		if (offset < 0)
  			return 0;
  	} else
  		offset = sizeof(struct ipv6hdr);
  
  	if (nexthdr == IPPROTO_ICMPV6) {
  		struct icmp6hdr *icmp6;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
325
326
  		if (!pskb_may_pull(skb, (skb_network_header(skb) +
  					 offset + 1 - skb->data)))
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
327
  			return 0;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
328
  		icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  
  		switch (icmp6->icmp6_type) {
  		case NDISC_ROUTER_SOLICITATION:
  		case NDISC_ROUTER_ADVERTISEMENT:
  		case NDISC_NEIGHBOUR_SOLICITATION:
  		case NDISC_NEIGHBOUR_ADVERTISEMENT:
  		case NDISC_REDIRECT:
  			/* For reaction involving unicast neighbor discovery
  			 * message destined to the proxied address, pass it to
  			 * input function.
  			 */
  			return 1;
  		default:
  			break;
  		}
  	}
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
345
346
347
348
349
350
351
352
353
  	/*
  	 * The proxying router can't forward traffic sent to a link-local
  	 * address, so signal the sender and discard the packet. This
  	 * behavior is clarified by the MIPv6 specification.
  	 */
  	if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) {
  		dst_link_failure(skb);
  		return -1;
  	}
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
354
355
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
360
361
362
  static inline int ip6_forward_finish(struct sk_buff *skb)
  {
  	return dst_output(skb);
  }
  
  int ip6_forward(struct sk_buff *skb)
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
363
  	struct dst_entry *dst = skb_dst(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
364
  	struct ipv6hdr *hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  	struct inet6_skb_parm *opt = IP6CB(skb);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
366
  	struct net *net = dev_net(dst->dev);
69cce1d14   David S. Miller   net: Abstract dst...
367
  	struct neighbour *n;
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
368
  	u32 mtu;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
369

53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
370
  	if (net->ipv6.devconf_all->forwarding == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  		goto error;
4497b0763   Ben Hutchings   net: Discard and ...
372
373
  	if (skb_warn_if_lro(skb))
  		goto drop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
3bd653c84   Denis V. Lunev   netns: add net pa...
375
  		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  		goto drop;
  	}
72b43d089   Alexey Kuznetsov   inet6: prevent ne...
378
379
  	if (skb->pkt_type != PACKET_HOST)
  		goto drop;
35fc92a9d   Herbert Xu   [NET]: Allow forw...
380
  	skb_forward_csum(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  
  	/*
  	 *	We DO NOT make any processing on
  	 *	RA packets, pushing them to user level AS IS
  	 *	without ane WARRANTY that application will be able
  	 *	to interpret them. The reason is that we
  	 *	cannot make anything clever here.
  	 *
  	 *	We are not end-node, so that if packet contains
  	 *	AH/ESP, we cannot make anything.
  	 *	Defragmentation also would be mistake, RA packets
  	 *	cannot be fragmented, because there is no warranty
  	 *	that different fragments will go along one path. --ANK
  	 */
  	if (opt->ra) {
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
396
  		u8 *ptr = skb_network_header(skb) + opt->ra;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
405
406
  		if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3]))
  			return 0;
  	}
  
  	/*
  	 *	check and decrement ttl
  	 */
  	if (hdr->hop_limit <= 1) {
  		/* Force OUTPUT device used as source address */
  		skb->dev = dst->dev;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
407
  		icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
483a47d2f   Denis V. Lunev   ipv6: added net a...
408
409
  		IP6_INC_STATS_BH(net,
  				 ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
  
  		kfree_skb(skb);
  		return -ETIMEDOUT;
  	}
fbea49e1e   YOSHIFUJI Hideaki   [IPV6] NDISC: Add...
414
  	/* XXX: idev->cnf.proxy_ndp? */
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
415
  	if (net->ipv6.devconf_all->proxy_ndp &&
8a3edd800   Daniel Lezcano   [NETNS][IPV6] fix...
416
  	    pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
417
418
  		int proxied = ip6_forward_proxy_check(skb);
  		if (proxied > 0)
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
419
  			return ip6_input(skb);
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
420
  		else if (proxied < 0) {
3bd653c84   Denis V. Lunev   netns: add net pa...
421
422
  			IP6_INC_STATS(net, ip6_dst_idev(dst),
  				      IPSTATS_MIB_INDISCARDS);
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
423
424
  			goto drop;
  		}
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
425
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  	if (!xfrm6_route_forward(skb)) {
3bd653c84   Denis V. Lunev   netns: add net pa...
427
  		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
  		goto drop;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
430
  	dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
  
  	/* IPv6 specs say nothing about it, but it is clear that we cannot
  	   send redirects to source routed frames.
1e5dc1461   Masahide NAKAMURA   [IPV6] IPSEC: Omi...
434
  	   We don't send redirects to frames decapsulated from IPsec.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  	 */
272174550   David Miller   net: Rename dst_g...
436
  	n = dst_get_neighbour_noref(dst);
69cce1d14   David S. Miller   net: Abstract dst...
437
  	if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  		struct in6_addr *target = NULL;
  		struct rt6_info *rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
443
444
445
446
447
448
449
450
  
  		/*
  		 *	incoming and outgoing devices are the same
  		 *	send a redirect.
  		 */
  
  		rt = (struct rt6_info *) dst;
  		if ((rt->rt6i_flags & RTF_GATEWAY))
  			target = (struct in6_addr*)&n->primary_key;
  		else
  			target = &hdr->daddr;
92d868292   David S. Miller   inetpeer: Move IC...
451
452
  		if (!rt->rt6i_peer)
  			rt6_bind_peer(rt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
  		/* Limit redirects both by destination (here)
  		   and by source (inside ndisc_send_redirect)
  		 */
92d868292   David S. Miller   inetpeer: Move IC...
456
  		if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  			ndisc_send_redirect(skb, n, target);
5bb1ab09e   David L Stevens   [IPV6]: Send ICMP...
458
459
  	} else {
  		int addrtype = ipv6_addr_type(&hdr->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  		/* This check is security critical. */
f81b2e7d8   YOSHIFUJI Hideaki   ipv6: Do not forw...
461
462
  		if (addrtype == IPV6_ADDR_ANY ||
  		    addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
5bb1ab09e   David L Stevens   [IPV6]: Send ICMP...
463
464
465
  			goto error;
  		if (addrtype & IPV6_ADDR_LINKLOCAL) {
  			icmpv6_send(skb, ICMPV6_DEST_UNREACH,
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
466
  				    ICMPV6_NOT_NEIGHBOUR, 0);
5bb1ab09e   David L Stevens   [IPV6]: Send ICMP...
467
468
  			goto error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  	}
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
470
471
472
  	mtu = dst_mtu(dst);
  	if (mtu < IPV6_MIN_MTU)
  		mtu = IPV6_MIN_MTU;
0aa682715   Herbert Xu   ipv6: Add GSO sup...
473
  	if (skb->len > mtu && !skb_is_gso(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
  		/* Again, force OUTPUT device used as source address */
  		skb->dev = dst->dev;
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
476
  		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
483a47d2f   Denis V. Lunev   ipv6: added net a...
477
478
479
480
  		IP6_INC_STATS_BH(net,
  				 ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
  		IP6_INC_STATS_BH(net,
  				 ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
  		kfree_skb(skb);
  		return -EMSGSIZE;
  	}
  
  	if (skb_cow(skb, dst->dev->hard_header_len)) {
3bd653c84   Denis V. Lunev   netns: add net pa...
486
  		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  		goto drop;
  	}
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
489
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  
  	/* Mangling hops number delayed to point after skb COW */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
492

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  	hdr->hop_limit--;
483a47d2f   Denis V. Lunev   ipv6: added net a...
494
  	IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
495
  	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
496
  		       ip6_forward_finish);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  
  error:
483a47d2f   Denis V. Lunev   ipv6: added net a...
499
  	IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
503
504
505
506
507
508
509
  drop:
  	kfree_skb(skb);
  	return -EINVAL;
  }
  
  static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
  {
  	to->pkt_type = from->pkt_type;
  	to->priority = from->priority;
  	to->protocol = from->protocol;
adf30907d   Eric Dumazet   net: skb->dst acc...
510
511
  	skb_dst_drop(to);
  	skb_dst_set(to, dst_clone(skb_dst(from)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  	to->dev = from->dev;
82e91ffef   Thomas Graf   [NET]: Turn nfmar...
513
  	to->mark = from->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
  
  #ifdef CONFIG_NET_SCHED
  	to->tc_index = from->tc_index;
  #endif
e7ac05f34   Yasuyuki Kozakai   [NETFILTER]: nf_c...
518
  	nf_copy(to, from);
ba9dda3ab   Jozsef Kadlecsik   [NETFILTER]: x_ta...
519
520
521
522
  #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
      defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
  	to->nf_trace = from->nf_trace;
  #endif
984bc16cc   James Morris   [SECMARK]: Add se...
523
  	skb_copy_secmark(to, from);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
  }
  
  int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
  {
  	u16 offset = sizeof(struct ipv6hdr);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
529
530
  	struct ipv6_opt_hdr *exthdr =
  				(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
531
  	unsigned int packet_len = skb->tail - skb->network_header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  	int found_rhdr = 0;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
533
  	*nexthdr = &ipv6_hdr(skb)->nexthdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
538
539
  
  	while (offset + 1 <= packet_len) {
  
  		switch (**nexthdr) {
  
  		case NEXTHDR_HOP:
27637df92   Masahide NAKAMURA   [IPV6] IPSEC: Sup...
540
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  		case NEXTHDR_ROUTING:
27637df92   Masahide NAKAMURA   [IPV6] IPSEC: Sup...
542
543
  			found_rhdr = 1;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  		case NEXTHDR_DEST:
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
545
  #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
27637df92   Masahide NAKAMURA   [IPV6] IPSEC: Sup...
546
547
548
549
550
  			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
  				break;
  #endif
  			if (found_rhdr)
  				return offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
  			break;
  		default :
  			return offset;
  		}
27637df92   Masahide NAKAMURA   [IPV6] IPSEC: Sup...
555
556
557
  
  		offset += ipv6_optlen(exthdr);
  		*nexthdr = &exthdr->nexthdr;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
558
559
  		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
  						 offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
  	}
  
  	return offset;
  }
87c48fa3b   Eric Dumazet   ipv6: make fragme...
564
565
566
567
  void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
  {
  	static atomic_t ipv6_fragmentation_id;
  	int old, new;
e688a6048   Eric Dumazet   net: introduce DS...
568
  	if (rt && !(rt->dst.flags & DST_NOPEER)) {
87c48fa3b   Eric Dumazet   ipv6: make fragme...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  		struct inet_peer *peer;
  
  		if (!rt->rt6i_peer)
  			rt6_bind_peer(rt, 1);
  		peer = rt->rt6i_peer;
  		if (peer) {
  			fhdr->identification = htonl(inet_getid(peer, 0));
  			return;
  		}
  	}
  	do {
  		old = atomic_read(&ipv6_fragmentation_id);
  		new = old + 1;
  		if (!new)
  			new = 1;
  	} while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
  	fhdr->identification = htonl(new);
  }
ad0081e43   David Stevens   ipv6: Fragment lo...
587
  int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  	struct sk_buff *frag;
adf30907d   Eric Dumazet   net: skb->dst acc...
590
  	struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
d91675f9c   YOSHIFUJI Hideaki   [IPV6]: Do not ig...
591
  	struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
  	struct ipv6hdr *tmp_hdr;
  	struct frag_hdr *fh;
  	unsigned int mtu, hlen, left, len;
a7ae19922   Herbert Xu   ipv6: Remove all ...
595
  	int hroom, troom;
ae08e1f09   Al Viro   [IPV6]: ip6_outpu...
596
  	__be32 frag_id = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  	int ptr, offset = 0, err=0;
  	u8 *prevhdr, nexthdr = 0;
adf30907d   Eric Dumazet   net: skb->dst acc...
599
  	struct net *net = dev_net(skb_dst(skb)->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
  	hlen = ip6_find_1stfragopt(skb, &prevhdr);
  	nexthdr = *prevhdr;
628a5c561   John Heffner   [INET]: Add IP(V6...
603
  	mtu = ip6_skb_dst_mtu(skb);
b881ef760   John Heffner   [IPV6]: MTU disco...
604
605
  
  	/* We must not fragment if the socket is set to force MTU discovery
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
606
  	 * or if the skb it not generated by a local socket.
b881ef760   John Heffner   [IPV6]: MTU disco...
607
  	 */
f2228f785   Shan Wei   ipv6: allow to se...
608
  	if (!skb->local_df && skb->len > mtu) {
adf30907d   Eric Dumazet   net: skb->dst acc...
609
  		skb->dev = skb_dst(skb)->dev;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
610
  		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
adf30907d   Eric Dumazet   net: skb->dst acc...
611
  		IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
3bd653c84   Denis V. Lunev   netns: add net pa...
612
  			      IPSTATS_MIB_FRAGFAILS);
b881ef760   John Heffner   [IPV6]: MTU disco...
613
614
615
  		kfree_skb(skb);
  		return -EMSGSIZE;
  	}
d91675f9c   YOSHIFUJI Hideaki   [IPV6]: Do not ig...
616
617
618
619
620
  	if (np && np->frag_size < mtu) {
  		if (np->frag_size)
  			mtu = np->frag_size;
  	}
  	mtu -= hlen + sizeof(struct frag_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

21dc33015   David S. Miller   net: Rename skb_h...
622
  	if (skb_has_frag_list(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  		int first_len = skb_pagelen(skb);
3d13008e7   Eric Dumazet   ip: fix truesize ...
624
  		struct sk_buff *frag2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
  
  		if (first_len - hlen > mtu ||
  		    ((first_len - hlen) & 7) ||
  		    skb_cloned(skb))
  			goto slow_path;
4d9092bb4   David S. Miller   ipv6: Use frag li...
630
  		skb_walk_frags(skb, frag) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
  			/* Correct geometry. */
  			if (frag->len > mtu ||
  			    ((frag->len & 7) && frag->next) ||
  			    skb_headroom(frag) < hlen)
3d13008e7   Eric Dumazet   ip: fix truesize ...
635
  				goto slow_path_clean;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  			/* Partially cloned skb? */
  			if (skb_shared(frag))
3d13008e7   Eric Dumazet   ip: fix truesize ...
639
  				goto slow_path_clean;
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
640
641
642
  
  			BUG_ON(frag->sk);
  			if (skb->sk) {
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
643
644
  				frag->sk = skb->sk;
  				frag->destructor = sock_wfree;
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
645
  			}
3d13008e7   Eric Dumazet   ip: fix truesize ...
646
  			skb->truesize -= frag->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
  		}
  
  		err = 0;
  		offset = 0;
  		frag = skb_shinfo(skb)->frag_list;
4d9092bb4   David S. Miller   ipv6: Use frag li...
652
  		skb_frag_list_init(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  		/* BUILD HEADER */
9a217a1c7   YOSHIFUJI Hideaki   [IPV6]: Repair IP...
654
  		*prevhdr = NEXTHDR_FRAGMENT;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
655
  		tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  		if (!tmp_hdr) {
adf30907d   Eric Dumazet   net: skb->dst acc...
657
  			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
3bd653c84   Denis V. Lunev   netns: add net pa...
658
  				      IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
  			return -ENOMEM;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  		__skb_pull(skb, hlen);
  		fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
663
664
  		__skb_push(skb, hlen);
  		skb_reset_network_header(skb);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
665
  		memcpy(skb_network_header(skb), tmp_hdr, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666

87c48fa3b   Eric Dumazet   ipv6: make fragme...
667
  		ipv6_select_ident(fh, rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
673
674
675
  		fh->nexthdr = nexthdr;
  		fh->reserved = 0;
  		fh->frag_off = htons(IP6_MF);
  		frag_id = fh->identification;
  
  		first_len = skb_pagelen(skb);
  		skb->data_len = first_len - skb_headlen(skb);
  		skb->len = first_len;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
676
677
  		ipv6_hdr(skb)->payload_len = htons(first_len -
  						   sizeof(struct ipv6hdr));
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
678

d8d1f30b9   Changli Gao   net-next: remove ...
679
  		dst_hold(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
684
685
  
  		for (;;) {
  			/* Prepare header of the next frame,
  			 * before previous one went down. */
  			if (frag) {
  				frag->ip_summed = CHECKSUM_NONE;
badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
686
  				skb_reset_transport_header(frag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  				fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
688
689
  				__skb_push(frag, hlen);
  				skb_reset_network_header(frag);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
690
691
  				memcpy(skb_network_header(frag), tmp_hdr,
  				       hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
697
698
  				offset += skb->len - hlen - sizeof(struct frag_hdr);
  				fh->nexthdr = nexthdr;
  				fh->reserved = 0;
  				fh->frag_off = htons(offset);
  				if (frag->next != NULL)
  					fh->frag_off |= htons(IP6_MF);
  				fh->identification = frag_id;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
699
700
701
  				ipv6_hdr(frag)->payload_len =
  						htons(frag->len -
  						      sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  				ip6_copy_metadata(frag, skb);
  			}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
704

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  			err = output(skb);
dafee4908   Wei Dong   [IPV6]: SNMPv2 "i...
706
  			if(!err)
d8d1f30b9   Changli Gao   net-next: remove ...
707
  				IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
708
  					      IPSTATS_MIB_FRAGCREATES);
dafee4908   Wei Dong   [IPV6]: SNMPv2 "i...
709

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
714
715
716
  			if (err || !frag)
  				break;
  
  			skb = frag;
  			frag = skb->next;
  			skb->next = NULL;
  		}
a51482bde   Jesper Juhl   [NET]: kfree cleanup
717
  		kfree(tmp_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
  
  		if (err == 0) {
d8d1f30b9   Changli Gao   net-next: remove ...
720
  			IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
721
  				      IPSTATS_MIB_FRAGOKS);
d8d1f30b9   Changli Gao   net-next: remove ...
722
  			dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
725
726
727
728
729
730
  			return 0;
  		}
  
  		while (frag) {
  			skb = frag->next;
  			kfree_skb(frag);
  			frag = skb;
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
731
  		IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
732
  			      IPSTATS_MIB_FRAGFAILS);
d8d1f30b9   Changli Gao   net-next: remove ...
733
  		dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  		return err;
3d13008e7   Eric Dumazet   ip: fix truesize ...
735
736
737
738
739
740
741
742
743
  
  slow_path_clean:
  		skb_walk_frags(skb, frag2) {
  			if (frag2 == frag)
  				break;
  			frag2->sk = NULL;
  			frag2->destructor = NULL;
  			skb->truesize += frag2->truesize;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
749
750
751
752
753
754
  	}
  
  slow_path:
  	left = skb->len - hlen;		/* Space per frame */
  	ptr = hlen;			/* Where to start from */
  
  	/*
  	 *	Fragment the datagram.
  	 */
  
  	*prevhdr = NEXTHDR_FRAGMENT;
a7ae19922   Herbert Xu   ipv6: Remove all ...
755
756
  	hroom = LL_RESERVED_SPACE(rt->dst.dev);
  	troom = rt->dst.dev->needed_tailroom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
763
764
765
  
  	/*
  	 *	Keep copying data until we run out.
  	 */
  	while(left > 0)	{
  		len = left;
  		/* IF: it doesn't fit, use 'mtu' - the data space left */
  		if (len > mtu)
  			len = mtu;
25985edce   Lucas De Marchi   Fix common misspe...
766
  		/* IF: we are not sending up to and including the packet end
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
  		   then align the next start on an eight byte boundary */
  		if (len < left)	{
  			len &= ~7;
  		}
  		/*
  		 *	Allocate buffer.
  		 */
a7ae19922   Herbert Xu   ipv6: Remove all ...
774
775
  		if ((frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
  				      hroom + troom, GFP_ATOMIC)) == NULL) {
64ce20730   Patrick McHardy   [NET]: Make NETDE...
776
777
  			NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!
  ");
adf30907d   Eric Dumazet   net: skb->dst acc...
778
  			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
779
  				      IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
784
785
786
787
788
  			err = -ENOMEM;
  			goto fail;
  		}
  
  		/*
  		 *	Set up data on packet
  		 */
  
  		ip6_copy_metadata(frag, skb);
a7ae19922   Herbert Xu   ipv6: Remove all ...
789
  		skb_reserve(frag, hroom);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  		skb_put(frag, len + hlen + sizeof(struct frag_hdr));
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
791
  		skb_reset_network_header(frag);
badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
792
  		fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
793
794
  		frag->transport_header = (frag->network_header + hlen +
  					  sizeof(struct frag_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
801
802
803
804
805
  
  		/*
  		 *	Charge the memory for the fragment to any owner
  		 *	it might possess
  		 */
  		if (skb->sk)
  			skb_set_owner_w(frag, skb->sk);
  
  		/*
  		 *	Copy the packet header into the new buffer.
  		 */
d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
806
  		skb_copy_from_linear_data(skb, skb_network_header(frag), hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
811
812
  
  		/*
  		 *	Build fragment header.
  		 */
  		fh->nexthdr = nexthdr;
  		fh->reserved = 0;
f36d6ab18   Yan Zheng   [IPV6]: Fix ipv6 ...
813
  		if (!frag_id) {
87c48fa3b   Eric Dumazet   ipv6: make fragme...
814
  			ipv6_select_ident(fh, rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
  			frag_id = fh->identification;
  		} else
  			fh->identification = frag_id;
  
  		/*
  		 *	Copy a block of the IP datagram.
  		 */
8984e41d1   Wei Yongjun   [IPV6]: Fix kerne...
822
  		if (skb_copy_bits(skb, ptr, skb_transport_header(frag), len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
828
  			BUG();
  		left -= len;
  
  		fh->frag_off = htons(offset);
  		if (left > 0)
  			fh->frag_off |= htons(IP6_MF);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
829
830
  		ipv6_hdr(frag)->payload_len = htons(frag->len -
  						    sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
835
836
837
  
  		ptr += len;
  		offset += len;
  
  		/*
  		 *	Put this fragment into the sending queue.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
  		err = output(frag);
  		if (err)
  			goto fail;
dafee4908   Wei Dong   [IPV6]: SNMPv2 "i...
841

adf30907d   Eric Dumazet   net: skb->dst acc...
842
  		IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
3bd653c84   Denis V. Lunev   netns: add net pa...
843
  			      IPSTATS_MIB_FRAGCREATES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
845
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
846
  		      IPSTATS_MIB_FRAGOKS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
  	return err;
  
  fail:
adf30907d   Eric Dumazet   net: skb->dst acc...
851
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
852
  		      IPSTATS_MIB_FRAGFAILS);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
853
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
855
  	return err;
  }
b71d1d426   Eric Dumazet   inet: constify ip...
856
857
858
  static inline int ip6_rt_check(const struct rt6key *rt_key,
  			       const struct in6_addr *fl_addr,
  			       const struct in6_addr *addr_cache)
cf6b19825   YOSHIFUJI Hideaki   [IPV6] ROUTE: Int...
859
  {
a02cec215   Eric Dumazet   net: return opera...
860
861
  	return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
  		(addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache));
cf6b19825   YOSHIFUJI Hideaki   [IPV6] ROUTE: Int...
862
  }
497c615ab   Herbert Xu   [IPV6]: Audit all...
863
864
  static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
  					  struct dst_entry *dst,
b71d1d426   Eric Dumazet   inet: constify ip...
865
  					  const struct flowi6 *fl6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  {
497c615ab   Herbert Xu   [IPV6]: Audit all...
867
868
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct rt6_info *rt = (struct rt6_info *)dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869

497c615ab   Herbert Xu   [IPV6]: Audit all...
870
871
872
873
874
875
876
877
  	if (!dst)
  		goto out;
  
  	/* Yes, checking route validity in not connected
  	 * case is not very simple. Take into account,
  	 * that we do not support routing by source, TOS,
  	 * and MSG_DONTROUTE 		--ANK (980726)
  	 *
cf6b19825   YOSHIFUJI Hideaki   [IPV6] ROUTE: Int...
878
879
  	 * 1. ip6_rt_check(): If route was host route,
  	 *    check that cached destination is current.
497c615ab   Herbert Xu   [IPV6]: Audit all...
880
881
882
883
884
885
886
887
888
889
  	 *    If it is network route, we still may
  	 *    check its validity using saved pointer
  	 *    to the last used address: daddr_cache.
  	 *    We do not want to save whole address now,
  	 *    (because main consumer of this service
  	 *    is tcp, which has not this problem),
  	 *    so that the last trick works only on connected
  	 *    sockets.
  	 * 2. oif also should be the same.
  	 */
4c9483b2f   David S. Miller   ipv6: Convert to ...
890
  	if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) ||
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
891
  #ifdef CONFIG_IPV6_SUBTREES
4c9483b2f   David S. Miller   ipv6: Convert to ...
892
  	    ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) ||
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
893
  #endif
4c9483b2f   David S. Miller   ipv6: Convert to ...
894
  	    (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex)) {
497c615ab   Herbert Xu   [IPV6]: Audit all...
895
896
  		dst_release(dst);
  		dst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  	}
497c615ab   Herbert Xu   [IPV6]: Audit all...
898
899
900
901
902
  out:
  	return dst;
  }
  
  static int ip6_dst_lookup_tail(struct sock *sk,
4c9483b2f   David S. Miller   ipv6: Convert to ...
903
  			       struct dst_entry **dst, struct flowi6 *fl6)
497c615ab   Herbert Xu   [IPV6]: Audit all...
904
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
905
  	struct net *net = sock_net(sk);
69cce1d14   David S. Miller   net: Abstract dst...
906
907
908
909
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
  	struct neighbour *n;
  #endif
  	int err;
497c615ab   Herbert Xu   [IPV6]: Audit all...
910

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	if (*dst == NULL)
4c9483b2f   David S. Miller   ipv6: Convert to ...
912
  		*dst = ip6_route_output(net, sk, fl6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
915
  
  	if ((err = (*dst)->error))
  		goto out_err_release;
4c9483b2f   David S. Miller   ipv6: Convert to ...
916
  	if (ipv6_addr_any(&fl6->saddr)) {
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
917
918
919
920
  		struct rt6_info *rt = (struct rt6_info *) *dst;
  		err = ip6_route_get_saddr(net, rt, &fl6->daddr,
  					  sk ? inet6_sk(sk)->srcprefs : 0,
  					  &fl6->saddr);
44456d37b   Olaf Hering   [PATCH] turn many...
921
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  			goto out_err_release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  	}
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
924
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
925
926
927
928
929
930
931
932
  	/*
  	 * Here if the dst entry we've looked up
  	 * has a neighbour entry that is in the INCOMPLETE
  	 * state and the src address from the flow is
  	 * marked as OPTIMISTIC, we release the found
  	 * dst entry and replace it instead with the
  	 * dst entry of the nexthop router
  	 */
f2c31e32b   Eric Dumazet   net: fix NULL der...
933
  	rcu_read_lock();
272174550   David Miller   net: Rename dst_g...
934
  	n = dst_get_neighbour_noref(*dst);
69cce1d14   David S. Miller   net: Abstract dst...
935
  	if (n && !(n->nud_state & NUD_VALID)) {
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
936
  		struct inet6_ifaddr *ifp;
4c9483b2f   David S. Miller   ipv6: Convert to ...
937
  		struct flowi6 fl_gw6;
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
938
  		int redirect;
f2c31e32b   Eric Dumazet   net: fix NULL der...
939
  		rcu_read_unlock();
4c9483b2f   David S. Miller   ipv6: Convert to ...
940
  		ifp = ipv6_get_ifaddr(net, &fl6->saddr,
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
941
942
943
944
945
946
947
948
949
950
951
952
  				      (*dst)->dev, 1);
  
  		redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
  		if (ifp)
  			in6_ifa_put(ifp);
  
  		if (redirect) {
  			/*
  			 * We need to get the dst entry for the
  			 * default router instead
  			 */
  			dst_release(*dst);
4c9483b2f   David S. Miller   ipv6: Convert to ...
953
954
955
  			memcpy(&fl_gw6, fl6, sizeof(struct flowi6));
  			memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr));
  			*dst = ip6_route_output(net, sk, &fl_gw6);
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
956
957
  			if ((err = (*dst)->error))
  				goto out_err_release;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
958
  		}
f2c31e32b   Eric Dumazet   net: fix NULL der...
959
960
  	} else {
  		rcu_read_unlock();
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
961
  	}
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
962
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
964
965
  	return 0;
  
  out_err_release:
ca46f9c83   Mitsuru Chinen   [IPv6] SNMP: Incr...
966
  	if (err == -ENETUNREACH)
483a47d2f   Denis V. Lunev   ipv6: added net a...
967
  		IP6_INC_STATS_BH(net, NULL, IPSTATS_MIB_OUTNOROUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
970
971
  	dst_release(*dst);
  	*dst = NULL;
  	return err;
  }
34a0b3cdc   Adrian Bunk   [IPV6]: make two ...
972

497c615ab   Herbert Xu   [IPV6]: Audit all...
973
974
975
976
  /**
   *	ip6_dst_lookup - perform route lookup on flow
   *	@sk: socket which provides route info
   *	@dst: pointer to dst_entry * for result
4c9483b2f   David S. Miller   ipv6: Convert to ...
977
   *	@fl6: flow to lookup
497c615ab   Herbert Xu   [IPV6]: Audit all...
978
979
980
981
982
   *
   *	This function performs a route lookup on the given flow.
   *
   *	It returns zero on success, or a standard errno code on error.
   */
4c9483b2f   David S. Miller   ipv6: Convert to ...
983
  int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6)
497c615ab   Herbert Xu   [IPV6]: Audit all...
984
985
  {
  	*dst = NULL;
4c9483b2f   David S. Miller   ipv6: Convert to ...
986
  	return ip6_dst_lookup_tail(sk, dst, fl6);
497c615ab   Herbert Xu   [IPV6]: Audit all...
987
  }
3cf3dc6c2   Arnaldo Carvalho de Melo   [IPV6]: Export so...
988
  EXPORT_SYMBOL_GPL(ip6_dst_lookup);
497c615ab   Herbert Xu   [IPV6]: Audit all...
989
  /**
68d0c6d34   David S. Miller   ipv6: Consolidate...
990
991
   *	ip6_dst_lookup_flow - perform route lookup on flow with ipsec
   *	@sk: socket which provides route info
4c9483b2f   David S. Miller   ipv6: Convert to ...
992
   *	@fl6: flow to lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
993
   *	@final_dst: final destination address for ipsec lookup
a1414715f   David S. Miller   ipv6: Change fina...
994
   *	@can_sleep: we are in a sleepable context
68d0c6d34   David S. Miller   ipv6: Consolidate...
995
996
997
998
999
1000
   *
   *	This function performs a route lookup on the given flow.
   *
   *	It returns a valid dst pointer on success, or a pointer encoded
   *	error code.
   */
4c9483b2f   David S. Miller   ipv6: Convert to ...
1001
  struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
68d0c6d34   David S. Miller   ipv6: Consolidate...
1002
  				      const struct in6_addr *final_dst,
a1414715f   David S. Miller   ipv6: Change fina...
1003
  				      bool can_sleep)
68d0c6d34   David S. Miller   ipv6: Consolidate...
1004
1005
1006
  {
  	struct dst_entry *dst = NULL;
  	int err;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1007
  	err = ip6_dst_lookup_tail(sk, &dst, fl6);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1008
1009
1010
  	if (err)
  		return ERR_PTR(err);
  	if (final_dst)
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1011
  		fl6->daddr = *final_dst;
2774c131b   David S. Miller   xfrm: Handle blac...
1012
  	if (can_sleep)
4c9483b2f   David S. Miller   ipv6: Convert to ...
1013
  		fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP;
2774c131b   David S. Miller   xfrm: Handle blac...
1014

4c9483b2f   David S. Miller   ipv6: Convert to ...
1015
  	return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1016
1017
1018
1019
1020
  }
  EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
  
  /**
   *	ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow
497c615ab   Herbert Xu   [IPV6]: Audit all...
1021
   *	@sk: socket which provides the dst cache and route info
4c9483b2f   David S. Miller   ipv6: Convert to ...
1022
   *	@fl6: flow to lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
1023
   *	@final_dst: final destination address for ipsec lookup
a1414715f   David S. Miller   ipv6: Change fina...
1024
   *	@can_sleep: we are in a sleepable context
497c615ab   Herbert Xu   [IPV6]: Audit all...
1025
1026
1027
1028
1029
1030
   *
   *	This function performs a route lookup on the given flow with the
   *	possibility of using the cached route in the socket if it is valid.
   *	It will take the socket dst lock when operating on the dst cache.
   *	As a result, this function can only be used in process context.
   *
68d0c6d34   David S. Miller   ipv6: Consolidate...
1031
1032
   *	It returns a valid dst pointer on success, or a pointer encoded
   *	error code.
497c615ab   Herbert Xu   [IPV6]: Audit all...
1033
   */
4c9483b2f   David S. Miller   ipv6: Convert to ...
1034
  struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
68d0c6d34   David S. Miller   ipv6: Consolidate...
1035
  					 const struct in6_addr *final_dst,
a1414715f   David S. Miller   ipv6: Change fina...
1036
  					 bool can_sleep)
497c615ab   Herbert Xu   [IPV6]: Audit all...
1037
  {
68d0c6d34   David S. Miller   ipv6: Consolidate...
1038
1039
  	struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
  	int err;
497c615ab   Herbert Xu   [IPV6]: Audit all...
1040

4c9483b2f   David S. Miller   ipv6: Convert to ...
1041
  	dst = ip6_sk_dst_check(sk, dst, fl6);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1042

4c9483b2f   David S. Miller   ipv6: Convert to ...
1043
  	err = ip6_dst_lookup_tail(sk, &dst, fl6);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1044
1045
1046
  	if (err)
  		return ERR_PTR(err);
  	if (final_dst)
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1047
  		fl6->daddr = *final_dst;
2774c131b   David S. Miller   xfrm: Handle blac...
1048
  	if (can_sleep)
4c9483b2f   David S. Miller   ipv6: Convert to ...
1049
  		fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP;
2774c131b   David S. Miller   xfrm: Handle blac...
1050

4c9483b2f   David S. Miller   ipv6: Convert to ...
1051
  	return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1052
  }
68d0c6d34   David S. Miller   ipv6: Consolidate...
1053
  EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1054

34a0b3cdc   Adrian Bunk   [IPV6]: make two ...
1055
  static inline int ip6_ufo_append_data(struct sock *sk,
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1056
1057
1058
  			int getfrag(void *from, char *to, int offset, int len,
  			int odd, struct sk_buff *skb),
  			void *from, int length, int hh_len, int fragheaderlen,
87c48fa3b   Eric Dumazet   ipv6: make fragme...
1059
1060
  			int transhdrlen, int mtu,unsigned int flags,
  			struct rt6_info *rt)
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
  
  {
  	struct sk_buff *skb;
  	int err;
  
  	/* There is support for UDP large send offload by network
  	 * device, so create one single skb packet containing complete
  	 * udp datagram
  	 */
  	if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
  		skb = sock_alloc_send_skb(sk,
  			hh_len + fragheaderlen + transhdrlen + 20,
  			(flags & MSG_DONTWAIT), &err);
  		if (skb == NULL)
504744e4e   Zheng Yan   ipv6: fix error p...
1075
  			return err;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1076
1077
1078
1079
1080
1081
1082
1083
  
  		/* reserve space for Hardware header */
  		skb_reserve(skb, hh_len);
  
  		/* create space for UDP/IP header */
  		skb_put(skb,fragheaderlen + transhdrlen);
  
  		/* initialize network header pointer */
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1084
  		skb_reset_network_header(skb);
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1085
1086
  
  		/* initialize protocol header pointer */
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1087
  		skb->transport_header = skb->network_header + fragheaderlen;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1088

84fa7933a   Patrick McHardy   [NET]: Replace CH...
1089
  		skb->ip_summed = CHECKSUM_PARTIAL;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1090
  		skb->csum = 0;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1091
1092
1093
1094
1095
1096
  	}
  
  	err = skb_append_datato_frags(sk,skb, getfrag, from,
  				      (length - transhdrlen));
  	if (!err) {
  		struct frag_hdr fhdr;
c31d53269   Sridhar Samudrala   udpv6: Fix gso_si...
1097
1098
1099
1100
1101
  		/* Specify the length of each IPv6 datagram fragment.
  		 * It has to be a multiple of 8.
  		 */
  		skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
  					     sizeof(struct frag_hdr)) & ~7;
f83ef8c0b   Herbert Xu   [IPV6]: Added GSO...
1102
  		skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
87c48fa3b   Eric Dumazet   ipv6: make fragme...
1103
  		ipv6_select_ident(&fhdr, rt);
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  		skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
  		__skb_queue_tail(&sk->sk_write_queue, skb);
  
  		return 0;
  	}
  	/* There is not enough support do UPD LSO,
  	 * so follow normal path
  	 */
  	kfree_skb(skb);
  
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116

0178b695f   Herbert Xu   ipv6: Copy cork o...
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
  					       gfp_t gfp)
  {
  	return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
  }
  
  static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
  						gfp_t gfp)
  {
  	return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
  }
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1128
1129
1130
  int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
  	int offset, int len, int odd, struct sk_buff *skb),
  	void *from, int length, int transhdrlen,
4c9483b2f   David S. Miller   ipv6: Convert to ...
1131
  	int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
13b52cd44   Brian Haley   IPv6: Add dontfra...
1132
  	struct rt6_info *rt, unsigned int flags, int dontfrag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
1135
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
bdc712b4c   David S. Miller   inet: Decrease ov...
1136
  	struct inet_cork *cork;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
  	struct sk_buff *skb;
  	unsigned int maxfraglen, fragheaderlen;
  	int exthdrlen;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1140
  	int dst_exthdrlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141
1142
1143
1144
1145
1146
  	int hh_len;
  	int mtu;
  	int copy;
  	int err;
  	int offset = 0;
  	int csummode = CHECKSUM_NONE;
a693e6989   Anders Berggren   net: TX timestamp...
1147
  	__u8 tx_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
  
  	if (flags&MSG_PROBE)
  		return 0;
bdc712b4c   David S. Miller   inet: Decrease ov...
1151
  	cork = &inet->cork.base;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
1154
1155
1156
  	if (skb_queue_empty(&sk->sk_write_queue)) {
  		/*
  		 * setup for corking
  		 */
  		if (opt) {
0178b695f   Herbert Xu   ipv6: Copy cork o...
1157
  			if (WARN_ON(np->cork.opt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  				return -EINVAL;
0178b695f   Herbert Xu   ipv6: Copy cork o...
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
  
  			np->cork.opt = kmalloc(opt->tot_len, sk->sk_allocation);
  			if (unlikely(np->cork.opt == NULL))
  				return -ENOBUFS;
  
  			np->cork.opt->tot_len = opt->tot_len;
  			np->cork.opt->opt_flen = opt->opt_flen;
  			np->cork.opt->opt_nflen = opt->opt_nflen;
  
  			np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt,
  							    sk->sk_allocation);
  			if (opt->dst0opt && !np->cork.opt->dst0opt)
  				return -ENOBUFS;
  
  			np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt,
  							    sk->sk_allocation);
  			if (opt->dst1opt && !np->cork.opt->dst1opt)
  				return -ENOBUFS;
  
  			np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt,
  							   sk->sk_allocation);
  			if (opt->hopopt && !np->cork.opt->hopopt)
  				return -ENOBUFS;
  
  			np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt,
  							    sk->sk_allocation);
  			if (opt->srcrt && !np->cork.opt->srcrt)
  				return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
  			/* need source address above miyazawa*/
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
1189
  		dst_hold(&rt->dst);
bdc712b4c   David S. Miller   inet: Decrease ov...
1190
  		cork->dst = &rt->dst;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1191
  		inet->cork.fl.u.ip6 = *fl6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  		np->cork.hop_limit = hlimit;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1193
  		np->cork.tclass = tclass;
628a5c561   John Heffner   [INET]: Add IP(V6...
1194
  		mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1195
  		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
c75036093   Dave Jones   [IPV6]: remove us...
1196
  		if (np->frag_size < mtu) {
d91675f9c   YOSHIFUJI Hideaki   [IPV6]: Do not ig...
1197
1198
1199
  			if (np->frag_size)
  				mtu = np->frag_size;
  		}
bdc712b4c   David S. Miller   inet: Decrease ov...
1200
  		cork->fragsize = mtu;
d8d1f30b9   Changli Gao   net-next: remove ...
1201
  		if (dst_allfrag(rt->dst.path))
bdc712b4c   David S. Miller   inet: Decrease ov...
1202
1203
  			cork->flags |= IPCORK_ALLFRAG;
  		cork->length = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
  		sk->sk_sndmsg_page = NULL;
  		sk->sk_sndmsg_off = 0;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1206
  		exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
  		length += exthdrlen;
  		transhdrlen += exthdrlen;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1209
  		dst_exthdrlen = rt->dst.header_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
  	} else {
bdc712b4c   David S. Miller   inet: Decrease ov...
1211
  		rt = (struct rt6_info *)cork->dst;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1212
  		fl6 = &inet->cork.fl.u.ip6;
0178b695f   Herbert Xu   ipv6: Copy cork o...
1213
  		opt = np->cork.opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
  		transhdrlen = 0;
  		exthdrlen = 0;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1216
  		dst_exthdrlen = 0;
bdc712b4c   David S. Miller   inet: Decrease ov...
1217
  		mtu = cork->fragsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1219
  	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220

a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1221
  	fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
b4ce92775   Herbert Xu   [IPV6]: Move nfhe...
1222
  			(opt ? opt->opt_nflen : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
1225
  	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
  
  	if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
bdc712b4c   David S. Miller   inet: Decrease ov...
1226
  		if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
1227
  			ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
  			return -EMSGSIZE;
  		}
  	}
a693e6989   Anders Berggren   net: TX timestamp...
1231
1232
1233
1234
1235
1236
  	/* For UDP, check if TX timestamp is enabled */
  	if (sk->sk_type == SOCK_DGRAM) {
  		err = sock_tx_timestamp(sk, &tx_flags);
  		if (err)
  			goto error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
1239
1240
1241
1242
1243
  	/*
  	 * Let's try using as much space as possible.
  	 * Use MTU if total length of the message fits into the MTU.
  	 * Otherwise, we need to reserve fragment header and
  	 * fragment alignment (= 8-15 octects, in total).
  	 *
  	 * Note that we may need to "move" the data from the tail of
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1244
  	 * of the buffer to the new fragment when we split
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
1246
  	 * the message.
  	 *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1247
  	 * FIXME: It may be fragmented into multiple chunks
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248
1249
  	 *        at once if non-fragmentable extension headers
  	 *        are too large.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1250
  	 * --yoshfuji
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
  	 */
bdc712b4c   David S. Miller   inet: Decrease ov...
1252
  	cork->length += length;
4b340ae20   Brian Haley   IPv6: Complete IP...
1253
1254
1255
  	if (length > mtu) {
  		int proto = sk->sk_protocol;
  		if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
4c9483b2f   David S. Miller   ipv6: Convert to ...
1256
  			ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
4b340ae20   Brian Haley   IPv6: Complete IP...
1257
1258
  			return -EMSGSIZE;
  		}
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1259

4b340ae20   Brian Haley   IPv6: Complete IP...
1260
  		if (proto == IPPROTO_UDP &&
d8d1f30b9   Changli Gao   net-next: remove ...
1261
  		    (rt->dst.dev->features & NETIF_F_UFO)) {
4b340ae20   Brian Haley   IPv6: Complete IP...
1262
1263
1264
  
  			err = ip6_ufo_append_data(sk, getfrag, from, length,
  						  hh_len, fragheaderlen,
87c48fa3b   Eric Dumazet   ipv6: make fragme...
1265
  						  transhdrlen, mtu, flags, rt);
4b340ae20   Brian Haley   IPv6: Complete IP...
1266
1267
1268
1269
  			if (err)
  				goto error;
  			return 0;
  		}
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1270
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
1273
1274
1275
1276
  
  	if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
  		goto alloc_new_skb;
  
  	while (length > 0) {
  		/* Check if the remaining data fits into current packet. */
bdc712b4c   David S. Miller   inet: Decrease ov...
1277
  		copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
  		if (copy < length)
  			copy = maxfraglen - skb->len;
  
  		if (copy <= 0) {
  			char *data;
  			unsigned int datalen;
  			unsigned int fraglen;
  			unsigned int fraggap;
  			unsigned int alloclen;
  			struct sk_buff *skb_prev;
  alloc_new_skb:
  			skb_prev = skb;
  
  			/* There's no room in the current skb */
  			if (skb_prev)
  				fraggap = skb_prev->len - maxfraglen;
  			else
  				fraggap = 0;
  
  			/*
  			 * If remaining data exceeds the mtu,
  			 * we know we need more fragment(s).
  			 */
  			datalen = length + fraggap;
bdc712b4c   David S. Miller   inet: Decrease ov...
1302
  			if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
1306
  				datalen = maxfraglen - fragheaderlen;
  
  			fraglen = datalen + fragheaderlen;
  			if ((flags & MSG_MORE) &&
d8d1f30b9   Changli Gao   net-next: remove ...
1307
  			    !(rt->dst.dev->features&NETIF_F_SG))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
  				alloclen = mtu;
  			else
  				alloclen = datalen + fragheaderlen;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1311
  			alloclen += dst_exthdrlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
1313
1314
1315
1316
1317
  			/*
  			 * The last fragment gets additional space at tail.
  			 * Note: we overallocate on fragments with MSG_MODE
  			 * because we have no idea if we're the last one.
  			 */
  			if (datalen == length + fraggap)
d8d1f30b9   Changli Gao   net-next: remove ...
1318
  				alloclen += rt->dst.trailer_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
  
  			/*
  			 * We just reserve space for fragment header.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1322
  			 * Note: this may be overallocation if the message
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  			 * (without MSG_MORE) fits into the MTU.
  			 */
  			alloclen += sizeof(struct frag_hdr);
  
  			if (transhdrlen) {
  				skb = sock_alloc_send_skb(sk,
  						alloclen + hh_len,
  						(flags & MSG_DONTWAIT), &err);
  			} else {
  				skb = NULL;
  				if (atomic_read(&sk->sk_wmem_alloc) <=
  				    2 * sk->sk_sndbuf)
  					skb = sock_wmalloc(sk,
  							   alloclen + hh_len, 1,
  							   sk->sk_allocation);
  				if (unlikely(skb == NULL))
  					err = -ENOBUFS;
a693e6989   Anders Berggren   net: TX timestamp...
1340
1341
1342
1343
1344
1345
  				else {
  					/* Only the initial fragment
  					 * is time stamped.
  					 */
  					tx_flags = 0;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
  			}
  			if (skb == NULL)
  				goto error;
  			/*
  			 *	Fill in the control structures
  			 */
  			skb->ip_summed = csummode;
  			skb->csum = 0;
  			/* reserve for fragmentation */
  			skb_reserve(skb, hh_len+sizeof(struct frag_hdr));
a693e6989   Anders Berggren   net: TX timestamp...
1356
1357
  			if (sk->sk_type == SOCK_DGRAM)
  				skb_shinfo(skb)->tx_flags = tx_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
  			/*
  			 *	Find where to start putting bytes
  			 */
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1361
1362
1363
  			data = skb_put(skb, fraglen + dst_exthdrlen);
  			skb_set_network_header(skb, exthdrlen + dst_exthdrlen);
  			data += fragheaderlen + dst_exthdrlen;
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1364
1365
  			skb->transport_header = (skb->network_header +
  						 fragheaderlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
1367
1368
1369
1370
1371
1372
  			if (fraggap) {
  				skb->csum = skb_copy_and_csum_bits(
  					skb_prev, maxfraglen,
  					data + transhdrlen, fraggap, 0);
  				skb_prev->csum = csum_sub(skb_prev->csum,
  							  skb->csum);
  				data += fraggap;
e9fa4f7bd   Herbert Xu   [INET]: Use pskb_...
1373
  				pskb_trim_unique(skb_prev, maxfraglen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
  			}
  			copy = datalen - transhdrlen - fraggap;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1376

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
  			if (copy < 0) {
  				err = -EINVAL;
  				kfree_skb(skb);
  				goto error;
  			} else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
  				err = -EFAULT;
  				kfree_skb(skb);
  				goto error;
  			}
  
  			offset += copy;
  			length -= datalen - fraggap;
  			transhdrlen = 0;
  			exthdrlen = 0;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1391
  			dst_exthdrlen = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  			csummode = CHECKSUM_NONE;
  
  			/*
  			 * Put the packet on the pending queue
  			 */
  			__skb_queue_tail(&sk->sk_write_queue, skb);
  			continue;
  		}
  
  		if (copy > length)
  			copy = length;
d8d1f30b9   Changli Gao   net-next: remove ...
1403
  		if (!(rt->dst.dev->features&NETIF_F_SG)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
  			unsigned int off;
  
  			off = skb->len;
  			if (getfrag(from, skb_put(skb, copy),
  						offset, copy, off, skb) < 0) {
  				__skb_trim(skb, off);
  				err = -EFAULT;
  				goto error;
  			}
  		} else {
  			int i = skb_shinfo(skb)->nr_frags;
  			skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
  			struct page *page = sk->sk_sndmsg_page;
  			int off = sk->sk_sndmsg_off;
  			unsigned int left;
  
  			if (page && (left = PAGE_SIZE - off) > 0) {
  				if (copy >= left)
  					copy = left;
408dadf03   Ian Campbell   net: ipv6: conver...
1423
  				if (page != skb_frag_page(frag)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424
1425
1426
1427
  					if (i == MAX_SKB_FRAGS) {
  						err = -EMSGSIZE;
  						goto error;
  					}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1428
  					skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
408dadf03   Ian Campbell   net: ipv6: conver...
1429
  					skb_frag_ref(skb, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
  					frag = &skb_shinfo(skb)->frags[i];
  				}
  			} else if(i < MAX_SKB_FRAGS) {
  				if (copy > PAGE_SIZE)
  					copy = PAGE_SIZE;
  				page = alloc_pages(sk->sk_allocation, 0);
  				if (page == NULL) {
  					err = -ENOMEM;
  					goto error;
  				}
  				sk->sk_sndmsg_page = page;
  				sk->sk_sndmsg_off = 0;
  
  				skb_fill_page_desc(skb, i, page, 0, 0);
  				frag = &skb_shinfo(skb)->frags[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
1446
1447
1448
  			} else {
  				err = -EMSGSIZE;
  				goto error;
  			}
9e903e085   Eric Dumazet   net: add skb frag...
1449
1450
  			if (getfrag(from,
  				    skb_frag_address(frag) + skb_frag_size(frag),
408dadf03   Ian Campbell   net: ipv6: conver...
1451
  				    offset, copy, skb->len, skb) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
1453
1454
1455
  				err = -EFAULT;
  				goto error;
  			}
  			sk->sk_sndmsg_off += copy;
9e903e085   Eric Dumazet   net: add skb frag...
1456
  			skb_frag_size_add(frag, copy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457
1458
  			skb->len += copy;
  			skb->data_len += copy;
f945fa7ad   Herbert Xu   [INET]: Fix trues...
1459
1460
  			skb->truesize += copy;
  			atomic_add(copy, &sk->sk_wmem_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
1462
1463
1464
1465
1466
  		}
  		offset += copy;
  		length -= copy;
  	}
  	return 0;
  error:
bdc712b4c   David S. Miller   inet: Decrease ov...
1467
  	cork->length -= length;
3bd653c84   Denis V. Lunev   netns: add net pa...
1468
  	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
1470
  	return err;
  }
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1471
1472
  static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
  {
0178b695f   Herbert Xu   ipv6: Copy cork o...
1473
1474
1475
1476
1477
1478
1479
1480
  	if (np->cork.opt) {
  		kfree(np->cork.opt->dst0opt);
  		kfree(np->cork.opt->dst1opt);
  		kfree(np->cork.opt->hopopt);
  		kfree(np->cork.opt->srcrt);
  		kfree(np->cork.opt);
  		np->cork.opt = NULL;
  	}
bdc712b4c   David S. Miller   inet: Decrease ov...
1481
1482
1483
1484
  	if (inet->cork.base.dst) {
  		dst_release(inet->cork.base.dst);
  		inet->cork.base.dst = NULL;
  		inet->cork.base.flags &= ~IPCORK_ALLFRAG;
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1485
1486
1487
  	}
  	memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1488
1489
1490
1491
1492
1493
1494
  int ip6_push_pending_frames(struct sock *sk)
  {
  	struct sk_buff *skb, *tmp_skb;
  	struct sk_buff **tail_skb;
  	struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
3bd653c84   Denis V. Lunev   netns: add net pa...
1495
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1496
1497
  	struct ipv6hdr *hdr;
  	struct ipv6_txoptions *opt = np->cork.opt;
bdc712b4c   David S. Miller   inet: Decrease ov...
1498
  	struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1499
1500
  	struct flowi6 *fl6 = &inet->cork.fl.u.ip6;
  	unsigned char proto = fl6->flowi6_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
1503
1504
1505
1506
1507
  	int err = 0;
  
  	if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL)
  		goto out;
  	tail_skb = &(skb_shinfo(skb)->frag_list);
  
  	/* move skb->data to ip header from ext header */
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1508
  	if (skb->data < skb_network_header(skb))
bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1509
  		__skb_pull(skb, skb_network_offset(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
  	while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1511
  		__skb_pull(tmp_skb, skb_network_header_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
1514
1515
  		*tail_skb = tmp_skb;
  		tail_skb = &(tmp_skb->next);
  		skb->len += tmp_skb->len;
  		skb->data_len += tmp_skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1516
  		skb->truesize += tmp_skb->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1517
1518
  		tmp_skb->destructor = NULL;
  		tmp_skb->sk = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
  	}
28a89453b   Herbert Xu   [IPV6]: Fix IPsec...
1520
  	/* Allow local fragmentation. */
b5c15fc00   Herbert Xu   [IPV6]: Fix rever...
1521
  	if (np->pmtudisc < IPV6_PMTUDISC_DO)
28a89453b   Herbert Xu   [IPV6]: Fix IPsec...
1522
  		skb->local_df = 1;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1523
  	*final_dst = fl6->daddr;
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1524
  	__skb_pull(skb, skb_network_header_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
1527
1528
  	if (opt && opt->opt_flen)
  		ipv6_push_frag_opts(skb, opt, &proto);
  	if (opt && opt->opt_nflen)
  		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
1529
1530
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1531
  	hdr = ipv6_hdr(skb);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1532

4c9483b2f   David S. Miller   ipv6: Convert to ...
1533
  	*(__be32*)hdr = fl6->flowlabel |
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1534
  		     htonl(0x60000000 | ((int)np->cork.tclass << 20));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
1537
  	hdr->hop_limit = np->cork.hop_limit;
  	hdr->nexthdr = proto;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1538
1539
  	hdr->saddr = fl6->saddr;
  	hdr->daddr = *final_dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540

a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
1541
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
1542
  	skb->mark = sk->sk_mark;
a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
1543

d8d1f30b9   Changli Gao   net-next: remove ...
1544
  	skb_dst_set(skb, dst_clone(&rt->dst));
edf391ff1   Neil Horman   snmp: add missing...
1545
  	IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
1546
  	if (proto == IPPROTO_ICMPV6) {
adf30907d   Eric Dumazet   net: skb->dst acc...
1547
  		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
1548

5a57d4c7f   Denis V. Lunev   ipv6: added net a...
1549
  		ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type);
e41b5368e   Denis V. Lunev   ipv6: added net a...
1550
  		ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
1551
  	}
ef76bc23e   Herbert Xu   [IPV6]: Add ip6_l...
1552
  	err = ip6_local_out(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
1554
  	if (err) {
  		if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
1555
  			err = net_xmit_errno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
1557
1558
1559
1560
  		if (err)
  			goto error;
  	}
  
  out:
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1561
  	ip6_cork_release(inet, np);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1562
1563
  	return err;
  error:
062549149   Eric Dumazet   ipv6: ip6_push_pe...
1564
  	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
  	goto out;
  }
  
  void ip6_flush_pending_frames(struct sock *sk)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
1572
  	struct sk_buff *skb;
  
  	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
adf30907d   Eric Dumazet   net: skb->dst acc...
1573
1574
  		if (skb_dst(skb))
  			IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
e1f52208b   YOSHIFUJI Hideaki   [IPv6]: Fix NULL ...
1575
  				      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
1577
  		kfree_skb(skb);
  	}
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1578
  	ip6_cork_release(inet_sk(sk), inet6_sk(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
  }