Blame view

net/ipv6/ip6_output.c 45.8 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
   *	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>
67ba4152e   Ian Morris   ipv6: White-space...
23
   *	Imran Patel	:	frag id should be in NBO
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
   *      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

33b486793   Daniel Mack   net: ipv4, ipv6: ...
41
  #include <linux/bpf-cgroup.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  #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...
57
  #include <linux/mroute6.h>
ca254490c   David Ahern   net: Add VRF supp...
58
  #include <net/l3mdev.h>
14972cbd3   Roopa Prabhu   net: lwtunnel: Ha...
59
  #include <net/lwtunnel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
61
  static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
63
  	struct dst_entry *dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  	struct net_device *dev = dst->dev;
f6b72b621   David S. Miller   net: Embed hh_cac...
65
  	struct neighbour *neigh;
6fd6ce205   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
66
67
  	struct in6_addr *nexthop;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
  
  	skb->protocol = htons(ETH_P_IPV6);
  	skb->dev = dev;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
71
  	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
adf30907d   Eric Dumazet   net: skb->dst acc...
72
  		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

7026b1ddb   David Miller   netfilter: Pass s...
74
  		if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) &&
78126c419   Eric W. Biederman   ipv6: Only comput...
75
  		    ((mroute6_socket(net, skb) &&
bd91b8bf3   Benjamin Thery   netns: ip6mr: all...
76
  		     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
77
78
  		     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
  					 &ipv6_hdr(skb)->saddr))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
  			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: ...
85
  				NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
29a26a568   Eric W. Biederman   netfilter: Pass s...
86
  					net, sk, newskb, NULL, newskb->dev,
95603e229   Michel Machado   net-next: add dev...
87
  					dev_loopback_xmit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
89
  			if (ipv6_hdr(skb)->hop_limit == 0) {
78126c419   Eric W. Biederman   ipv6: Only comput...
90
  				IP6_INC_STATS(net, idev,
3bd653c84   Denis V. Lunev   netns: add net pa...
91
  					      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
  				kfree_skb(skb);
  				return 0;
  			}
  		}
78126c419   Eric W. Biederman   ipv6: Only comput...
96
  		IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, skb->len);
dd4085152   Hannes Frederic Sowa   ipv6: don't let n...
97
98
99
100
101
102
103
  
  		if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
  		    IPV6_ADDR_SCOPE_NODELOCAL &&
  		    !(dev->flags & IFF_LOOPBACK)) {
  			kfree_skb(skb);
  			return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	}
14972cbd3   Roopa Prabhu   net: lwtunnel: Ha...
105
106
107
108
109
110
  	if (lwtunnel_xmit_redirect(dst->lwtstate)) {
  		int res = lwtunnel_xmit(skb);
  
  		if (res < 0 || res == LWTUNNEL_XMIT_DONE)
  			return res;
  	}
6fd6ce205   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
111
  	rcu_read_lock_bh();
2647a9b07   Martin KaFai Lau   ipv6: Remove exte...
112
  	nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
6fd6ce205   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
113
114
115
116
117
118
119
120
121
  	neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
  	if (unlikely(!neigh))
  		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
  	if (!IS_ERR(neigh)) {
  		ret = dst_neigh_output(dst, neigh, skb);
  		rcu_read_unlock_bh();
  		return ret;
  	}
  	rcu_read_unlock_bh();
05e3aa094   David S. Miller   net: Create and u...
122

78126c419   Eric W. Biederman   ipv6: Only comput...
123
  	IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
124
125
  	kfree_skb(skb);
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  }
0c4b51f00   Eric W. Biederman   netfilter: Pass n...
127
  static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
128
  {
33b486793   Daniel Mack   net: ipv4, ipv6: ...
129
130
131
132
133
134
135
  	int ret;
  
  	ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
  	if (ret) {
  		kfree_skb(skb);
  		return ret;
  	}
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
136
  	if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
9037c3579   Jiri Pirko   ip6_output: fragm...
137
138
  	    dst_allfrag(skb_dst(skb)) ||
  	    (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size))
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
139
  		return ip6_fragment(net, sk, skb, ip6_finish_output2);
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
140
  	else
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
141
  		return ip6_finish_output2(net, sk, skb);
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
142
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
143
  int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  {
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
145
  	struct net_device *dev = skb_dst(skb)->dev;
adf30907d   Eric Dumazet   net: skb->dst acc...
146
  	struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
be10de0a3   Eric W. Biederman   netfilter: Add bl...
147

778d80be5   YOSHIFUJI Hideaki   ipv6: Add disable...
148
  	if (unlikely(idev->cnf.disable_ipv6)) {
19a0644ca   Eric W. Biederman   ipv6: Cache net i...
149
  		IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
778d80be5   YOSHIFUJI Hideaki   ipv6: Add disable...
150
151
152
  		kfree_skb(skb);
  		return 0;
  	}
29a26a568   Eric W. Biederman   netfilter: Pass s...
153
154
  	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
  			    net, sk, skb, NULL, dev,
9c6eb28ac   Jan Engelhardt   netfilter: ipv6: ...
155
156
  			    ip6_finish_output,
  			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  /*
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
159
160
161
162
   * xmit an sk_buff (used by TCP, SCTP and DCCP)
   * Note : socket lock is not held for SYNACK packets, but might be modified
   * by calls to skb_set_owner_w() and ipv6_local_error(),
   * which are using proper atomic operations or spinlocks.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
   */
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
164
  int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
b903d324b   Eric Dumazet   ipv6: tcp: fix TC...
165
  	     struct ipv6_txoptions *opt, int tclass)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  {
3bd653c84   Denis V. Lunev   netns: add net pa...
167
  	struct net *net = sock_net(sk);
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
168
  	const struct ipv6_pinfo *np = inet6_sk(sk);
4c9483b2f   David S. Miller   ipv6: Convert to ...
169
  	struct in6_addr *first_hop = &fl6->daddr;
adf30907d   Eric Dumazet   net: skb->dst acc...
170
  	struct dst_entry *dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	struct ipv6hdr *hdr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
172
  	u8  proto = fl6->flowi6_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	int seg_len = skb->len;
e651f03af   Gerrit Renker   inet6: Conversion...
174
  	int hlimit = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
  	u32 mtu;
  
  	if (opt) {
c2636b4d9   Chuck Lever   [NET]: Treat the ...
178
  		unsigned int head_room;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
  
  		/* 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);
63159f29b   Ian Morris   ipv6: coding styl...
189
  			if (!skb2) {
adf30907d   Eric Dumazet   net: skb->dst acc...
190
  				IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
191
192
  					      IPSTATS_MIB_OUTDISCARDS);
  				kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  				return -ENOBUFS;
  			}
808db80a7   Eric Dumazet   ipv6: call consum...
195
  			consume_skb(skb);
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
196
  			skb = skb2;
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
197
198
199
200
  			/* skb_set_owner_w() changes sk->sk_wmem_alloc atomically,
  			 * it is safe to call in our context (socket lock not held)
  			 */
  			skb_set_owner_w(skb, (struct sock *)sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
  		}
  		if (opt->opt_flen)
  			ipv6_push_frag_opts(skb, opt, &proto);
  		if (opt->opt_nflen)
613fa3ca9   David Lebrun   ipv6: add source ...
205
206
  			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
  					     &fl6->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	}
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
208
209
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
210
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  
  	/*
  	 *	Fill in the IPv6 header
  	 */
b903d324b   Eric Dumazet   ipv6: tcp: fix TC...
215
  	if (np)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  		hlimit = np->hop_limit;
  	if (hlimit < 0)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
218
  		hlimit = ip6_dst_hoplimit(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

cb1ce2ef3   Tom Herbert   ipv6: Implement a...
220
  	ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel,
67800f9b1   Tom Herbert   ipv6: Call skb_ge...
221
  						     np->autoflowlabel, fl6));
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

9c9c9ad5f   Hannes Frederic Sowa   ipv6: set skb->pr...
229
  	skb->protocol = htons(ETH_P_IPV6);
a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
230
  	skb->priority = sk->sk_priority;
4a19ec580   Laszlo Attila Toth   [NET]: Introducin...
231
  	skb->mark = sk->sk_mark;
a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
232

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  	mtu = dst_mtu(dst);
60ff74673   WANG Cong   net: rename local...
234
  	if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
adf30907d   Eric Dumazet   net: skb->dst acc...
235
  		IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
edf391ff1   Neil Horman   snmp: add missing...
236
  			      IPSTATS_MIB_OUT, skb->len);
a8e3e1a9f   David Ahern   net: l3mdev: Add ...
237
238
239
240
241
242
243
  
  		/* if egress device is enslaved to an L3 master device pass the
  		 * skb to its handler for processing
  		 */
  		skb = l3mdev_ip6_out((struct sock *)sk, skb);
  		if (unlikely(!skb))
  			return 0;
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
244
245
246
  		/* hooks should never assume socket lock is held.
  		 * we promote our socket to non const
  		 */
29a26a568   Eric W. Biederman   netfilter: Pass s...
247
  		return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
248
  			       net, (struct sock *)sk, skb, NULL, dst->dev,
