Blame view

net/ipv6/ip6_output.c 44.5 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

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
69
  	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
adf30907d   Eric Dumazet   net: skb->dst acc...
70
  		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

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

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

78126c419   Eric W. Biederman   ipv6: Only comput...
122
  	IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
123
124
  	kfree_skb(skb);
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  }
0c4b51f00   Eric W. Biederman   netfilter: Pass n...
126
  static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
127
  {
33b486793   Daniel Mack   net: ipv4, ipv6: ...
128
129
130
131
132
133
134
  	int ret;
  
  	ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
  	if (ret) {
  		kfree_skb(skb);
  		return ret;
  	}
fd78be4b3   Tobias Brunner   ipv6: Reinject IP...
135
136
137
138
139
140
141
  #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
  	/* Policy lookup after SNAT yielded a new policy */
  	if (skb_dst(skb)->xfrm) {
  		IPCB(skb)->flags |= IPSKB_REROUTED;
  		return dst_output(net, sk, skb);
  	}
  #endif
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
142
  	if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
9037c3579   Jiri Pirko   ip6_output: fragm...
143
144
  	    dst_allfrag(skb_dst(skb)) ||
  	    (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size))
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
145
  		return ip6_fragment(net, sk, skb, ip6_finish_output2);
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
146
  	else
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
147
  		return ip6_finish_output2(net, sk, skb);
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
148
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
149
  int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  {
9e5084905   Jan Engelhardt   netfilter: ipv6: ...
151
  	struct net_device *dev = skb_dst(skb)->dev;
adf30907d   Eric Dumazet   net: skb->dst acc...
152
  	struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
be10de0a3   Eric W. Biederman   netfilter: Add bl...
153

97a7a37a7   Chenbo Feng   ipv6: Initial skb...
154
155
  	skb->protocol = htons(ETH_P_IPV6);
  	skb->dev = dev;
778d80be5   YOSHIFUJI Hideaki   ipv6: Add disable...
156
  	if (unlikely(idev->cnf.disable_ipv6)) {
19a0644ca   Eric W. Biederman   ipv6: Cache net i...
157
  		IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
778d80be5   YOSHIFUJI Hideaki   ipv6: Add disable...
158
159
160
  		kfree_skb(skb);
  		return 0;
  	}
29a26a568   Eric W. Biederman   netfilter: Pass s...
161
162
  	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
  			    net, sk, skb, NULL, dev,
9c6eb28ac   Jan Engelhardt   netfilter: ipv6: ...
163
164
  			    ip6_finish_output,
  			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
2295b3dd5   Ben Hutchings   ipv6: Fix getsock...
166
  bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np)
6d0317869   Shaohua Li   net: reevalulate ...
167
168
169
170
171
172
  {
  	if (!np->autoflowlabel_set)
  		return ip6_default_np_autolabel(net);
  	else
  		return np->autoflowlabel;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  /*
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
174
175
176
177
   * 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
178
   */
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
179
  int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
92e55f412   Pablo Neira   tcp: don't annota...
180
  	     __u32 mark, struct ipv6_txoptions *opt, int tclass)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
3bd653c84   Denis V. Lunev   netns: add net pa...
182
  	struct net *net = sock_net(sk);
1c1e9d2b6   Eric Dumazet   ipv6: constify ip...
183
  	const struct ipv6_pinfo *np = inet6_sk(sk);
4c9483b2f   David S. Miller   ipv6: Convert to ...
184
  	struct in6_addr *first_hop = &fl6->daddr;
adf30907d   Eric Dumazet   net: skb->dst acc...
185
  	struct dst_entry *dst = skb_dst(skb);
ece6a4b7e   Stefano Brivio   ipv6: Check avail...
186
  	unsigned int head_room;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	struct ipv6hdr *hdr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
188
  	u8  proto = fl6->flowi6_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	int seg_len = skb->len;
e651f03af   Gerrit Renker   inet6: Conversion...
190
  	int hlimit = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	u32 mtu;
ece6a4b7e   Stefano Brivio   ipv6: Check avail...
192
193
194
195
196
197
198
199
200
201
202
  	head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
  	if (opt)
  		head_room += opt->opt_nflen + opt->opt_flen;
  
  	if (unlikely(skb_headroom(skb) < head_room)) {
  		struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
  		if (!skb2) {
  			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
  				      IPSTATS_MIB_OUTDISCARDS);
  			kfree_skb(skb);
  			return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  		}
ece6a4b7e   Stefano Brivio   ipv6: Check avail...
204
205
206
207
208
209
210
211
  		if (skb->sk)
  			skb_set_owner_w(skb2, skb->sk);
  		consume_skb(skb);
  		skb = skb2;
  	}
  
  	if (opt) {
  		seg_len += opt->opt_nflen + opt->opt_flen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
  		if (opt->opt_flen)
  			ipv6_push_frag_opts(skb, opt, &proto);
ece6a4b7e   Stefano Brivio   ipv6: Check avail...
214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  		if (opt->opt_nflen)
613fa3ca9   David Lebrun   ipv6: add source ...
216
217
  			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
  					     &fl6->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	}
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
219
220
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
221
  	hdr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
  
  	/*
  	 *	Fill in the IPv6 header
  	 */
b903d324b   Eric Dumazet   ipv6: tcp: fix TC...
226
  	if (np)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
  		hlimit = np->hop_limit;
  	if (hlimit < 0)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
229
  		hlimit = ip6_dst_hoplimit(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230

cb1ce2ef3   Tom Herbert   ipv6: Implement a...
231
  	ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel,
6d0317869   Shaohua Li   net: reevalulate ...
232
  				ip6_autoflowlabel(net, np), fl6));
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
233

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
  	hdr->payload_len = htons(seg_len);
  	hdr->nexthdr = proto;
  	hdr->hop_limit = hlimit;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
237
238
  	hdr->saddr = fl6->saddr;
  	hdr->daddr = *first_hop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

9c9c9ad5f   Hannes Frederic Sowa   ipv6: set skb->pr...
240
  	skb->protocol = htons(ETH_P_IPV6);
a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
241
  	skb->priority = sk->sk_priority;
92e55f412   Pablo Neira   tcp: don't annota...
242
  	skb->mark = mark;