13206b6bf   Eric W. Biederman   net: Pass net int...
249
  			       dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  	skb->dev = dst->dev;
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
252
253
254
255
  	/* ipv6_local_error() does not require socket lock,
  	 * we promote our socket to non const
  	 */
  	ipv6_local_error((struct sock *)sk, EMSGSIZE, fl6, mtu);
adf30907d   Eric Dumazet   net: skb->dst acc...
256
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
  	kfree_skb(skb);
  	return -EMSGSIZE;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
260
  EXPORT_SYMBOL(ip6_xmit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
265
266
267
268
  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...
269
270
271
  		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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  			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...
289
290
  static int ip6_forward_proxy_check(struct sk_buff *skb)
  {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
291
  	struct ipv6hdr *hdr = ipv6_hdr(skb);
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
292
  	u8 nexthdr = hdr->nexthdr;
75f2811c6   Jesse Gross   ipv6: Add fragmen...
293
  	__be16 frag_off;
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
294
295
296
  	int offset;
  
  	if (ipv6_ext_hdr(nexthdr)) {
75f2811c6   Jesse Gross   ipv6: Add fragmen...
297
  		offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off);
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
298
299
300
301
302
303
304
  		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...
305
306
  		if (!pskb_may_pull(skb, (skb_network_header(skb) +
  					 offset + 1 - skb->data)))
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
307
  			return 0;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
308
  		icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  		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...
325
326
327
328
329
330
331
332
333
  	/*
  	 * 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...
334
335
  	return 0;
  }
0c4b51f00   Eric W. Biederman   netfilter: Pass n...
336
337
  static inline int ip6_forward_finish(struct net *net, struct sock *sk,
  				     struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  {
13206b6bf   Eric W. Biederman   net: Pass net int...
339
  	return dst_output(net, sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  }
0954cf9c6   Hannes Frederic Sowa   ipv6: introduce i...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
  {
  	unsigned int mtu;
  	struct inet6_dev *idev;
  
  	if (dst_metric_locked(dst, RTAX_MTU)) {
  		mtu = dst_metric_raw(dst, RTAX_MTU);
  		if (mtu)
  			return mtu;
  	}
  
  	mtu = IPV6_MIN_MTU;
  	rcu_read_lock();
  	idev = __in6_dev_get(dst->dev);
  	if (idev)
  		mtu = idev->cnf.mtu6;
  	rcu_read_unlock();
  
  	return mtu;
  }
fe6cc55f3   Florian Westphal   net: ip, ipv6: ha...
361
362
  static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
  {
418a31561   Florian Westphal   net: ipv6: send p...
363
  	if (skb->len <= mtu)
fe6cc55f3   Florian Westphal   net: ip, ipv6: ha...
364
  		return false;
60ff74673   WANG Cong   net: rename local...
365
  	/* ipv6 conntrack defrag sets max_frag_size + ignore_df */
fe6cc55f3   Florian Westphal   net: ip, ipv6: ha...
366
367
  	if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)
  		return true;
60ff74673   WANG Cong   net: rename local...
368
  	if (skb->ignore_df)
418a31561   Florian Westphal   net: ipv6: send p...
369
  		return false;
ae7ef81ef   Marcelo Ricardo Leitner   skbuff: introduce...
370
  	if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
fe6cc55f3   Florian Westphal   net: ip, ipv6: ha...
371
372
373
374
  		return false;
  
  	return true;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
  int ip6_forward(struct sk_buff *skb)
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
377
  	struct dst_entry *dst = skb_dst(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
378
  	struct ipv6hdr *hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  	struct inet6_skb_parm *opt = IP6CB(skb);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
380
  	struct net *net = dev_net(dst->dev);
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
381
  	u32 mtu;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
382

53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
383
  	if (net->ipv6.devconf_all->forwarding == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  		goto error;
090f1166c   Li RongQing   ipv6: ip6_forward...
385
386
  	if (skb->pkt_type != PACKET_HOST)
  		goto drop;
9ef2e965e   Hannes Frederic Sowa   ipv6: drop frames...
387
388
  	if (unlikely(skb->sk))
  		goto drop;
4497b0763   Ben Hutchings   net: Discard and ...
389
390
  	if (skb_warn_if_lro(skb))
  		goto drop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
1d0155035   Eric Dumazet   ipv6: rename IP6_...
392
393
  		__IP6_INC_STATS(net, ip6_dst_idev(dst),
  				IPSTATS_MIB_INDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
  		goto drop;
  	}
35fc92a9d   Herbert Xu   [NET]: Allow forw...
396
  	skb_forward_csum(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  
  	/*
  	 *	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
  	 */
ab4eb3537   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Process uni...
411
412
  	if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
  		if (ip6_call_ra_chain(skb, ntohs(opt->ra)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
  			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...
422
  		icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
1d0155035   Eric Dumazet   ipv6: rename IP6_...
423
424
  		__IP6_INC_STATS(net, ip6_dst_idev(dst),
  				IPSTATS_MIB_INHDRERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
  
  		kfree_skb(skb);
  		return -ETIMEDOUT;
  	}
fbea49e1e   YOSHIFUJI Hideaki   [IPV6] NDISC: Add...
429
  	/* XXX: idev->cnf.proxy_ndp? */
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
430
  	if (net->ipv6.devconf_all->proxy_ndp &&
8a3edd800   Daniel Lezcano   [NETNS][IPV6] fix...
431
  	    pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
432
433
  		int proxied = ip6_forward_proxy_check(skb);
  		if (proxied > 0)
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
434
  			return ip6_input(skb);
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
435
  		else if (proxied < 0) {
1d0155035   Eric Dumazet   ipv6: rename IP6_...
436
437
  			__IP6_INC_STATS(net, ip6_dst_idev(dst),
  					IPSTATS_MIB_INDISCARDS);
74553b09d   Ville Nuorvala   [IPV6]: Don't for...
438
439
  			goto drop;
  		}
e21e0b5f1   Ville Nuorvala   [IPV6] NDISC: Han...
440
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  	if (!xfrm6_route_forward(skb)) {
1d0155035   Eric Dumazet   ipv6: rename IP6_...
442
443
  		__IP6_INC_STATS(net, ip6_dst_idev(dst),
  				IPSTATS_MIB_INDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  		goto drop;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
446
  	dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
449
  
  	/* 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...
450
  	   We don't send redirects to frames decapsulated from IPsec.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  	 */
c45a3dfb5   David S. Miller   ipv6: Eliminate d...
452
  	if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  		struct in6_addr *target = NULL;
fbfe95a42   David S. Miller   inet: Create and ...
454
  		struct inet_peer *peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  		struct rt6_info *rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
458
459
460
461
462
  
  		/*
  		 *	incoming and outgoing devices are the same
  		 *	send a redirect.
  		 */
  
  		rt = (struct rt6_info *) dst;
c45a3dfb5   David S. Miller   ipv6: Eliminate d...
463
464
  		if (rt->rt6i_flags & RTF_GATEWAY)
  			target = &rt->rt6i_gateway;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
  		else
  			target = &hdr->daddr;
fd0273d79   Martin KaFai Lau   ipv6: Remove exte...
467
  		peer = inet_getpeer_v6(net->ipv6.peers, &hdr->daddr, 1);
92d868292   David S. Miller   inetpeer: Move IC...
468

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
  		/* Limit redirects both by destination (here)
  		   and by source (inside ndisc_send_redirect)
  		 */
fbfe95a42   David S. Miller   inet: Create and ...
472
  		if (inet_peer_xrlim_allow(peer, 1*HZ))
4991969a1   David S. Miller   ipv6: Remove neig...
473
  			ndisc_send_redirect(skb, target);
1d861aa4b   David S. Miller   inet: Minimize us...
474
475
  		if (peer)
  			inet_putpeer(peer);
5bb1ab09e   David L Stevens   [IPV6]: Send ICMP...
476
477
  	} else {
  		int addrtype = ipv6_addr_type(&hdr->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  		/* This check is security critical. */
f81b2e7d8   YOSHIFUJI Hideaki   ipv6: Do not forw...
479
480
  		if (addrtype == IPV6_ADDR_ANY ||
  		    addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
5bb1ab09e   David L Stevens   [IPV6]: Send ICMP...
481
482
483
  			goto error;
  		if (addrtype & IPV6_ADDR_LINKLOCAL) {
  			icmpv6_send(skb, ICMPV6_DEST_UNREACH,
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
484
  				    ICMPV6_NOT_NEIGHBOUR, 0);
5bb1ab09e   David L Stevens   [IPV6]: Send ICMP...
485
486
  			goto error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  	}
0954cf9c6   Hannes Frederic Sowa   ipv6: introduce i...
488
  	mtu = ip6_dst_mtu_forward(dst);
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
489
490
  	if (mtu < IPV6_MIN_MTU)
  		mtu = IPV6_MIN_MTU;
fe6cc55f3   Florian Westphal   net: ip, ipv6: ha...
491
  	if (ip6_pkt_too_big(skb, mtu)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
  		/* Again, force OUTPUT device used as source address */
  		skb->dev = dst->dev;
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
494
  		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
1d0155035   Eric Dumazet   ipv6: rename IP6_...
495
496
497
498
  		__IP6_INC_STATS(net, ip6_dst_idev(dst),
  				IPSTATS_MIB_INTOOBIGERRORS);
  		__IP6_INC_STATS(net, ip6_dst_idev(dst),
  				IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
502
503
  		kfree_skb(skb);
  		return -EMSGSIZE;
  	}
  
  	if (skb_cow(skb, dst->dev->hard_header_len)) {
1d0155035   Eric Dumazet   ipv6: rename IP6_...
504
505
  		__IP6_INC_STATS(net, ip6_dst_idev(dst),
  				IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
  		goto drop;
  	}
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
508
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  
  	/* Mangling hops number delayed to point after skb COW */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
511

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  	hdr->hop_limit--;
1d0155035   Eric Dumazet   ipv6: rename IP6_...
513
514
  	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
  	__IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
29a26a568   Eric W. Biederman   netfilter: Pass s...
515
516
  	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
  		       net, NULL, skb, skb->dev, dst->dev,
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
517
  		       ip6_forward_finish);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
  
  error:
1d0155035   Eric Dumazet   ipv6: rename IP6_...
520
  	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
525
526
527
528
529
530
  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...
531
532
  	skb_dst_drop(to);
  	skb_dst_set(to, dst_clone(skb_dst(from)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  	to->dev = from->dev;
82e91ffef   Thomas Graf   [NET]: Turn nfmar...
534
  	to->mark = from->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
  
  #ifdef CONFIG_NET_SCHED
  	to->tc_index = from->tc_index;
  #endif
e7ac05f34   Yasuyuki Kozakai   [NETFILTER]: nf_c...
539
  	nf_copy(to, from);
984bc16cc   James Morris   [SECMARK]: Add se...
540
  	skb_copy_secmark(to, from);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  }
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
542
543
  int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
  		 int (*output)(struct net *, struct sock *, struct sk_buff *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  	struct sk_buff *frag;
67ba4152e   Ian Morris   ipv6: White-space...
546
  	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
f60e5990d   hannes@stressinduktion.org   ipv6: protect skb...
547
548
  	struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
  				inet6_sk(skb->sk) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
  	struct ipv6hdr *tmp_hdr;
  	struct frag_hdr *fh;
  	unsigned int mtu, hlen, left, len;
a7ae19922   Herbert Xu   ipv6: Remove all ...
552
  	int hroom, troom;
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
553
  	__be32 frag_id;
67ba4152e   Ian Morris   ipv6: White-space...
554
  	int ptr, offset = 0, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  	u8 *prevhdr, nexthdr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  	hlen = ip6_find_1stfragopt(skb, &prevhdr);
  	nexthdr = *prevhdr;
628a5c561   John Heffner   [INET]: Add IP(V6...
558
  	mtu = ip6_skb_dst_mtu(skb);
b881ef760   John Heffner   [IPV6]: MTU disco...
559
560
  
  	/* We must not fragment if the socket is set to force MTU discovery
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
561
  	 * or if the skb it not generated by a local socket.
b881ef760   John Heffner   [IPV6]: MTU disco...
562
  	 */
485fca664   Florian Westphal   ipv6: don't incre...
563
564
  	if (unlikely(!skb->ignore_df && skb->len > mtu))
  		goto fail_toobig;
a34a101e1   Eric Dumazet   ipv6: disable GSO...
565

485fca664   Florian Westphal   ipv6: don't incre...
566
567
568
569
570
571
572
573
  	if (IP6CB(skb)->frag_max_size) {
  		if (IP6CB(skb)->frag_max_size > mtu)
  			goto fail_toobig;
  
  		/* don't send fragments larger than what we received */
  		mtu = IP6CB(skb)->frag_max_size;
  		if (mtu < IPV6_MIN_MTU)
  			mtu = IPV6_MIN_MTU;
b881ef760   John Heffner   [IPV6]: MTU disco...
574
  	}
d91675f9c   YOSHIFUJI Hideaki   [IPV6]: Do not ig...
575
576
577
578
  	if (np && np->frag_size < mtu) {
  		if (np->frag_size)
  			mtu = np->frag_size;
  	}
89bc7848a   Hannes Frederic Sowa   ipv6: protect mtu...
579
  	if (mtu < hlen + sizeof(struct frag_hdr) + 8)
b72a2b01b   Hannes Frederic Sowa   ipv6: protect mtu...
580
  		goto fail_toobig;
1e0d69a9c   Hannes Frederic Sowa   Revert "Merge bra...
581
  	mtu -= hlen + sizeof(struct frag_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582

fd0273d79   Martin KaFai Lau   ipv6: Remove exte...
583
584
  	frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
  				    &ipv6_hdr(skb)->saddr);
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
585

405c92f7a   Hannes Frederic Sowa   ipv6: add defensi...
586
587
588
  	if (skb->ip_summed == CHECKSUM_PARTIAL &&
  	    (err = skb_checksum_help(skb)))
  		goto fail;
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
589
  	hroom = LL_RESERVED_SPACE(rt->dst.dev);
21dc33015   David S. Miller   net: Rename skb_h...
590
  	if (skb_has_frag_list(skb)) {
c72d8cdaa   Alexey Dobriyan   net: fix bogus ca...
591
  		unsigned int first_len = skb_pagelen(skb);
3d13008e7   Eric Dumazet   ip: fix truesize ...
592
  		struct sk_buff *frag2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  
  		if (first_len - hlen > mtu ||
  		    ((first_len - hlen) & 7) ||
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
596
597
  		    skb_cloned(skb) ||
  		    skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  			goto slow_path;
4d9092bb4   David S. Miller   ipv6: Use frag li...
599
  		skb_walk_frags(skb, frag) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
  			/* Correct geometry. */
  			if (frag->len > mtu ||
  			    ((frag->len & 7) && frag->next) ||
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
603
  			    skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
3d13008e7   Eric Dumazet   ip: fix truesize ...
604
  				goto slow_path_clean;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  			/* Partially cloned skb? */
  			if (skb_shared(frag))
3d13008e7   Eric Dumazet   ip: fix truesize ...
608
  				goto slow_path_clean;
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
609
610
611
  
  			BUG_ON(frag->sk);
  			if (skb->sk) {
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
612
613
  				frag->sk = skb->sk;
  				frag->destructor = sock_wfree;
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
614
  			}
3d13008e7   Eric Dumazet   ip: fix truesize ...
615
  			skb->truesize -= frag->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
619
  		}
  
  		err = 0;
  		offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  		/* BUILD HEADER */
9a217a1c7   YOSHIFUJI Hideaki   [IPV6]: Repair IP...
621
  		*prevhdr = NEXTHDR_FRAGMENT;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
622
  		tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  		if (!tmp_hdr) {
adf30907d   Eric Dumazet   net: skb->dst acc...
624
  			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
3bd653c84   Denis V. Lunev   netns: add net pa...
625
  				      IPSTATS_MIB_FRAGFAILS);
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
626
627
  			err = -ENOMEM;
  			goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  		}
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
629
630
  		frag = skb_shinfo(skb)->frag_list;
  		skb_frag_list_init(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  		__skb_pull(skb, hlen);
67ba4152e   Ian Morris   ipv6: White-space...
633
  		fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
634
635
  		__skb_push(skb, hlen);
  		skb_reset_network_header(skb);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
636
  		memcpy(skb_network_header(skb), tmp_hdr, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
  		fh->nexthdr = nexthdr;
  		fh->reserved = 0;
  		fh->frag_off = htons(IP6_MF);
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
641
  		fh->identification = frag_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
  
  		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...
646
647
  		ipv6_hdr(skb)->payload_len = htons(first_len -
  						   sizeof(struct ipv6hdr));
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
648

d8d1f30b9   Changli Gao   net-next: remove ...
649
  		dst_hold(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
  
  		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...
656
  				skb_reset_transport_header(frag);
67ba4152e   Ian Morris   ipv6: White-space...
657
  				fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr));
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
658
659
  				__skb_push(frag, hlen);
  				skb_reset_network_header(frag);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
660
661
  				memcpy(skb_network_header(frag), tmp_hdr,
  				       hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
  				offset += skb->len - hlen - sizeof(struct frag_hdr);
  				fh->nexthdr = nexthdr;
  				fh->reserved = 0;
  				fh->frag_off = htons(offset);
53b24b8f9   Ian Morris   ipv6: coding styl...
666
  				if (frag->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
  					fh->frag_off |= htons(IP6_MF);
  				fh->identification = frag_id;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
669
670
671
  				ipv6_hdr(frag)->payload_len =
  						htons(frag->len -
  						      sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
  				ip6_copy_metadata(frag, skb);
  			}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
674

7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
675
  			err = output(net, sk, skb);
67ba4152e   Ian Morris   ipv6: White-space...
676
  			if (!err)
d8d1f30b9   Changli Gao   net-next: remove ...
677
  				IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
678
  					      IPSTATS_MIB_FRAGCREATES);
dafee4908   Wei Dong   [IPV6]: SNMPv2 "i...
679

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
684
685
686
  			if (err || !frag)
  				break;
  
  			skb = frag;
  			frag = skb->next;
  			skb->next = NULL;
  		}
a51482bde   Jesper Juhl   [NET]: kfree cleanup
687
  		kfree(tmp_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
689
  
  		if (err == 0) {
d8d1f30b9   Changli Gao   net-next: remove ...
690
  			IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
691
  				      IPSTATS_MIB_FRAGOKS);
94e187c01   Amerigo Wang   ipv6: introduce i...
692
  			ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  			return 0;
  		}
46cfd725c   Florian Westphal   net: use kfree_sk...
695
  		kfree_skb_list(frag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696

d8d1f30b9   Changli Gao   net-next: remove ...
697
  		IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
698
  			      IPSTATS_MIB_FRAGFAILS);
94e187c01   Amerigo Wang   ipv6: introduce i...
699
  		ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  		return err;
3d13008e7   Eric Dumazet   ip: fix truesize ...
701
702
703
704
705
706
707
708
709
  
  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
710
711
712
713
714
715
716
717
718
719
720
  	}
  
  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 ...
721
  	troom = rt->dst.dev->needed_tailroom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
  
  	/*
  	 *	Keep copying data until we run out.
  	 */
67ba4152e   Ian Morris   ipv6: White-space...
726
  	while (left > 0)	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
  		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...
731
  		/* IF: we are not sending up to and including the packet end
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
  		   then align the next start on an eight byte boundary */
  		if (len < left)	{
  			len &= ~7;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736

cbffccc97   Joe Perches   net; ipv[46] - Re...
737
738
739
740
  		/* Allocate buffer */
  		frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
  				 hroom + troom, GFP_ATOMIC);
  		if (!frag) {
adf30907d   Eric Dumazet   net: skb->dst acc...
741
  			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
742
  				      IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
749
750
751
  			err = -ENOMEM;
  			goto fail;
  		}
  
  		/*
  		 *	Set up data on packet
  		 */
  
  		ip6_copy_metadata(frag, skb);
a7ae19922   Herbert Xu   ipv6: Remove all ...
752
  		skb_reserve(frag, hroom);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  		skb_put(frag, len + hlen + sizeof(struct frag_hdr));
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
754
  		skb_reset_network_header(frag);
badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
755
  		fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
756
757
  		frag->transport_header = (frag->network_header + hlen +
  					  sizeof(struct frag_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
763
764
765
766
767
768
  
  		/*
  		 *	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...
769
  		skb_copy_from_linear_data(skb, skb_network_header(frag), hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
774
775
  
  		/*
  		 *	Build fragment header.
  		 */
  		fh->nexthdr = nexthdr;
  		fh->reserved = 0;
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
776
  		fh->identification = frag_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
  
  		/*
  		 *	Copy a block of the IP datagram.
  		 */
e3f0b86b9   Himangi Saraogi   ipv6: Use BUG_ON
781
782
  		BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag),
  				     len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
786
787
  		left -= len;
  
  		fh->frag_off = htons(offset);
  		if (left > 0)
  			fh->frag_off |= htons(IP6_MF);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
788
789
  		ipv6_hdr(frag)->payload_len = htons(frag->len -
  						    sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
793
794
795
796
  
  		ptr += len;
  		offset += len;
  
  		/*
  		 *	Put this fragment into the sending queue.
  		 */
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
797
  		err = output(net, sk, frag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
  		if (err)
  			goto fail;
dafee4908   Wei Dong   [IPV6]: SNMPv2 "i...
800

adf30907d   Eric Dumazet   net: skb->dst acc...
801
  		IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
3bd653c84   Denis V. Lunev   netns: add net pa...
802
  			      IPSTATS_MIB_FRAGCREATES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
804
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
805
  		      IPSTATS_MIB_FRAGOKS);
808db80a7   Eric Dumazet   ipv6: call consum...
806
  	consume_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	return err;
485fca664   Florian Westphal   ipv6: don't incre...
808
809
810
811
812
813
814
  fail_toobig:
  	if (skb->sk && dst_allfrag(skb_dst(skb)))
  		sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
  
  	skb->dev = skb_dst(skb)->dev;
  	icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
  	err = -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  fail:
adf30907d   Eric Dumazet   net: skb->dst acc...
816
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
817
  		      IPSTATS_MIB_FRAGFAILS);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
818
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
  	return err;
  }
b71d1d426   Eric Dumazet   inet: constify ip...
821
822
823
  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...
824
  {
a02cec215   Eric Dumazet   net: return opera...
825
  	return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
63159f29b   Ian Morris   ipv6: coding styl...
826
  		(!addr_cache || !ipv6_addr_equal(fl_addr, addr_cache));
cf6b19825   YOSHIFUJI Hideaki   [IPV6] ROUTE: Int...
827
  }
497c615ab   Herbert Xu   [IPV6]: Audit all...
828
829
  static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
  					  struct dst_entry *dst,
b71d1d426   Eric Dumazet   inet: constify ip...
830
  					  const struct flowi6 *fl6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  {
497c615ab   Herbert Xu   [IPV6]: Audit all...
832
  	struct ipv6_pinfo *np = inet6_sk(sk);
a963a37d3   Eric Dumazet   ipv6: ip6_sk_dst_...
833
  	struct rt6_info *rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834

497c615ab   Herbert Xu   [IPV6]: Audit all...
835
836
  	if (!dst)
  		goto out;
a963a37d3   Eric Dumazet   ipv6: ip6_sk_dst_...
837
838
839
840
841
842
  	if (dst->ops->family != AF_INET6) {
  		dst_release(dst);
  		return NULL;
  	}
  
  	rt = (struct rt6_info *)dst;
497c615ab   Herbert Xu   [IPV6]: Audit all...
843
844
845
  	/* Yes, checking route validity in not connected
  	 * case is not very simple. Take into account,
  	 * that we do not support routing by source, TOS,
67ba4152e   Ian Morris   ipv6: White-space...
846
  	 * and MSG_DONTROUTE		--ANK (980726)
497c615ab   Herbert Xu   [IPV6]: Audit all...
847
  	 *
cf6b19825   YOSHIFUJI Hideaki   [IPV6] ROUTE: Int...
848
849
  	 * 1. ip6_rt_check(): If route was host route,
  	 *    check that cached destination is current.
497c615ab   Herbert Xu   [IPV6]: Audit all...
850
851
852
853
854
855
856
857
858
859
  	 *    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 ...
860
  	if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) ||
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
861
  #ifdef CONFIG_IPV6_SUBTREES
4c9483b2f   David S. Miller   ipv6: Convert to ...
862
  	    ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) ||
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
863
  #endif
ca254490c   David Ahern   net: Add VRF supp...
864
865
  	   (!(fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) &&
  	      (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex))) {
497c615ab   Herbert Xu   [IPV6]: Audit all...
866
867
  		dst_release(dst);
  		dst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	}
497c615ab   Herbert Xu   [IPV6]: Audit all...
869
870
871
  out:
  	return dst;
  }
3aef934f4   Eric Dumazet   ipv6: constify ip...
872
  static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
4c9483b2f   David S. Miller   ipv6: Convert to ...
873
  			       struct dst_entry **dst, struct flowi6 *fl6)
497c615ab   Herbert Xu   [IPV6]: Audit all...
874
  {
69cce1d14   David S. Miller   net: Abstract dst...
875
876
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
  	struct neighbour *n;
97cac0821   David S. Miller   ipv6: Store route...
877
  	struct rt6_info *rt;
69cce1d14   David S. Miller   net: Abstract dst...
878
879
  #endif
  	int err;
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
880
  	int flags = 0;
497c615ab   Herbert Xu   [IPV6]: Audit all...
881

e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
882
883
884
885
886
887
888
889
890
891
892
893
  	/* The correct way to handle this would be to do
  	 * ip6_route_get_saddr, and then ip6_route_output; however,
  	 * the route-specific preferred source forces the
  	 * ip6_route_output call _before_ ip6_route_get_saddr.
  	 *
  	 * In source specific routing (no src=any default route),
  	 * ip6_route_output will fail given src=any saddr, though, so
  	 * that's why we try it again later.
  	 */
  	if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) {
  		struct rt6_info *rt;
  		bool had_dst = *dst != NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894

e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
895
896
897
  		if (!had_dst)
  			*dst = ip6_route_output(net, sk, fl6);
  		rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
898
899
900
  		err = ip6_route_get_saddr(net, rt, &fl6->daddr,
  					  sk ? inet6_sk(sk)->srcprefs : 0,
  					  &fl6->saddr);
44456d37b   Olaf Hering   [PATCH] turn many...
901
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
  			goto out_err_release;
e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
903
904
905
906
907
908
909
910
911
  
  		/* If we had an erroneous initial result, pretend it
  		 * never existed and let the SA-enabled version take
  		 * over.
  		 */
  		if (!had_dst && (*dst)->error) {
  			dst_release(*dst);
  			*dst = NULL;
  		}
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
912
913
914
  
  		if (fl6->flowi6_oif)
  			flags |= RT6_LOOKUP_F_IFACE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  	}
e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
916
  	if (!*dst)
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
917
  		*dst = ip6_route_output_flags(net, sk, fl6, flags);
e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
918
919
920
921
  
  	err = (*dst)->error;
  	if (err)
  		goto out_err_release;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
922
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
923
924
925
926
927
928
929
930
  	/*
  	 * 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
  	 */
c56bf6fe7   Eric Dumazet   ipv6: fix a bad c...
931
  	rt = (struct rt6_info *) *dst;
707be1ff3   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
932
  	rcu_read_lock_bh();
2647a9b07   Martin KaFai Lau   ipv6: Remove exte...
933
934
  	n = __ipv6_neigh_lookup_noref(rt->dst.dev,
  				      rt6_nexthop(rt, &fl6->daddr));
707be1ff3   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
935
936
937
938
  	err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;
  	rcu_read_unlock_bh();
  
  	if (err) {
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
939
  		struct inet6_ifaddr *ifp;
4c9483b2f   David S. Miller   ipv6: Convert to ...
940
  		struct flowi6 fl_gw6;
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
941
  		int redirect;
4c9483b2f   David S. Miller   ipv6: Convert to ...
942
  		ifp = ipv6_get_ifaddr(net, &fl6->saddr,
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
943
944
945
946
947
948
949
950
951
952
953
954
  				      (*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 ...
955
956
957
  			memcpy(&fl_gw6, fl6, sizeof(struct flowi6));
  			memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr));
  			*dst = ip6_route_output(net, sk, &fl_gw6);
e5d08d718   Ian Morris   ipv6: coding styl...
958
959
  			err = (*dst)->error;
  			if (err)
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
960
  				goto out_err_release;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
961
  		}
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
962
  	}
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
963
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
966
967
968
  	return 0;
  
  out_err_release:
  	dst_release(*dst);
  	*dst = NULL;
8a966fc01   David Ahern   net: ipv6: Remove...
969

0d240e781   David Ahern   net: vrf: Impleme...
970
971
  	if (err == -ENETUNREACH)
  		IP6_INC_STATS(net, NULL, IPSTATS_MIB_OUTNOROUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
  	return err;
  }
34a0b3cdc   Adrian Bunk   [IPV6]: make two ...
974

497c615ab   Herbert Xu   [IPV6]: Audit all...
975
976
977
978
  /**
   *	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 ...
979
   *	@fl6: flow to lookup
497c615ab   Herbert Xu   [IPV6]: Audit all...
980
981
982
983
984
   *
   *	This function performs a route lookup on the given flow.
   *
   *	It returns zero on success, or a standard errno code on error.
   */
343d60aad   Roopa Prabhu   ipv6: change ipv6...
985
986
  int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
  		   struct flowi6 *fl6)
497c615ab   Herbert Xu   [IPV6]: Audit all...
987
988
  {
  	*dst = NULL;
343d60aad   Roopa Prabhu   ipv6: change ipv6...
989
  	return ip6_dst_lookup_tail(net, sk, dst, fl6);
497c615ab   Herbert Xu   [IPV6]: Audit all...
990
  }
3cf3dc6c2   Arnaldo Carvalho de Melo   [IPV6]: Export so...
991
  EXPORT_SYMBOL_GPL(ip6_dst_lookup);
497c615ab   Herbert Xu   [IPV6]: Audit all...
992
  /**
68d0c6d34   David S. Miller   ipv6: Consolidate...
993
994
   *	ip6_dst_lookup_flow - perform route lookup on flow with ipsec
   *	@sk: socket which provides route info
4c9483b2f   David S. Miller   ipv6: Convert to ...
995
   *	@fl6: flow to lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
996
   *	@final_dst: final destination address for ipsec lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
997
998
999
1000
1001
1002
   *
   *	This function performs a route lookup on the given flow.
   *
   *	It returns a valid dst pointer on success, or a pointer encoded
   *	error code.
   */
3aef934f4   Eric Dumazet   ipv6: constify ip...
1003
  struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
0e0d44ab4   Steffen Klassert   net: Remove FLOWI...
1004
  				      const struct in6_addr *final_dst)
68d0c6d34   David S. Miller   ipv6: Consolidate...
1005
1006
1007
  {
  	struct dst_entry *dst = NULL;
  	int err;
343d60aad   Roopa Prabhu   ipv6: change ipv6...
1008
  	err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1009
1010
1011
  	if (err)
  		return ERR_PTR(err);
  	if (final_dst)
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1012
  		fl6->daddr = *final_dst;
2774c131b   David S. Miller   xfrm: Handle blac...
1013

f92ee6198   Steffen Klassert   xfrm: Generate bl...
1014
  	return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1015
1016
1017
1018
1019
  }
  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...
1020
   *	@sk: socket which provides the dst cache and route info
4c9483b2f   David S. Miller   ipv6: Convert to ...
1021
   *	@fl6: flow to lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
1022
   *	@final_dst: final destination address for ipsec lookup
497c615ab   Herbert Xu   [IPV6]: Audit all...
1023
1024
1025
1026
1027
1028
   *
   *	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...
1029
1030
   *	It returns a valid dst pointer on success, or a pointer encoded
   *	error code.
497c615ab   Herbert Xu   [IPV6]: Audit all...
1031
   */
4c9483b2f   David S. Miller   ipv6: Convert to ...
1032
  struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
0e0d44ab4   Steffen Klassert   net: Remove FLOWI...
1033
  					 const struct in6_addr *final_dst)
497c615ab   Herbert Xu   [IPV6]: Audit all...
1034
  {
68d0c6d34   David S. Miller   ipv6: Consolidate...
1035
  	struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1036

4c9483b2f   David S. Miller   ipv6: Convert to ...
1037
  	dst = ip6_sk_dst_check(sk, dst, fl6);
00bc0ef58   Jakub Sitnicki   ipv6: Skip XFRM l...
1038
1039
  	if (!dst)
  		dst = ip6_dst_lookup_flow(sk, fl6, final_dst);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1040

00bc0ef58   Jakub Sitnicki   ipv6: Skip XFRM l...
1041
  	return dst;
497c615ab   Herbert Xu   [IPV6]: Audit all...
1042
  }
68d0c6d34   David S. Miller   ipv6: Consolidate...
1043
  EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1044

34a0b3cdc   Adrian Bunk   [IPV6]: make two ...
1045
  static inline int ip6_ufo_append_data(struct sock *sk,
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1046
  			struct sk_buff_head *queue,
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1047
1048
1049
  			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,
3ba3458fb   Jakub Sitnicki   ipv6: Count in ex...
1050
1051
  			int exthdrlen, int transhdrlen, int mtu,
  			unsigned int flags, const struct flowi6 *fl6)
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1052
1053
1054
1055
1056
1057
1058
1059
1060
  
  {
  	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
  	 */
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1061
  	skb = skb_peek_tail(queue);
63159f29b   Ian Morris   ipv6: coding styl...
1062
  	if (!skb) {
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1063
1064
1065
  		skb = sock_alloc_send_skb(sk,
  			hh_len + fragheaderlen + transhdrlen + 20,
  			(flags & MSG_DONTWAIT), &err);
63159f29b   Ian Morris   ipv6: coding styl...
1066
  		if (!skb)
504744e4e   Zheng Yan   ipv6: fix error p...
1067
  			return err;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1068
1069
1070
1071
1072
  
  		/* reserve space for Hardware header */
  		skb_reserve(skb, hh_len);
  
  		/* create space for UDP/IP header */
67ba4152e   Ian Morris   ipv6: White-space...
1073
  		skb_put(skb, fragheaderlen + transhdrlen);
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1074
1075
  
  		/* initialize network header pointer */
3ba3458fb   Jakub Sitnicki   ipv6: Count in ex...
1076
  		skb_set_network_header(skb, exthdrlen);
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1077
1078
  
  		/* initialize protocol header pointer */
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1079
  		skb->transport_header = skb->network_header + fragheaderlen;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1080

9c9c9ad5f   Hannes Frederic Sowa   ipv6: set skb->pr...
1081
  		skb->protocol = htons(ETH_P_IPV6);
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1082
  		skb->csum = 0;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1083

0bbe84a67   Vlad Yasevich   ipv6: Append send...
1084
  		__skb_queue_tail(queue, skb);
c547dbf55   Jiri Pirko   ip6_output: do sk...
1085
1086
  	} else if (skb_is_gso(skb)) {
  		goto append;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1087
  	}
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1088

c547dbf55   Jiri Pirko   ip6_output: do sk...
1089
1090
1091
1092
1093
1094
1095
  	skb->ip_summed = CHECKSUM_PARTIAL;
  	/* 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;
  	skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
fd0273d79   Martin KaFai Lau   ipv6: Remove exte...
1096
1097
1098
  	skb_shinfo(skb)->ip6_frag_id = ipv6_select_ident(sock_net(sk),
  							 &fl6->daddr,
  							 &fl6->saddr);
c547dbf55   Jiri Pirko   ip6_output: do sk...
1099
1100
  
  append:
2811ebac2   Hannes Frederic Sowa   ipv6: udp packets...
1101
1102
  	return skb_append_datato_frags(sk, skb, getfrag, from,
  				       (length - transhdrlen));
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1103
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104

0178b695f   Herbert Xu   ipv6: Copy cork o...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  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;
  }
75a493e60   Hannes Frederic Sowa   ipv6: ip6_append_...
1116
  static void ip6_append_data_mtu(unsigned int *mtu,
0c1833797   Gao feng   ipv6: fix incorre...
1117
1118
1119
  				int *maxfraglen,
  				unsigned int fragheaderlen,
  				struct sk_buff *skb,
75a493e60   Hannes Frederic Sowa   ipv6: ip6_append_...
1120
  				struct rt6_info *rt,
e367c2d03   lucien   ipv6: ip6_append_...
1121
  				unsigned int orig_mtu)
0c1833797   Gao feng   ipv6: fix incorre...
1122
1123
  {
  	if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
63159f29b   Ian Morris   ipv6: coding styl...
1124
  		if (!skb) {
0c1833797   Gao feng   ipv6: fix incorre...
1125
  			/* first fragment, reserve header_len */
e367c2d03   lucien   ipv6: ip6_append_...
1126
  			*mtu = orig_mtu - rt->dst.header_len;
0c1833797   Gao feng   ipv6: fix incorre...
1127
1128
1129
1130
1131
1132
  
  		} else {
  			/*
  			 * this fragment is not first, the headers
  			 * space is regarded as data space.
  			 */
e367c2d03   lucien   ipv6: ip6_append_...
1133
  			*mtu = orig_mtu;
0c1833797   Gao feng   ipv6: fix incorre...
1134
1135
1136
1137
1138
  		}
  		*maxfraglen = ((*mtu - fragheaderlen) & ~7)
  			      + fragheaderlen - sizeof(struct frag_hdr);
  	}
  }
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1139
  static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
26879da58   Wei Wang   ipv6: add new str...
1140
  			  struct inet6_cork *v6_cork, struct ipcm6_cookie *ipc6,
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1141
1142
1143
1144
  			  struct rt6_info *rt, struct flowi6 *fl6)
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	unsigned int mtu;
26879da58   Wei Wang   ipv6: add new str...
1145
  	struct ipv6_txoptions *opt = ipc6->opt;
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1146
1147
1148
1149
1150
1151
1152
1153
1154
  
  	/*
  	 * setup for corking
  	 */
  	if (opt) {
  		if (WARN_ON(v6_cork->opt))
  			return -EINVAL;
  
  		v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation);
63159f29b   Ian Morris   ipv6: coding styl...
1155
  		if (unlikely(!v6_cork->opt))
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1156
1157
1158
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
  			return -ENOBUFS;
  
  		v6_cork->opt->tot_len = opt->tot_len;
  		v6_cork->opt->opt_flen = opt->opt_flen;
  		v6_cork->opt->opt_nflen = opt->opt_nflen;
  
  		v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt,
  						    sk->sk_allocation);
  		if (opt->dst0opt && !v6_cork->opt->dst0opt)
  			return -ENOBUFS;
  
  		v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt,
  						    sk->sk_allocation);
  		if (opt->dst1opt && !v6_cork->opt->dst1opt)
  			return -ENOBUFS;
  
  		v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt,
  						   sk->sk_allocation);
  		if (opt->hopopt && !v6_cork->opt->hopopt)
  			return -ENOBUFS;
  
  		v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt,
  						    sk->sk_allocation);
  		if (opt->srcrt && !v6_cork->opt->srcrt)
  			return -ENOBUFS;
  
  		/* need source address above miyazawa*/
  	}
  	dst_hold(&rt->dst);
  	cork->base.dst = &rt->dst;
  	cork->fl.u.ip6 = *fl6;
26879da58   Wei Wang   ipv6: add new str...
1187
1188
  	v6_cork->hop_limit = ipc6->hlimit;
  	v6_cork->tclass = ipc6->tclass;
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
  	if (rt->dst.flags & DST_XFRM_TUNNEL)
  		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
  		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
  	else
  		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
  		      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
  	if (np->frag_size < mtu) {
  		if (np->frag_size)
  			mtu = np->frag_size;
  	}
  	cork->base.fragsize = mtu;
  	if (dst_allfrag(rt->dst.path))
  		cork->base.flags |= IPCORK_ALLFRAG;
  	cork->base.length = 0;
  
  	return 0;
  }
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1206
1207
1208
1209
1210
1211
1212
1213
1214
  static int __ip6_append_data(struct sock *sk,
  			     struct flowi6 *fl6,
  			     struct sk_buff_head *queue,
  			     struct inet_cork *cork,
  			     struct inet6_cork *v6_cork,
  			     struct page_frag *pfrag,
  			     int getfrag(void *from, char *to, int offset,
  					 int len, int odd, struct sk_buff *skb),
  			     void *from, int length, int transhdrlen,
26879da58   Wei Wang   ipv6: add new str...
1215
  			     unsigned int flags, struct ipcm6_cookie *ipc6,
c14ac9451   Soheil Hassas Yeganeh   sock: enable time...
1216
  			     const struct sockcm_cookie *sockc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
  {
0c1833797   Gao feng   ipv6: fix incorre...
1218
  	struct sk_buff *skb, *skb_prev = NULL;
e367c2d03   lucien   ipv6: ip6_append_...
1219
  	unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1220
1221
  	int exthdrlen = 0;
  	int dst_exthdrlen = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
  	int hh_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
1225
  	int copy;
  	int err;
  	int offset = 0;
a693e6989   Anders Berggren   net: TX timestamp...
1226
  	__u8 tx_flags = 0;
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1227
  	u32 tskey = 0;
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1228
1229
  	struct rt6_info *rt = (struct rt6_info *)cork->dst;
  	struct ipv6_txoptions *opt = v6_cork->opt;
32dce968d   Vlad Yasevich   ipv6: Allow for p...
1230
  	int csummode = CHECKSUM_NONE;
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1231
  	unsigned int maxnonfragsize, headersize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232

0bbe84a67   Vlad Yasevich   ipv6: Append send...
1233
1234
1235
  	skb = skb_peek_tail(queue);
  	if (!skb) {
  		exthdrlen = opt ? opt->opt_flen : 0;
7efdba5bd   Romain KUNTZ   ipv6: fix header ...
1236
  		dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
  	}
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1238

366e41d97   Vlad Yasevich   ipv6: pull cork i...
1239
  	mtu = cork->fragsize;
e367c2d03   lucien   ipv6: ip6_append_...
1240
  	orig_mtu = mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241

d8d1f30b9   Changli Gao   net-next: remove ...
1242
  	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243

a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1244
  	fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
b4ce92775   Herbert Xu   [IPV6]: Move nfhe...
1245
  			(opt ? opt->opt_nflen : 0);
4df98e76c   Hannes Frederic Sowa   ipv6: pmtudisc se...
1246
1247
  	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
  		     sizeof(struct frag_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248

682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1249
1250
1251
1252
1253
  	headersize = sizeof(struct ipv6hdr) +
  		     (opt ? opt->opt_flen + opt->opt_nflen : 0) +
  		     (dst_allfrag(&rt->dst) ?
  		      sizeof(struct frag_hdr) : 0) +
  		     rt->rt6i_nfheader_len;
26879da58   Wei Wang   ipv6: add new str...
1254
  	if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1255
1256
1257
1258
1259
1260
  	    (sk->sk_protocol == IPPROTO_UDP ||
  	     sk->sk_protocol == IPPROTO_RAW)) {
  		ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
  				sizeof(struct ipv6hdr));
  		goto emsgsize;
  	}
4df98e76c   Hannes Frederic Sowa   ipv6: pmtudisc se...
1261

682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1262
1263
1264
1265
  	if (ip6_sk_ignore_df(sk))
  		maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
  	else
  		maxnonfragsize = mtu;
4df98e76c   Hannes Frederic Sowa   ipv6: pmtudisc se...
1266

682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1267
  	if (cork->length + length > maxnonfragsize - headersize) {
4df98e76c   Hannes Frederic Sowa   ipv6: pmtudisc se...
1268
  emsgsize:
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1269
1270
1271
1272
  		ipv6_local_error(sk, EMSGSIZE, fl6,
  				 mtu - headersize +
  				 sizeof(struct ipv6hdr));
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273
  	}
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1274
1275
1276
1277
1278
1279
1280
  	/* CHECKSUM_PARTIAL only with no extension headers and when
  	 * we are not going to fragment
  	 */
  	if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
  	    headersize == sizeof(struct ipv6hdr) &&
  	    length < mtu - headersize &&
  	    !(flags & MSG_MORE) &&
c8cd0989b   Tom Herbert   net: Eliminate NE...
1281
  	    rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1282
  		csummode = CHECKSUM_PARTIAL;
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1283
  	if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) {
c14ac9451   Soheil Hassas Yeganeh   sock: enable time...
1284
  		sock_tx_timestamp(sk, sockc->tsflags, &tx_flags);
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1285
1286
1287
1288
  		if (tx_flags & SKBTX_ANY_SW_TSTAMP &&
  		    sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
  			tskey = sk->sk_tskey++;
  	}
a693e6989   Anders Berggren   net: TX timestamp...
1289

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290
1291
1292
1293
1294
1295
1296
  	/*
  	 * 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...
1297
  	 * of the buffer to the new fragment when we split
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
  	 * the message.
  	 *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1300
  	 * FIXME: It may be fragmented into multiple chunks
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
1302
  	 *        at once if non-fragmentable extension headers
  	 *        are too large.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1303
  	 * --yoshfuji
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
  	 */
2811ebac2   Hannes Frederic Sowa   ipv6: udp packets...
1305
1306
1307
1308
  	cork->length += length;
  	if (((length > mtu) ||
  	     (skb && skb_is_gso(skb))) &&
  	    (sk->sk_protocol == IPPROTO_UDP) &&
f89c56ce7   Jakub Sitnicki   ipv6: Don't use u...
1309
  	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
40ba33022   Michal Kubeček   udp: disallow UFO...
1310
  	    (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1311
  		err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
3ba3458fb   Jakub Sitnicki   ipv6: Count in ex...
1312
  					  hh_len, fragheaderlen, exthdrlen,
fd0273d79   Martin KaFai Lau   ipv6: Remove exte...
1313
  					  transhdrlen, mtu, flags, fl6);
2811ebac2   Hannes Frederic Sowa   ipv6: udp packets...
1314
1315
1316
  		if (err)
  			goto error;
  		return 0;
e89e9cf53   Ananda Raju   [IPv4/IPv6]: UFO ...
1317
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318

2811ebac2   Hannes Frederic Sowa   ipv6: udp packets...
1319
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
1322
1323
  		goto alloc_new_skb;
  
  	while (length > 0) {
  		/* Check if the remaining data fits into current packet. */
bdc712b4c   David S. Miller   inet: Decrease ov...
1324
  		copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
1326
1327
1328
1329
1330
1331
1332
1333
  		if (copy < length)
  			copy = maxfraglen - skb->len;
  
  		if (copy <= 0) {
  			char *data;
  			unsigned int datalen;
  			unsigned int fraglen;
  			unsigned int fraggap;
  			unsigned int alloclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
  alloc_new_skb:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
  			/* There's no room in the current skb */
0c1833797   Gao feng   ipv6: fix incorre...
1336
1337
  			if (skb)
  				fraggap = skb->len - maxfraglen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
  			else
  				fraggap = 0;
0c1833797   Gao feng   ipv6: fix incorre...
1340
  			/* update mtu and maxfraglen if necessary */
63159f29b   Ian Morris   ipv6: coding styl...
1341
  			if (!skb || !skb_prev)
0c1833797   Gao feng   ipv6: fix incorre...
1342
  				ip6_append_data_mtu(&mtu, &maxfraglen,
75a493e60   Hannes Frederic Sowa   ipv6: ip6_append_...
1343
  						    fragheaderlen, skb, rt,
e367c2d03   lucien   ipv6: ip6_append_...
1344
  						    orig_mtu);
0c1833797   Gao feng   ipv6: fix incorre...
1345
1346
  
  			skb_prev = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
1348
1349
1350
1351
1352
  
  			/*
  			 * If remaining data exceeds the mtu,
  			 * we know we need more fragment(s).
  			 */
  			datalen = length + fraggap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353

0c1833797   Gao feng   ipv6: fix incorre...
1354
1355
  			if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
  				datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
  			if ((flags & MSG_MORE) &&
d8d1f30b9   Changli Gao   net-next: remove ...
1357
  			    !(rt->dst.dev->features&NETIF_F_SG))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
  				alloclen = mtu;
  			else
  				alloclen = datalen + fragheaderlen;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1361
  			alloclen += dst_exthdrlen;
0c1833797   Gao feng   ipv6: fix incorre...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
  			if (datalen != length + fraggap) {
  				/*
  				 * this is not the last fragment, the trailer
  				 * space is regarded as data space.
  				 */
  				datalen += rt->dst.trailer_len;
  			}
  
  			alloclen += rt->dst.trailer_len;
  			fraglen = datalen + fragheaderlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
1373
1374
  
  			/*
  			 * We just reserve space for fragment header.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1375
  			 * Note: this may be overallocation if the message
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
  			 * (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);
63159f29b   Ian Morris   ipv6: coding styl...
1391
  				if (unlikely(!skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
1393
  					err = -ENOBUFS;
  			}
63159f29b   Ian Morris   ipv6: coding styl...
1394
  			if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
1396
1397
1398
  				goto error;
  			/*
  			 *	Fill in the control structures
  			 */
9c9c9ad5f   Hannes Frederic Sowa   ipv6: set skb->pr...
1399
  			skb->protocol = htons(ETH_P_IPV6);
32dce968d   Vlad Yasevich   ipv6: Allow for p...
1400
  			skb->ip_summed = csummode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
  			skb->csum = 0;
1f85851e1   Gao feng   ipv6: fix incorre...
1402
1403
1404
  			/* reserve for fragmentation and ipsec header */
  			skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +
  				    dst_exthdrlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405

11878b40e   Willem de Bruijn   net-timestamp: SO...
1406
1407
1408
  			/* Only the initial fragment is time stamped */
  			skb_shinfo(skb)->tx_flags = tx_flags;
  			tx_flags = 0;
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1409
1410
  			skb_shinfo(skb)->tskey = tskey;
  			tskey = 0;
a693e6989   Anders Berggren   net: TX timestamp...
1411

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
  			/*
  			 *	Find where to start putting bytes
  			 */
1f85851e1   Gao feng   ipv6: fix incorre...
1415
1416
1417
  			data = skb_put(skb, fraglen);
  			skb_set_network_header(skb, exthdrlen);
  			data += fragheaderlen;
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1418
1419
  			skb->transport_header = (skb->network_header +
  						 fragheaderlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1420
1421
1422
1423
1424
1425
1426
  			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_...
1427
  				pskb_trim_unique(skb_prev, maxfraglen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1428
1429
  			}
  			copy = datalen - transhdrlen - fraggap;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1430

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
  			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...
1445
  			dst_exthdrlen = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
1449
  
  			/*
  			 * Put the packet on the pending queue
  			 */
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1450
  			__skb_queue_tail(queue, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
1452
1453
1454
1455
  			continue;
  		}
  
  		if (copy > length)
  			copy = length;
d8d1f30b9   Changli Gao   net-next: remove ...
1456
  		if (!(rt->dst.dev->features&NETIF_F_SG)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
  			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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468

5640f7685   Eric Dumazet   net: use a per ta...
1469
1470
  			err = -ENOMEM;
  			if (!sk_page_frag_refill(sk, pfrag))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
  				goto error;
5640f7685   Eric Dumazet   net: use a per ta...
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  
  			if (!skb_can_coalesce(skb, i, pfrag->page,
  					      pfrag->offset)) {
  				err = -EMSGSIZE;
  				if (i == MAX_SKB_FRAGS)
  					goto error;
  
  				__skb_fill_page_desc(skb, i, pfrag->page,
  						     pfrag->offset, 0);
  				skb_shinfo(skb)->nr_frags = ++i;
  				get_page(pfrag->page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
  			}
5640f7685   Eric Dumazet   net: use a per ta...
1484
  			copy = min_t(int, copy, pfrag->size - pfrag->offset);
9e903e085   Eric Dumazet   net: add skb frag...
1485
  			if (getfrag(from,
5640f7685   Eric Dumazet   net: use a per ta...
1486
1487
1488
1489
1490
1491
  				    page_address(pfrag->page) + pfrag->offset,
  				    offset, copy, skb->len, skb) < 0)
  				goto error_efault;
  
  			pfrag->offset += copy;
  			skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1492
1493
  			skb->len += copy;
  			skb->data_len += copy;
f945fa7ad   Herbert Xu   [INET]: Fix trues...
1494
1495
  			skb->truesize += copy;
  			atomic_add(copy, &sk->sk_wmem_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1496
1497
1498
1499
  		}
  		offset += copy;
  		length -= copy;
  	}
5640f7685   Eric Dumazet   net: use a per ta...
1500

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
  	return 0;
5640f7685   Eric Dumazet   net: use a per ta...
1502
1503
1504
  
  error_efault:
  	err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505
  error:
bdc712b4c   David S. Miller   inet: Decrease ov...
1506
  	cork->length -= length;
3bd653c84   Denis V. Lunev   netns: add net pa...
1507
  	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508
1509
  	return err;
  }
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1510
1511
1512
1513
  
  int ip6_append_data(struct sock *sk,
  		    int getfrag(void *from, char *to, int offset, int len,
  				int odd, struct sk_buff *skb),
26879da58   Wei Wang   ipv6: add new str...
1514
1515
1516
  		    void *from, int length, int transhdrlen,
  		    struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
  		    struct rt6_info *rt, unsigned int flags,
c14ac9451   Soheil Hassas Yeganeh   sock: enable time...
1517
  		    const struct sockcm_cookie *sockc)
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	int exthdrlen;
  	int err;
  
  	if (flags&MSG_PROBE)
  		return 0;
  	if (skb_queue_empty(&sk->sk_write_queue)) {
  		/*
  		 * setup for corking
  		 */
26879da58   Wei Wang   ipv6: add new str...
1530
1531
  		err = ip6_setup_cork(sk, &inet->cork, &np->cork,
  				     ipc6, rt, fl6);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1532
1533
  		if (err)
  			return err;
26879da58   Wei Wang   ipv6: add new str...
1534
  		exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1535
1536
1537
1538
1539
1540
1541
1542
1543
  		length += exthdrlen;
  		transhdrlen += exthdrlen;
  	} else {
  		fl6 = &inet->cork.fl.u.ip6;
  		transhdrlen = 0;
  	}
  
  	return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
  				 &np->cork, sk_page_frag(sk), getfrag,
26879da58   Wei Wang   ipv6: add new str...
1544
  				 from, length, transhdrlen, flags, ipc6, sockc);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1545
  }
a495f8364   Chris Elston   ipv6: Export ipv6...
1546
  EXPORT_SYMBOL_GPL(ip6_append_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547

366e41d97   Vlad Yasevich   ipv6: pull cork i...
1548
1549
  static void ip6_cork_release(struct inet_cork_full *cork,
  			     struct inet6_cork *v6_cork)
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1550
  {
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1551
1552
1553
1554
1555
1556
1557
  	if (v6_cork->opt) {
  		kfree(v6_cork->opt->dst0opt);
  		kfree(v6_cork->opt->dst1opt);
  		kfree(v6_cork->opt->hopopt);
  		kfree(v6_cork->opt->srcrt);
  		kfree(v6_cork->opt);
  		v6_cork->opt = NULL;
0178b695f   Herbert Xu   ipv6: Copy cork o...
1558
  	}
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1559
1560
1561
1562
  	if (cork->base.dst) {
  		dst_release(cork->base.dst);
  		cork->base.dst = NULL;
  		cork->base.flags &= ~IPCORK_ALLFRAG;
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1563
  	}
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1564
  	memset(&cork->fl, 0, sizeof(cork->fl));
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1565
  }
6422398c2   Vlad Yasevich   ipv6: introduce i...
1566
1567
1568
1569
  struct sk_buff *__ip6_make_skb(struct sock *sk,
  			       struct sk_buff_head *queue,
  			       struct inet_cork_full *cork,
  			       struct inet6_cork *v6_cork)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
1572
1573
  {
  	struct sk_buff *skb, *tmp_skb;
  	struct sk_buff **tail_skb;
  	struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
  	struct ipv6_pinfo *np = inet6_sk(sk);
3bd653c84   Denis V. Lunev   netns: add net pa...
1575
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
  	struct ipv6hdr *hdr;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1577
1578
1579
  	struct ipv6_txoptions *opt = v6_cork->opt;
  	struct rt6_info *rt = (struct rt6_info *)cork->base.dst;
  	struct flowi6 *fl6 = &cork->fl.u.ip6;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1580
  	unsigned char proto = fl6->flowi6_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581

6422398c2   Vlad Yasevich   ipv6: introduce i...
1582
  	skb = __skb_dequeue(queue);
63159f29b   Ian Morris   ipv6: coding styl...
1583
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
1586
1587
  		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...
1588
  	if (skb->data < skb_network_header(skb))
bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1589
  		__skb_pull(skb, skb_network_offset(skb));
6422398c2   Vlad Yasevich   ipv6: introduce i...
1590
  	while ((tmp_skb = __skb_dequeue(queue)) != NULL) {
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1591
  		__skb_pull(tmp_skb, skb_network_header_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1592
1593
1594
1595
  		*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
1596
  		skb->truesize += tmp_skb->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
  		tmp_skb->destructor = NULL;
  		tmp_skb->sk = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599
  	}
28a89453b   Herbert Xu   [IPV6]: Fix IPsec...
1600
  	/* Allow local fragmentation. */
60ff74673   WANG Cong   net: rename local...
1601
  	skb->ignore_df = ip6_sk_ignore_df(sk);
28a89453b   Herbert Xu   [IPV6]: Fix IPsec...
1602

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1603
  	*final_dst = fl6->daddr;
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1604
  	__skb_pull(skb, skb_network_header_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
  	if (opt && opt->opt_flen)
  		ipv6_push_frag_opts(skb, opt, &proto);
  	if (opt && opt->opt_nflen)
613fa3ca9   David Lebrun   ipv6: add source ...
1608
  		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst, &fl6->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1609

e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
1610
1611
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1612
  	hdr = ipv6_hdr(skb);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1613

6422398c2   Vlad Yasevich   ipv6: introduce i...
1614
  	ip6_flow_hdr(hdr, v6_cork->tclass,
cb1ce2ef3   Tom Herbert   ipv6: Implement a...
1615
  		     ip6_make_flowlabel(net, skb, fl6->flowlabel,
67800f9b1   Tom Herbert   ipv6: Call skb_ge...
1616
  					np->autoflowlabel, fl6));
6422398c2   Vlad Yasevich   ipv6: introduce i...
1617
  	hdr->hop_limit = v6_cork->hop_limit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
  	hdr->nexthdr = proto;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1619
1620
  	hdr->saddr = fl6->saddr;
  	hdr->daddr = *final_dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621

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

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

43a43b604   Hannes Frederic Sowa   ipv6: some ipv6 s...
1630
1631
  		ICMP6MSGOUT_INC_STATS(net, idev, icmp6_hdr(skb)->icmp6_type);
  		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
1632
  	}
6422398c2   Vlad Yasevich   ipv6: introduce i...
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
  	ip6_cork_release(cork, v6_cork);
  out:
  	return skb;
  }
  
  int ip6_send_skb(struct sk_buff *skb)
  {
  	struct net *net = sock_net(skb->sk);
  	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
  	int err;
33224b16f   Eric W. Biederman   ipv4, ipv6: Pass ...
1643
  	err = ip6_local_out(net, skb->sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
  	if (err) {
  		if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
1646
  			err = net_xmit_errno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
  		if (err)
6422398c2   Vlad Yasevich   ipv6: introduce i...
1648
1649
  			IP6_INC_STATS(net, rt->rt6i_idev,
  				      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1650
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
  	return err;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
  }
  
  int ip6_push_pending_frames(struct sock *sk)
  {
  	struct sk_buff *skb;
  
  	skb = ip6_finish_skb(sk);
  	if (!skb)
  		return 0;
  
  	return ip6_send_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
  }
a495f8364   Chris Elston   ipv6: Export ipv6...
1664
  EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665

0bbe84a67   Vlad Yasevich   ipv6: Append send...
1666
  static void __ip6_flush_pending_frames(struct sock *sk,
6422398c2   Vlad Yasevich   ipv6: introduce i...
1667
1668
1669
  				       struct sk_buff_head *queue,
  				       struct inet_cork_full *cork,
  				       struct inet6_cork *v6_cork)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
  	struct sk_buff *skb;
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1672
  	while ((skb = __skb_dequeue_tail(queue)) != NULL) {
adf30907d   Eric Dumazet   net: skb->dst acc...
1673
1674
  		if (skb_dst(skb))
  			IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
e1f52208b   YOSHIFUJI Hideaki   [IPv6]: Fix NULL ...
1675
  				      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1676
1677
  		kfree_skb(skb);
  	}
6422398c2   Vlad Yasevich   ipv6: introduce i...
1678
  	ip6_cork_release(cork, v6_cork);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
  }
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1680
1681
1682
  
  void ip6_flush_pending_frames(struct sock *sk)
  {
6422398c2   Vlad Yasevich   ipv6: introduce i...
1683
1684
  	__ip6_flush_pending_frames(sk, &sk->sk_write_queue,
  				   &inet_sk(sk)->cork, &inet6_sk(sk)->cork);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1685
  }
a495f8364   Chris Elston   ipv6: Export ipv6...
1686
  EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1687
1688
1689
1690
1691
  
  struct sk_buff *ip6_make_skb(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,
26879da58   Wei Wang   ipv6: add new str...
1692
  			     struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
6422398c2   Vlad Yasevich   ipv6: introduce i...
1693
  			     struct rt6_info *rt, unsigned int flags,
26879da58   Wei Wang   ipv6: add new str...
1694
  			     const struct sockcm_cookie *sockc)
6422398c2   Vlad Yasevich   ipv6: introduce i...
1695
1696
1697
1698
  {
  	struct inet_cork_full cork;
  	struct inet6_cork v6_cork;
  	struct sk_buff_head queue;
26879da58   Wei Wang   ipv6: add new str...
1699
  	int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
  	int err;
  
  	if (flags & MSG_PROBE)
  		return NULL;
  
  	__skb_queue_head_init(&queue);
  
  	cork.base.flags = 0;
  	cork.base.addr = 0;
  	cork.base.opt = NULL;
  	v6_cork.opt = NULL;
26879da58   Wei Wang   ipv6: add new str...
1711
  	err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1712
1713
  	if (err)
  		return ERR_PTR(err);
26879da58   Wei Wang   ipv6: add new str...
1714
1715
  	if (ipc6->dontfrag < 0)
  		ipc6->dontfrag = inet6_sk(sk)->dontfrag;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1716
1717
1718
1719
  
  	err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork,
  				&current->task_frag, getfrag, from,
  				length + exthdrlen, transhdrlen + exthdrlen,
26879da58   Wei Wang   ipv6: add new str...
1720
  				flags, ipc6, sockc);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1721
1722
1723
1724
1725
1726
1727
  	if (err) {
  		__ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork);
  		return ERR_PTR(err);
  	}
  
  	return __ip6_make_skb(sk, &queue, &cork, &v6_cork);
  }