a2c2064f7   Patrick McHardy   [IPV6]: Set skb->...
243

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  	hdr->hop_limit--;
29a26a568   Eric W. Biederman   netfilter: Pass s...
529
530
  	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
  		       net, NULL, skb, skb->dev, dst->dev,
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
531
  		       ip6_forward_finish);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  
  error:
1d0155035   Eric Dumazet   ipv6: rename IP6_...
534
  	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
541
542
543
544
  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...
545
546
  	skb_dst_drop(to);
  	skb_dst_set(to, dst_clone(skb_dst(from)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  	to->dev = from->dev;
82e91ffef   Thomas Graf   [NET]: Turn nfmar...
548
  	to->mark = from->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

c2ce657fd   Paolo Abeni   ip: hash fragment...
550
  	skb_copy_hash(to, from);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
  #ifdef CONFIG_NET_SCHED
  	to->tc_index = from->tc_index;
  #endif
e7ac05f34   Yasuyuki Kozakai   [NETFILTER]: nf_c...
554
  	nf_copy(to, from);
984bc16cc   James Morris   [SECMARK]: Add se...
555
  	skb_copy_secmark(to, from);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  }
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
557
558
  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
559
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  	struct sk_buff *frag;
67ba4152e   Ian Morris   ipv6: White-space...
561
  	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
f60e5990d   hannes@stressinduktion.org   ipv6: protect skb...
562
563
  	struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
  				inet6_sk(skb->sk) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
  	struct ipv6hdr *tmp_hdr;
  	struct frag_hdr *fh;
  	unsigned int mtu, hlen, left, len;
a7ae19922   Herbert Xu   ipv6: Remove all ...
567
  	int hroom, troom;
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
568
  	__be32 frag_id;
67ba4152e   Ian Morris   ipv6: White-space...
569
  	int ptr, offset = 0, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  	u8 *prevhdr, nexthdr = 0;
7dd7eb951   David S. Miller   ipv6: Check ip6_f...
571
572
  	err = ip6_find_1stfragopt(skb, &prevhdr);
  	if (err < 0)
2423496af   Craig Gallek   ipv6: Prevent ove...
573
  		goto fail;
7dd7eb951   David S. Miller   ipv6: Check ip6_f...
574
  	hlen = err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  	nexthdr = *prevhdr;
628a5c561   John Heffner   [INET]: Add IP(V6...
576
  	mtu = ip6_skb_dst_mtu(skb);
b881ef760   John Heffner   [IPV6]: MTU disco...
577
578
  
  	/* We must not fragment if the socket is set to force MTU discovery
14f3ad6f4   Ulrich Weber   ipv6: Use 1280 as...
579
  	 * or if the skb it not generated by a local socket.
b881ef760   John Heffner   [IPV6]: MTU disco...
580
  	 */
485fca664   Florian Westphal   ipv6: don't incre...
581
582
  	if (unlikely(!skb->ignore_df && skb->len > mtu))
  		goto fail_toobig;
a34a101e1   Eric Dumazet   ipv6: disable GSO...
583

485fca664   Florian Westphal   ipv6: don't incre...
584
585
586
587
588
589
590
591
  	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...
592
  	}
d91675f9c   YOSHIFUJI Hideaki   [IPV6]: Do not ig...
593
594
595
596
  	if (np && np->frag_size < mtu) {
  		if (np->frag_size)
  			mtu = np->frag_size;
  	}
89bc7848a   Hannes Frederic Sowa   ipv6: protect mtu...
597
  	if (mtu < hlen + sizeof(struct frag_hdr) + 8)
b72a2b01b   Hannes Frederic Sowa   ipv6: protect mtu...
598
  		goto fail_toobig;
1e0d69a9c   Hannes Frederic Sowa   Revert "Merge bra...
599
  	mtu -= hlen + sizeof(struct frag_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600

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

405c92f7a   Hannes Frederic Sowa   ipv6: add defensi...
604
605
606
  	if (skb->ip_summed == CHECKSUM_PARTIAL &&
  	    (err = skb_checksum_help(skb)))
  		goto fail;
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
607
  	hroom = LL_RESERVED_SPACE(rt->dst.dev);
21dc33015   David S. Miller   net: Rename skb_h...
608
  	if (skb_has_frag_list(skb)) {
c72d8cdaa   Alexey Dobriyan   net: fix bogus ca...
609
  		unsigned int first_len = skb_pagelen(skb);
3d13008e7   Eric Dumazet   ip: fix truesize ...
610
  		struct sk_buff *frag2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
  
  		if (first_len - hlen > mtu ||
  		    ((first_len - hlen) & 7) ||
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
614
615
  		    skb_cloned(skb) ||
  		    skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
  			goto slow_path;
4d9092bb4   David S. Miller   ipv6: Use frag li...
617
  		skb_walk_frags(skb, frag) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
  			/* Correct geometry. */
  			if (frag->len > mtu ||
  			    ((frag->len & 7) && frag->next) ||
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
621
  			    skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
3d13008e7   Eric Dumazet   ip: fix truesize ...
622
  				goto slow_path_clean;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
  			/* Partially cloned skb? */
  			if (skb_shared(frag))
3d13008e7   Eric Dumazet   ip: fix truesize ...
626
  				goto slow_path_clean;
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
627
628
629
  
  			BUG_ON(frag->sk);
  			if (skb->sk) {
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
630
631
  				frag->sk = skb->sk;
  				frag->destructor = sock_wfree;
2fdba6b08   Herbert Xu   [IPV4/IPV6] Ensur...
632
  			}
3d13008e7   Eric Dumazet   ip: fix truesize ...
633
  			skb->truesize -= frag->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
  		}
  
  		err = 0;
  		offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  		/* BUILD HEADER */
9a217a1c7   YOSHIFUJI Hideaki   [IPV6]: Repair IP...
639
  		*prevhdr = NEXTHDR_FRAGMENT;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
640
  		tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  		if (!tmp_hdr) {
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
642
643
  			err = -ENOMEM;
  			goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  		}
1d325d217   Florian Westphal   ipv6: ip6_fragmen...
645
646
  		frag = skb_shinfo(skb)->frag_list;
  		skb_frag_list_init(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  		__skb_pull(skb, hlen);
d58ff3512   Johannes Berg   networking: make ...
649
  		fh = __skb_push(skb, sizeof(struct frag_hdr));
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
650
651
  		__skb_push(skb, hlen);
  		skb_reset_network_header(skb);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
652
  		memcpy(skb_network_header(skb), tmp_hdr, hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
  		fh->nexthdr = nexthdr;
  		fh->reserved = 0;
  		fh->frag_off = htons(IP6_MF);
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
657
  		fh->identification = frag_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
659
660
661
  
  		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...
662
663
  		ipv6_hdr(skb)->payload_len = htons(first_len -
  						   sizeof(struct ipv6hdr));
a11d206d0   YOSHIFUJI Hideaki   [IPV6]: Per-inter...
664

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
668
669
  		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...
670
  				skb_reset_transport_header(frag);
d58ff3512   Johannes Berg   networking: make ...
671
  				fh = __skb_push(frag, sizeof(struct frag_hdr));
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
672
673
  				__skb_push(frag, hlen);
  				skb_reset_network_header(frag);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
674
675
  				memcpy(skb_network_header(frag), tmp_hdr,
  				       hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
  				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...
680
  				if (frag->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
  					fh->frag_off |= htons(IP6_MF);
  				fh->identification = frag_id;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
683
684
685
  				ipv6_hdr(frag)->payload_len =
  						htons(frag->len -
  						      sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
  				ip6_copy_metadata(frag, skb);
  			}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
688

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
697
698
699
700
  			if (err || !frag)
  				break;
  
  			skb = frag;
  			frag = skb->next;
  			skb->next = NULL;
  		}
a51482bde   Jesper Juhl   [NET]: kfree cleanup
701
  		kfree(tmp_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  
  		if (err == 0) {
d8d1f30b9   Changli Gao   net-next: remove ...
704
  			IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
705
  				      IPSTATS_MIB_FRAGOKS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  			return 0;
  		}
46cfd725c   Florian Westphal   net: use kfree_sk...
708
  		kfree_skb_list(frag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709

d8d1f30b9   Changli Gao   net-next: remove ...
710
  		IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
3bd653c84   Denis V. Lunev   netns: add net pa...
711
  			      IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  		return err;
3d13008e7   Eric Dumazet   ip: fix truesize ...
713
714
715
716
717
718
719
720
721
  
  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
722
723
724
725
726
727
728
729
730
  	}
  
  slow_path:
  	left = skb->len - hlen;		/* Space per frame */
  	ptr = hlen;			/* Where to start from */
  
  	/*
  	 *	Fragment the datagram.
  	 */
a7ae19922   Herbert Xu   ipv6: Remove all ...
731
  	troom = rt->dst.dev->needed_tailroom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
  
  	/*
  	 *	Keep copying data until we run out.
  	 */
67ba4152e   Ian Morris   ipv6: White-space...
736
  	while (left > 0)	{
79e49503e   Florian Westphal   ipv6: avoid write...
737
  		u8 *fragnexthdr_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
741
  		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...
742
  		/* IF: we are not sending up to and including the packet end
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
  		   then align the next start on an eight byte boundary */
  		if (len < left)	{
  			len &= ~7;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747

cbffccc97   Joe Perches   net; ipv[46] - Re...
748
749
750
751
  		/* Allocate buffer */
  		frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
  				 hroom + troom, GFP_ATOMIC);
  		if (!frag) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
757
758
759
760
  			err = -ENOMEM;
  			goto fail;
  		}
  
  		/*
  		 *	Set up data on packet
  		 */
  
  		ip6_copy_metadata(frag, skb);
a7ae19922   Herbert Xu   ipv6: Remove all ...
761
  		skb_reserve(frag, hroom);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  		skb_put(frag, len + hlen + sizeof(struct frag_hdr));
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
763
  		skb_reset_network_header(frag);
badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
764
  		fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
765
766
  		frag->transport_header = (frag->network_header + hlen +
  					  sizeof(struct frag_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
774
775
776
777
  
  		/*
  		 *	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...
778
  		skb_copy_from_linear_data(skb, skb_network_header(frag), hlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779

79e49503e   Florian Westphal   ipv6: avoid write...
780
781
782
  		fragnexthdr_offset = skb_network_header(frag);
  		fragnexthdr_offset += prevhdr - skb_network_header(skb);
  		*fragnexthdr_offset = NEXTHDR_FRAGMENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
786
787
  		/*
  		 *	Build fragment header.
  		 */
  		fh->nexthdr = nexthdr;
  		fh->reserved = 0;
286c2349f   Martin KaFai Lau   ipv6: Clean up ip...
788
  		fh->identification = frag_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
792
  
  		/*
  		 *	Copy a block of the IP datagram.
  		 */
e3f0b86b9   Himangi Saraogi   ipv6: Use BUG_ON
793
794
  		BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag),
  				     len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
  		left -= len;
  
  		fh->frag_off = htons(offset);
  		if (left > 0)
  			fh->frag_off |= htons(IP6_MF);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
800
801
  		ipv6_hdr(frag)->payload_len = htons(frag->len -
  						    sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
806
807
808
  
  		ptr += len;
  		offset += len;
  
  		/*
  		 *	Put this fragment into the sending queue.
  		 */
7d8c6e391   Eric W. Biederman   ipv6: Pass struct...
809
  		err = output(net, sk, frag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  		if (err)
  			goto fail;
dafee4908   Wei Dong   [IPV6]: SNMPv2 "i...
812

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

497c615ab   Herbert Xu   [IPV6]: Audit all...
845
846
  	if (!dst)
  		goto out;
a963a37d3   Eric Dumazet   ipv6: ip6_sk_dst_...
847
848
849
850
851
852
  	if (dst->ops->family != AF_INET6) {
  		dst_release(dst);
  		return NULL;
  	}
  
  	rt = (struct rt6_info *)dst;
497c615ab   Herbert Xu   [IPV6]: Audit all...
853
854
855
  	/* 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...
856
  	 * and MSG_DONTROUTE		--ANK (980726)
497c615ab   Herbert Xu   [IPV6]: Audit all...
857
  	 *
cf6b19825   YOSHIFUJI Hideaki   [IPV6] ROUTE: Int...
858
859
  	 * 1. ip6_rt_check(): If route was host route,
  	 *    check that cached destination is current.
497c615ab   Herbert Xu   [IPV6]: Audit all...
860
861
862
863
864
865
866
867
868
869
  	 *    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 ...
870
  	if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) ||
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
871
  #ifdef CONFIG_IPV6_SUBTREES
4c9483b2f   David S. Miller   ipv6: Convert to ...
872
  	    ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) ||
8e1ef0a95   YOSHIFUJI Hideaki   [IPV6]: Cache sou...
873
  #endif
ca254490c   David Ahern   net: Add VRF supp...
874
875
  	   (!(fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) &&
  	      (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex))) {
497c615ab   Herbert Xu   [IPV6]: Audit all...
876
877
  		dst_release(dst);
  		dst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	}
497c615ab   Herbert Xu   [IPV6]: Audit all...
879
880
881
  out:
  	return dst;
  }
3aef934f4   Eric Dumazet   ipv6: constify ip...
882
  static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
4c9483b2f   David S. Miller   ipv6: Convert to ...
883
  			       struct dst_entry **dst, struct flowi6 *fl6)
497c615ab   Herbert Xu   [IPV6]: Audit all...
884
  {
69cce1d14   David S. Miller   net: Abstract dst...
885
886
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
  	struct neighbour *n;
97cac0821   David S. Miller   ipv6: Store route...
887
  	struct rt6_info *rt;
69cce1d14   David S. Miller   net: Abstract dst...
888
889
  #endif
  	int err;
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
890
  	int flags = 0;
497c615ab   Herbert Xu   [IPV6]: Audit all...
891

e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
892
893
894
895
896
897
898
899
900
901
902
903
  	/* 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
904

e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
905
906
907
  		if (!had_dst)
  			*dst = ip6_route_output(net, sk, fl6);
  		rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
908
909
910
  		err = ip6_route_get_saddr(net, rt, &fl6->daddr,
  					  sk ? inet6_sk(sk)->srcprefs : 0,
  					  &fl6->saddr);
44456d37b   Olaf Hering   [PATCH] turn many...
911
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  			goto out_err_release;
e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
913
914
915
916
917
918
919
920
921
  
  		/* 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...
922
923
924
  
  		if (fl6->flowi6_oif)
  			flags |= RT6_LOOKUP_F_IFACE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  	}
e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
926
  	if (!*dst)
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
927
  		*dst = ip6_route_output_flags(net, sk, fl6, flags);
e16e888b5   Markus Stenberg   ipv6: Fixed sourc...
928
929
930
931
  
  	err = (*dst)->error;
  	if (err)
  		goto out_err_release;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
932
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
933
934
935
936
937
938
939
940
  	/*
  	 * 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...
941
  	rt = (struct rt6_info *) *dst;
707be1ff3   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
942
  	rcu_read_lock_bh();
2647a9b07   Martin KaFai Lau   ipv6: Remove exte...
943
944
  	n = __ipv6_neigh_lookup_noref(rt->dst.dev,
  				      rt6_nexthop(rt, &fl6->daddr));
707be1ff3   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
945
946
947
948
  	err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;
  	rcu_read_unlock_bh();
  
  	if (err) {
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
949
  		struct inet6_ifaddr *ifp;
4c9483b2f   David S. Miller   ipv6: Convert to ...
950
  		struct flowi6 fl_gw6;
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
951
  		int redirect;
4c9483b2f   David S. Miller   ipv6: Convert to ...
952
  		ifp = ipv6_get_ifaddr(net, &fl6->saddr,
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
953
954
955
956
957
958
959
960
961
962
963
964
  				      (*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 ...
965
966
967
  			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...
968
969
  			err = (*dst)->error;
  			if (err)
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
970
  				goto out_err_release;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
971
  		}
e550dfb0c   Neil Horman   ipv6: Fix OOPS in...
972
  	}
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
973
  #endif
ec5e3b0a1   Jonathan T. Leighton   ipv6: Inhibit IPv...
974
  	if (ipv6_addr_v4mapped(&fl6->saddr) &&
00ea1ceeb   Willem de Bruijn   ipv6: release dst...
975
976
977
978
  	    !(ipv6_addr_v4mapped(&fl6->daddr) || ipv6_addr_any(&fl6->daddr))) {
  		err = -EAFNOSUPPORT;
  		goto out_err_release;
  	}
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
979

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
983
984
  	return 0;
  
  out_err_release:
  	dst_release(*dst);
  	*dst = NULL;
8a966fc01   David Ahern   net: ipv6: Remove...
985

0d240e781   David Ahern   net: vrf: Impleme...
986
987
  	if (err == -ENETUNREACH)
  		IP6_INC_STATS(net, NULL, IPSTATS_MIB_OUTNOROUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
  	return err;
  }
34a0b3cdc   Adrian Bunk   [IPV6]: make two ...
990

497c615ab   Herbert Xu   [IPV6]: Audit all...
991
992
993
994
  /**
   *	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 ...
995
   *	@fl6: flow to lookup
497c615ab   Herbert Xu   [IPV6]: Audit all...
996
997
998
999
1000
   *
   *	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...
1001
1002
  int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
  		   struct flowi6 *fl6)
497c615ab   Herbert Xu   [IPV6]: Audit all...
1003
1004
  {
  	*dst = NULL;
343d60aad   Roopa Prabhu   ipv6: change ipv6...
1005
  	return ip6_dst_lookup_tail(net, sk, dst, fl6);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1006
  }
3cf3dc6c2   Arnaldo Carvalho de Melo   [IPV6]: Export so...
1007
  EXPORT_SYMBOL_GPL(ip6_dst_lookup);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1008
  /**
68d0c6d34   David S. Miller   ipv6: Consolidate...
1009
1010
   *	ip6_dst_lookup_flow - perform route lookup on flow with ipsec
   *	@sk: socket which provides route info
4c9483b2f   David S. Miller   ipv6: Convert to ...
1011
   *	@fl6: flow to lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
1012
   *	@final_dst: final destination address for ipsec lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
1013
1014
1015
1016
1017
1018
   *
   *	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...
1019
  struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
0e0d44ab4   Steffen Klassert   net: Remove FLOWI...
1020
  				      const struct in6_addr *final_dst)
68d0c6d34   David S. Miller   ipv6: Consolidate...
1021
1022
1023
  {
  	struct dst_entry *dst = NULL;
  	int err;
343d60aad   Roopa Prabhu   ipv6: change ipv6...
1024
  	err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1025
1026
1027
  	if (err)
  		return ERR_PTR(err);
  	if (final_dst)
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1028
  		fl6->daddr = *final_dst;
2774c131b   David S. Miller   xfrm: Handle blac...
1029

f92ee6198   Steffen Klassert   xfrm: Generate bl...
1030
  	return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
68d0c6d34   David S. Miller   ipv6: Consolidate...
1031
1032
1033
1034
1035
  }
  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...
1036
   *	@sk: socket which provides the dst cache and route info
4c9483b2f   David S. Miller   ipv6: Convert to ...
1037
   *	@fl6: flow to lookup
68d0c6d34   David S. Miller   ipv6: Consolidate...
1038
   *	@final_dst: final destination address for ipsec lookup
497c615ab   Herbert Xu   [IPV6]: Audit all...
1039
1040
1041
1042
1043
1044
   *
   *	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...
1045
1046
   *	It returns a valid dst pointer on success, or a pointer encoded
   *	error code.
497c615ab   Herbert Xu   [IPV6]: Audit all...
1047
   */
4c9483b2f   David S. Miller   ipv6: Convert to ...
1048
  struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
0e0d44ab4   Steffen Klassert   net: Remove FLOWI...
1049
  					 const struct in6_addr *final_dst)
497c615ab   Herbert Xu   [IPV6]: Audit all...
1050
  {
68d0c6d34   David S. Miller   ipv6: Consolidate...
1051
  	struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
497c615ab   Herbert Xu   [IPV6]: Audit all...
1052

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

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

0178b695f   Herbert Xu   ipv6: Copy cork o...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  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_...
1072
  static void ip6_append_data_mtu(unsigned int *mtu,
0c1833797   Gao feng   ipv6: fix incorre...
1073
1074
1075
  				int *maxfraglen,
  				unsigned int fragheaderlen,
  				struct sk_buff *skb,
75a493e60   Hannes Frederic Sowa   ipv6: ip6_append_...
1076
  				struct rt6_info *rt,
e367c2d03   lucien   ipv6: ip6_append_...
1077
  				unsigned int orig_mtu)
0c1833797   Gao feng   ipv6: fix incorre...
1078
1079
  {
  	if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
63159f29b   Ian Morris   ipv6: coding styl...
1080
  		if (!skb) {
0c1833797   Gao feng   ipv6: fix incorre...
1081
  			/* first fragment, reserve header_len */
e367c2d03   lucien   ipv6: ip6_append_...
1082
  			*mtu = orig_mtu - rt->dst.header_len;
0c1833797   Gao feng   ipv6: fix incorre...
1083
1084
1085
1086
1087
1088
  
  		} else {
  			/*
  			 * this fragment is not first, the headers
  			 * space is regarded as data space.
  			 */
e367c2d03   lucien   ipv6: ip6_append_...
1089
  			*mtu = orig_mtu;
0c1833797   Gao feng   ipv6: fix incorre...
1090
1091
1092
1093
1094
  		}
  		*maxfraglen = ((*mtu - fragheaderlen) & ~7)
  			      + fragheaderlen - sizeof(struct frag_hdr);
  	}
  }
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1095
  static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
26879da58   Wei Wang   ipv6: add new str...
1096
  			  struct inet6_cork *v6_cork, struct ipcm6_cookie *ipc6,
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1097
1098
1099
1100
  			  struct rt6_info *rt, struct flowi6 *fl6)
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	unsigned int mtu;
26879da58   Wei Wang   ipv6: add new str...
1101
  	struct ipv6_txoptions *opt = ipc6->opt;
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1102
1103
1104
1105
1106
1107
1108
  
  	/*
  	 * setup for corking
  	 */
  	if (opt) {
  		if (WARN_ON(v6_cork->opt))
  			return -EINVAL;
864e2a1f8   Eric Dumazet   ipv6: flowlabel: ...
1109
  		v6_cork->opt = kzalloc(sizeof(*opt), sk->sk_allocation);
63159f29b   Ian Morris   ipv6: coding styl...
1110
  		if (unlikely(!v6_cork->opt))
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1111
  			return -ENOBUFS;
864e2a1f8   Eric Dumazet   ipv6: flowlabel: ...
1112
  		v6_cork->opt->tot_len = sizeof(*opt);
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  		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...
1141
1142
  	v6_cork->hop_limit = ipc6->hlimit;
  	v6_cork->tclass = ipc6->tclass;
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1143
1144
  	if (rt->dst.flags & DST_XFRM_TUNNEL)
  		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
8278804e0   Mike Maloney   ipv6: fix udpv6 s...
1145
  		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1146
1147
  	else
  		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
8278804e0   Mike Maloney   ipv6: fix udpv6 s...
1148
  		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(rt->dst.path);
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1149
1150
1151
1152
  	if (np->frag_size < mtu) {
  		if (np->frag_size)
  			mtu = np->frag_size;
  	}
8278804e0   Mike Maloney   ipv6: fix udpv6 s...
1153
1154
  	if (mtu < IPV6_MIN_MTU)
  		return -EINVAL;
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1155
1156
1157
1158
1159
1160
1161
  	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...
1162
1163
1164
1165
1166
1167
1168
1169
1170
  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...
1171
  			     unsigned int flags, struct ipcm6_cookie *ipc6,
c14ac9451   Soheil Hassas Yeganeh   sock: enable time...
1172
  			     const struct sockcm_cookie *sockc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  {
0c1833797   Gao feng   ipv6: fix incorre...
1174
  	struct sk_buff *skb, *skb_prev = NULL;
52f0a5ff6   Paolo Abeni   ipv6: the entire ...
1175
  	unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1176
1177
  	int exthdrlen = 0;
  	int dst_exthdrlen = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  	int hh_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
1180
1181
  	int copy;
  	int err;
  	int offset = 0;
a693e6989   Anders Berggren   net: TX timestamp...
1182
  	__u8 tx_flags = 0;
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1183
  	u32 tskey = 0;
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1184
1185
  	struct rt6_info *rt = (struct rt6_info *)cork->dst;
  	struct ipv6_txoptions *opt = v6_cork->opt;
32dce968d   Vlad Yasevich   ipv6: Allow for p...
1186
  	int csummode = CHECKSUM_NONE;
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1187
  	unsigned int maxnonfragsize, headersize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188

0bbe84a67   Vlad Yasevich   ipv6: Append send...
1189
1190
1191
  	skb = skb_peek_tail(queue);
  	if (!skb) {
  		exthdrlen = opt ? opt->opt_flen : 0;
7efdba5bd   Romain KUNTZ   ipv6: fix header ...
1192
  		dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  	}
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1194

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

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

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

682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1205
1206
1207
1208
1209
  	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;
52f0a5ff6   Paolo Abeni   ipv6: the entire ...
1210
1211
1212
1213
1214
  	/* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
  	 * the first fragment
  	 */
  	if (headersize + transhdrlen > mtu)
  		goto emsgsize;
26879da58   Wei Wang   ipv6: add new str...
1215
  	if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1216
1217
1218
1219
1220
1221
  	    (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...
1222

682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1223
1224
1225
1226
  	if (ip6_sk_ignore_df(sk))
  		maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
  	else
  		maxnonfragsize = mtu;
4df98e76c   Hannes Frederic Sowa   ipv6: pmtudisc se...
1227

682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1228
  	if (cork->length + length > maxnonfragsize - headersize) {
4df98e76c   Hannes Frederic Sowa   ipv6: pmtudisc se...
1229
  emsgsize:
52f0a5ff6   Paolo Abeni   ipv6: the entire ...
1230
1231
  		pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0);
  		ipv6_local_error(sk, EMSGSIZE, fl6, pmtu);
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1232
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  	}
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1234
1235
1236
1237
1238
  	/* 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) &&
2b89ed65a   Vlad Yasevich   ipv6: Paritially ...
1239
  	    length <= mtu - headersize &&
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1240
  	    !(flags & MSG_MORE) &&
c8cd0989b   Tom Herbert   net: Eliminate NE...
1241
  	    rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
682b1a9d3   Hannes Frederic Sowa   ipv6: no CHECKSUM...
1242
  		csummode = CHECKSUM_PARTIAL;
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1243
  	if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) {
c14ac9451   Soheil Hassas Yeganeh   sock: enable time...
1244
  		sock_tx_timestamp(sk, sockc->tsflags, &tx_flags);
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1245
1246
1247
1248
  		if (tx_flags & SKBTX_ANY_SW_TSTAMP &&
  		    sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
  			tskey = sk->sk_tskey++;
  	}
a693e6989   Anders Berggren   net: TX timestamp...
1249

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
1255
1256
  	/*
  	 * 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...
1257
  	 * of the buffer to the new fragment when we split
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
  	 * the message.
  	 *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1260
  	 * FIXME: It may be fragmented into multiple chunks
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
1262
  	 *        at once if non-fragmentable extension headers
  	 *        are too large.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1263
  	 * --yoshfuji
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
  	 */
2811ebac2   Hannes Frederic Sowa   ipv6: udp packets...
1265
  	cork->length += length;
2811ebac2   Hannes Frederic Sowa   ipv6: udp packets...
1266
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
1270
  		goto alloc_new_skb;
  
  	while (length > 0) {
  		/* Check if the remaining data fits into current packet. */
bdc712b4c   David S. Miller   inet: Decrease ov...
1271
  		copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
1274
1275
1276
1277
1278
1279
1280
  		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
1281
  alloc_new_skb:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
  			/* There's no room in the current skb */
0c1833797   Gao feng   ipv6: fix incorre...
1283
1284
  			if (skb)
  				fraggap = skb->len - maxfraglen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
  			else
  				fraggap = 0;
0c1833797   Gao feng   ipv6: fix incorre...
1287
  			/* update mtu and maxfraglen if necessary */
63159f29b   Ian Morris   ipv6: coding styl...
1288
  			if (!skb || !skb_prev)
0c1833797   Gao feng   ipv6: fix incorre...
1289
  				ip6_append_data_mtu(&mtu, &maxfraglen,
75a493e60   Hannes Frederic Sowa   ipv6: ip6_append_...
1290
  						    fragheaderlen, skb, rt,
e367c2d03   lucien   ipv6: ip6_append_...
1291
  						    orig_mtu);
0c1833797   Gao feng   ipv6: fix incorre...
1292
1293
  
  			skb_prev = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
1298
1299
  
  			/*
  			 * If remaining data exceeds the mtu,
  			 * we know we need more fragment(s).
  			 */
  			datalen = length + fraggap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300

0c1833797   Gao feng   ipv6: fix incorre...
1301
1302
  			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
1303
  			if ((flags & MSG_MORE) &&
d8d1f30b9   Changli Gao   net-next: remove ...
1304
  			    !(rt->dst.dev->features&NETIF_F_SG))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
1306
1307
  				alloclen = mtu;
  			else
  				alloclen = datalen + fragheaderlen;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1308
  			alloclen += dst_exthdrlen;
0c1833797   Gao feng   ipv6: fix incorre...
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
  			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
1319
1320
1321
  
  			/*
  			 * We just reserve space for fragment header.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1322
  			 * Note: this may be overallocation if the message
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
1325
  			 * (without MSG_MORE) fits into the MTU.
  			 */
  			alloclen += sizeof(struct frag_hdr);
232cd35d0   Eric Dumazet   ipv6: fix out of ...
1326
1327
1328
1329
1330
  			copy = datalen - transhdrlen - fraggap;
  			if (copy < 0) {
  				err = -EINVAL;
  				goto error;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
1332
1333
1334
1335
1336
  			if (transhdrlen) {
  				skb = sock_alloc_send_skb(sk,
  						alloclen + hh_len,
  						(flags & MSG_DONTWAIT), &err);
  			} else {
  				skb = NULL;
14afee4b6   Reshetova, Elena   net: convert sock...
1337
  				if (refcount_read(&sk->sk_wmem_alloc) <=
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
1340
1341
  				    2 * sk->sk_sndbuf)
  					skb = sock_wmalloc(sk,
  							   alloclen + hh_len, 1,
  							   sk->sk_allocation);
63159f29b   Ian Morris   ipv6: coding styl...
1342
  				if (unlikely(!skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
1344
  					err = -ENOBUFS;
  			}
63159f29b   Ian Morris   ipv6: coding styl...
1345
  			if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
1348
1349
  				goto error;
  			/*
  			 *	Fill in the control structures
  			 */
9c9c9ad5f   Hannes Frederic Sowa   ipv6: set skb->pr...
1350
  			skb->protocol = htons(ETH_P_IPV6);
32dce968d   Vlad Yasevich   ipv6: Allow for p...
1351
  			skb->ip_summed = csummode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
  			skb->csum = 0;
1f85851e1   Gao feng   ipv6: fix incorre...
1353
1354
1355
  			/* 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
1356

11878b40e   Willem de Bruijn   net-timestamp: SO...
1357
1358
1359
  			/* Only the initial fragment is time stamped */
  			skb_shinfo(skb)->tx_flags = tx_flags;
  			tx_flags = 0;
09c2d251b   Willem de Bruijn   net-timestamp: ad...
1360
1361
  			skb_shinfo(skb)->tskey = tskey;
  			tskey = 0;
a693e6989   Anders Berggren   net: TX timestamp...
1362

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
1364
1365
  			/*
  			 *	Find where to start putting bytes
  			 */
1f85851e1   Gao feng   ipv6: fix incorre...
1366
1367
1368
  			data = skb_put(skb, fraglen);
  			skb_set_network_header(skb, exthdrlen);
  			data += fragheaderlen;
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1369
1370
  			skb->transport_header = (skb->network_header +
  						 fragheaderlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
1375
1376
1377
  			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_...
1378
  				pskb_trim_unique(skb_prev, maxfraglen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379
  			}
232cd35d0   Eric Dumazet   ipv6: fix out of ...
1380
1381
1382
  			if (copy > 0 &&
  			    getfrag(from, data + transhdrlen, offset,
  				    copy, fraggap, skb) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
1384
1385
1386
1387
1388
1389
1390
1391
  				err = -EFAULT;
  				kfree_skb(skb);
  				goto error;
  			}
  
  			offset += copy;
  			length -= datalen - fraggap;
  			transhdrlen = 0;
  			exthdrlen = 0;
299b07676   Steffen Klassert   ipv6: Fix IPsec s...
1392
  			dst_exthdrlen = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393

0dec879f6   Julian Anastasov   net: use dst_conf...
1394
1395
  			if ((flags & MSG_CONFIRM) && !skb_prev)
  				skb_set_dst_pending_confirm(skb, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
1398
  			/*
  			 * Put the packet on the pending queue
  			 */
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1399
  			__skb_queue_tail(queue, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
1401
1402
1403
1404
  			continue;
  		}
  
  		if (copy > length)
  			copy = length;
c02756173   Willem de Bruijn   net: test tailroo...
1405
1406
  		if (!(rt->dst.dev->features&NETIF_F_SG) &&
  		    skb_tailroom(skb) >= copy) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
  			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
1418

5640f7685   Eric Dumazet   net: use a per ta...
1419
1420
  			err = -ENOMEM;
  			if (!sk_page_frag_refill(sk, pfrag))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
  				goto error;
5640f7685   Eric Dumazet   net: use a per ta...
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
  
  			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
1433
  			}
5640f7685   Eric Dumazet   net: use a per ta...
1434
  			copy = min_t(int, copy, pfrag->size - pfrag->offset);
9e903e085   Eric Dumazet   net: add skb frag...
1435
  			if (getfrag(from,
5640f7685   Eric Dumazet   net: use a per ta...
1436
1437
1438
1439
1440
1441
  				    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
1442
1443
  			skb->len += copy;
  			skb->data_len += copy;
f945fa7ad   Herbert Xu   [INET]: Fix trues...
1444
  			skb->truesize += copy;
14afee4b6   Reshetova, Elena   net: convert sock...
1445
  			refcount_add(copy, &sk->sk_wmem_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
1449
  		}
  		offset += copy;
  		length -= copy;
  	}
5640f7685   Eric Dumazet   net: use a per ta...
1450

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
  	return 0;
5640f7685   Eric Dumazet   net: use a per ta...
1452
1453
1454
  
  error_efault:
  	err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
  error:
bdc712b4c   David S. Miller   inet: Decrease ov...
1456
  	cork->length -= length;
3bd653c84   Denis V. Lunev   netns: add net pa...
1457
  	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
1459
  	return err;
  }
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1460
1461
1462
1463
  
  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...
1464
1465
1466
  		    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...
1467
  		    const struct sockcm_cookie *sockc)
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
  {
  	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...
1480
1481
  		err = ip6_setup_cork(sk, &inet->cork, &np->cork,
  				     ipc6, rt, fl6);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1482
1483
  		if (err)
  			return err;
26879da58   Wei Wang   ipv6: add new str...
1484
  		exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1485
1486
1487
1488
1489
1490
1491
1492
1493
  		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...
1494
  				 from, length, transhdrlen, flags, ipc6, sockc);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1495
  }
a495f8364   Chris Elston   ipv6: Export ipv6...
1496
  EXPORT_SYMBOL_GPL(ip6_append_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497

366e41d97   Vlad Yasevich   ipv6: pull cork i...
1498
1499
  static void ip6_cork_release(struct inet_cork_full *cork,
  			     struct inet6_cork *v6_cork)
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1500
  {
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1501
1502
1503
1504
1505
1506
1507
  	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...
1508
  	}
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1509
1510
1511
1512
  	if (cork->base.dst) {
  		dst_release(cork->base.dst);
  		cork->base.dst = NULL;
  		cork->base.flags &= ~IPCORK_ALLFRAG;
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1513
  	}
366e41d97   Vlad Yasevich   ipv6: pull cork i...
1514
  	memset(&cork->fl, 0, sizeof(cork->fl));
bf138862b   Pavel Emelyanov   [IPV6]: Consolida...
1515
  }
6422398c2   Vlad Yasevich   ipv6: introduce i...
1516
1517
1518
1519
  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
1520
1521
1522
1523
  {
  	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
1524
  	struct ipv6_pinfo *np = inet6_sk(sk);
3bd653c84   Denis V. Lunev   netns: add net pa...
1525
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526
  	struct ipv6hdr *hdr;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1527
1528
1529
  	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 ...
1530
  	unsigned char proto = fl6->flowi6_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531

6422398c2   Vlad Yasevich   ipv6: introduce i...
1532
  	skb = __skb_dequeue(queue);
63159f29b   Ian Morris   ipv6: coding styl...
1533
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
1535
1536
1537
  		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...
1538
  	if (skb->data < skb_network_header(skb))
bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1539
  		__skb_pull(skb, skb_network_offset(skb));
6422398c2   Vlad Yasevich   ipv6: introduce i...
1540
  	while ((tmp_skb = __skb_dequeue(queue)) != NULL) {
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1541
  		__skb_pull(tmp_skb, skb_network_header_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542
1543
1544
1545
  		*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
1546
  		skb->truesize += tmp_skb->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
1548
  		tmp_skb->destructor = NULL;
  		tmp_skb->sk = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
  	}
28a89453b   Herbert Xu   [IPV6]: Fix IPsec...
1550
  	/* Allow local fragmentation. */
60ff74673   WANG Cong   net: rename local...
1551
  	skb->ignore_df = ip6_sk_ignore_df(sk);
28a89453b   Herbert Xu   [IPV6]: Fix IPsec...
1552

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1553
  	*final_dst = fl6->daddr;
cfe1fc775   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1554
  	__skb_pull(skb, skb_network_header_len(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
1556
1557
  	if (opt && opt->opt_flen)
  		ipv6_push_frag_opts(skb, opt, &proto);
  	if (opt && opt->opt_nflen)
613fa3ca9   David Lebrun   ipv6: add source ...
1558
  		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst, &fl6->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559

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

6422398c2   Vlad Yasevich   ipv6: introduce i...
1564
  	ip6_flow_hdr(hdr, v6_cork->tclass,
cb1ce2ef3   Tom Herbert   ipv6: Implement a...
1565
  		     ip6_make_flowlabel(net, skb, fl6->flowlabel,
6d0317869   Shaohua Li   net: reevalulate ...
1566
  					ip6_autoflowlabel(net, np), fl6));
6422398c2   Vlad Yasevich   ipv6: introduce i...
1567
  	hdr->hop_limit = v6_cork->hop_limit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
  	hdr->nexthdr = proto;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1569
1570
  	hdr->saddr = fl6->saddr;
  	hdr->daddr = *final_dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571

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

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

43a43b604   Hannes Frederic Sowa   ipv6: some ipv6 s...
1580
1581
  		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...
1582
  	}
6422398c2   Vlad Yasevich   ipv6: introduce i...
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
  	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 ...
1593
  	err = ip6_local_out(net, skb->sk, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
1595
  	if (err) {
  		if (err > 0)
6ce9e7b5f   Eric Dumazet   ip: Report qdisc ...
1596
  			err = net_xmit_errno(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  		if (err)
6422398c2   Vlad Yasevich   ipv6: introduce i...
1598
1599
  			IP6_INC_STATS(net, rt->rt6i_idev,
  				      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  	return err;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
  }
  
  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
1613
  }
a495f8364   Chris Elston   ipv6: Export ipv6...
1614
  EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615

0bbe84a67   Vlad Yasevich   ipv6: Append send...
1616
  static void __ip6_flush_pending_frames(struct sock *sk,
6422398c2   Vlad Yasevich   ipv6: introduce i...
1617
1618
1619
  				       struct sk_buff_head *queue,
  				       struct inet_cork_full *cork,
  				       struct inet6_cork *v6_cork)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621
  	struct sk_buff *skb;
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1622
  	while ((skb = __skb_dequeue_tail(queue)) != NULL) {
adf30907d   Eric Dumazet   net: skb->dst acc...
1623
1624
  		if (skb_dst(skb))
  			IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
e1f52208b   YOSHIFUJI Hideaki   [IPv6]: Fix NULL ...
1625
  				      IPSTATS_MIB_OUTDISCARDS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
1627
  		kfree_skb(skb);
  	}
6422398c2   Vlad Yasevich   ipv6: introduce i...
1628
  	ip6_cork_release(cork, v6_cork);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
  }
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1630
1631
1632
  
  void ip6_flush_pending_frames(struct sock *sk)
  {
6422398c2   Vlad Yasevich   ipv6: introduce i...
1633
1634
  	__ip6_flush_pending_frames(sk, &sk->sk_write_queue,
  				   &inet_sk(sk)->cork, &inet6_sk(sk)->cork);
0bbe84a67   Vlad Yasevich   ipv6: Append send...
1635
  }
a495f8364   Chris Elston   ipv6: Export ipv6...
1636
  EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1637
1638
1639
1640
1641
  
  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...
1642
  			     struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
6422398c2   Vlad Yasevich   ipv6: introduce i...
1643
  			     struct rt6_info *rt, unsigned int flags,
26879da58   Wei Wang   ipv6: add new str...
1644
  			     const struct sockcm_cookie *sockc)
6422398c2   Vlad Yasevich   ipv6: introduce i...
1645
1646
1647
1648
  {
  	struct inet_cork_full cork;
  	struct inet6_cork v6_cork;
  	struct sk_buff_head queue;
26879da58   Wei Wang   ipv6: add new str...
1649
  	int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
  	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;
347217078   Eric Dumazet   ipv6: ip6_make_sk...
1660
  	cork.base.dst = NULL;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1661
  	v6_cork.opt = NULL;
26879da58   Wei Wang   ipv6: add new str...
1662
  	err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6);
d3ccc74c8   Eric Dumazet   ipv6: fix possibl...
1663
1664
  	if (err) {
  		ip6_cork_release(&cork, &v6_cork);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1665
  		return ERR_PTR(err);
d3ccc74c8   Eric Dumazet   ipv6: fix possibl...
1666
  	}
26879da58   Wei Wang   ipv6: add new str...
1667
1668
  	if (ipc6->dontfrag < 0)
  		ipc6->dontfrag = inet6_sk(sk)->dontfrag;
6422398c2   Vlad Yasevich   ipv6: introduce i...
1669
1670
1671
1672
  
  	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...
1673
  				flags, ipc6, sockc);
6422398c2   Vlad Yasevich   ipv6: introduce i...
1674
1675
1676
1677
1678
1679
1680
  	if (err) {
  		__ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork);
  		return ERR_PTR(err);
  	}
  
  	return __ip6_make_skb(sk, &queue, &cork, &v6_cork);
  }