Blame view
net/ipv6/ip6_output.c
41.1 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 |
/* * IPv6 output functions |
1ab1457c4 [NET] IPV6: Fix w... |
3 |
* Linux INET6 implementation |
1da177e4c Linux-2.6.12-rc2 |
4 5 |
* * Authors: |
1ab1457c4 [NET] IPV6: Fix w... |
6 |
* Pedro Roque <roque@di.fc.ul.pt> |
1da177e4c Linux-2.6.12-rc2 |
7 |
* |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
* Based on linux/net/ipv4/ip_output.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Changes: * A.N.Kuznetsov : airthmetics in fragmentation. * extension headers are implemented. * route changes now work. * ip6_forward does not confuse sniffers. * etc. * * H. von Brand : Added missing #include <linux/string.h> * Imran Patel : frag id should be in NBO * Kazunori MIYAZAWA @USAGI * : add ip6_append_data and related functions * for datagram xmit */ |
1da177e4c Linux-2.6.12-rc2 |
28 |
#include <linux/errno.h> |
ef76bc23e [IPV6]: Add ip6_l... |
29 |
#include <linux/kernel.h> |
1da177e4c 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 [IPSEC] xfrm: Abs... |
38 |
#include <linux/module.h> |
5a0e3ad6a include cleanup: ... |
39 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include <linux/netfilter.h> #include <linux/netfilter_ipv6.h> #include <net/sock.h> #include <net/snmp.h> #include <net/ipv6.h> #include <net/ndisc.h> #include <net/protocol.h> #include <net/ip6_route.h> #include <net/addrconf.h> #include <net/rawv6.h> #include <net/icmp.h> #include <net/xfrm.h> #include <net/checksum.h> |
7bc570c8b [IPV6] MROUTE: Su... |
56 |
#include <linux/mroute6.h> |
1da177e4c Linux-2.6.12-rc2 |
57 |
|
ad0081e43 ipv6: Fragment lo... |
58 |
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); |
1da177e4c Linux-2.6.12-rc2 |
59 |
|
ef76bc23e [IPV6]: Add ip6_l... |
60 61 62 63 64 65 66 67 |
int __ip6_local_out(struct sk_buff *skb) { int len; len = skb->len - sizeof(struct ipv6hdr); if (len > IPV6_MAXPLEN) len = 0; ipv6_hdr(skb)->payload_len = htons(len); |
b2e0b385d netfilter: ipv6: ... |
68 69 |
return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, dst_output); |
ef76bc23e [IPV6]: Add ip6_l... |
70 71 72 73 74 75 76 77 78 79 80 81 82 |
} int ip6_local_out(struct sk_buff *skb) { int err; err = __ip6_local_out(skb); if (likely(err == 1)) err = dst_output(skb); return err; } EXPORT_SYMBOL_GPL(ip6_local_out); |
1da177e4c Linux-2.6.12-rc2 |
83 84 85 |
/* dev_loopback_xmit for use with netfilter. */ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) { |
459a98ed8 [SK_BUFF]: Introd... |
86 |
skb_reset_mac_header(newskb); |
bbe735e42 [SK_BUFF]: Introd... |
87 |
__skb_pull(newskb, skb_network_offset(newskb)); |
1da177e4c Linux-2.6.12-rc2 |
88 89 |
newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; |
adf30907d net: skb->dst acc... |
90 |
WARN_ON(!skb_dst(newskb)); |
1da177e4c Linux-2.6.12-rc2 |
91 |
|
e30b38c29 ip: Fix ip_dev_lo... |
92 |
netif_rx_ni(newskb); |
1da177e4c Linux-2.6.12-rc2 |
93 94 |
return 0; } |
9e5084905 netfilter: ipv6: ... |
95 |
static int ip6_finish_output2(struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
96 |
{ |
adf30907d net: skb->dst acc... |
97 |
struct dst_entry *dst = skb_dst(skb); |
1da177e4c Linux-2.6.12-rc2 |
98 |
struct net_device *dev = dst->dev; |
f6b72b621 net: Embed hh_cac... |
99 |
struct neighbour *neigh; |
1da177e4c Linux-2.6.12-rc2 |
100 101 102 |
skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; |
0660e03f6 [SK_BUFF]: Introd... |
103 |
if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { |
adf30907d net: skb->dst acc... |
104 |
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
1da177e4c Linux-2.6.12-rc2 |
105 |
|
7ad6848c7 ip: fix mc_loop c... |
106 |
if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && |
d1db275dd ipv6: ip6mr: supp... |
107 |
((mroute6_socket(dev_net(dev), skb) && |
bd91b8bf3 netns: ip6mr: all... |
108 |
!(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || |
7bc570c8b [IPV6] MROUTE: Su... |
109 110 |
ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr))) { |
1da177e4c Linux-2.6.12-rc2 |
111 112 113 114 115 116 |
struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); /* Do not check for IFF_ALLMULTI; multicast routing is not supported in any case. */ if (newskb) |
b2e0b385d netfilter: ipv6: ... |
117 118 |
NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, newskb, NULL, newskb->dev, |
1da177e4c Linux-2.6.12-rc2 |
119 |
ip6_dev_loopback_xmit); |
0660e03f6 [SK_BUFF]: Introd... |
120 |
if (ipv6_hdr(skb)->hop_limit == 0) { |
3bd653c84 netns: add net pa... |
121 122 |
IP6_INC_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
123 124 125 126 |
kfree_skb(skb); return 0; } } |
edf391ff1 snmp: add missing... |
127 128 |
IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, skb->len); |
1da177e4c Linux-2.6.12-rc2 |
129 |
} |
f2c31e32b net: fix NULL der... |
130 |
rcu_read_lock(); |
272174550 net: Rename dst_g... |
131 |
neigh = dst_get_neighbour_noref(dst); |
f2c31e32b net: fix NULL der... |
132 133 |
if (neigh) { int res = neigh_output(neigh, skb); |
05e3aa094 net: Create and u... |
134 |
|
f2c31e32b net: fix NULL der... |
135 136 137 138 |
rcu_read_unlock(); return res; } rcu_read_unlock(); |
9e5084905 netfilter: ipv6: ... |
139 140 141 142 |
IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
143 |
} |
9e5084905 netfilter: ipv6: ... |
144 145 146 147 148 149 150 151 |
static int ip6_finish_output(struct sk_buff *skb) { if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || dst_allfrag(skb_dst(skb))) return ip6_fragment(skb, ip6_finish_output2); else return ip6_finish_output2(skb); } |
1da177e4c Linux-2.6.12-rc2 |
152 153 |
int ip6_output(struct sk_buff *skb) { |
9e5084905 netfilter: ipv6: ... |
154 |
struct net_device *dev = skb_dst(skb)->dev; |
adf30907d net: skb->dst acc... |
155 |
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
778d80be5 ipv6: Add disable... |
156 |
if (unlikely(idev->cnf.disable_ipv6)) { |
9e5084905 netfilter: ipv6: ... |
157 |
IP6_INC_STATS(dev_net(dev), idev, |
3bd653c84 netns: add net pa... |
158 |
IPSTATS_MIB_OUTDISCARDS); |
778d80be5 ipv6: Add disable... |
159 160 161 |
kfree_skb(skb); return 0; } |
9c6eb28ac netfilter: ipv6: ... |
162 163 164 |
return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev, ip6_finish_output, !(IP6CB(skb)->flags & IP6SKB_REROUTED)); |
1da177e4c Linux-2.6.12-rc2 |
165 |
} |
1da177e4c Linux-2.6.12-rc2 |
166 |
/* |
b5d439982 ipv6: fix the com... |
167 |
* xmit an sk_buff (used by TCP, SCTP and DCCP) |
1da177e4c Linux-2.6.12-rc2 |
168 |
*/ |
4c9483b2f ipv6: Convert to ... |
169 |
int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, |
b903d324b ipv6: tcp: fix TC... |
170 |
struct ipv6_txoptions *opt, int tclass) |
1da177e4c Linux-2.6.12-rc2 |
171 |
{ |
3bd653c84 netns: add net pa... |
172 |
struct net *net = sock_net(sk); |
b30bd282c [IPV6]: ip6_xmit:... |
173 |
struct ipv6_pinfo *np = inet6_sk(sk); |
4c9483b2f ipv6: Convert to ... |
174 |
struct in6_addr *first_hop = &fl6->daddr; |
adf30907d net: skb->dst acc... |
175 |
struct dst_entry *dst = skb_dst(skb); |
1da177e4c Linux-2.6.12-rc2 |
176 |
struct ipv6hdr *hdr; |
4c9483b2f ipv6: Convert to ... |
177 |
u8 proto = fl6->flowi6_proto; |
1da177e4c Linux-2.6.12-rc2 |
178 |
int seg_len = skb->len; |
e651f03af inet6: Conversion... |
179 |
int hlimit = -1; |
1da177e4c Linux-2.6.12-rc2 |
180 181 182 |
u32 mtu; if (opt) { |
c2636b4d9 [NET]: Treat the ... |
183 |
unsigned int head_room; |
1da177e4c Linux-2.6.12-rc2 |
184 185 186 187 188 189 190 191 192 193 |
/* First: exthdrs may take lots of space (~8K for now) MAX_HEADER is not enough. */ head_room = opt->opt_nflen + opt->opt_flen; seg_len += head_room; head_room += sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev); if (skb_headroom(skb) < head_room) { struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); |
a11d206d0 [IPV6]: Per-inter... |
194 |
if (skb2 == NULL) { |
adf30907d net: skb->dst acc... |
195 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
a11d206d0 [IPV6]: Per-inter... |
196 197 |
IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); |
1da177e4c Linux-2.6.12-rc2 |
198 199 |
return -ENOBUFS; } |
a11d206d0 [IPV6]: Per-inter... |
200 201 |
kfree_skb(skb); skb = skb2; |
83d7eb297 ipv6: cleanup: re... |
202 |
skb_set_owner_w(skb, sk); |
1da177e4c Linux-2.6.12-rc2 |
203 204 205 206 207 208 |
} if (opt->opt_flen) ipv6_push_frag_opts(skb, opt, &proto); if (opt->opt_nflen) ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop); } |
e2d1bca7e [SK_BUFF]: Use sk... |
209 210 |
skb_push(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); |
0660e03f6 [SK_BUFF]: Introd... |
211 |
hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
212 213 214 215 |
/* * Fill in the IPv6 header */ |
b903d324b ipv6: tcp: fix TC... |
216 |
if (np) |
1da177e4c Linux-2.6.12-rc2 |
217 218 |
hlimit = np->hop_limit; if (hlimit < 0) |
6b75d0908 [IPV6]: Optimize ... |
219 |
hlimit = ip6_dst_hoplimit(dst); |
1da177e4c Linux-2.6.12-rc2 |
220 |
|
4c9483b2f ipv6: Convert to ... |
221 |
*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel; |
41a1f8ea4 [IPV6]: Support I... |
222 |
|
1da177e4c Linux-2.6.12-rc2 |
223 224 225 |
hdr->payload_len = htons(seg_len); hdr->nexthdr = proto; hdr->hop_limit = hlimit; |
4e3fd7a06 net: remove ipv6_... |
226 227 |
hdr->saddr = fl6->saddr; hdr->daddr = *first_hop; |
1da177e4c Linux-2.6.12-rc2 |
228 |
|
a2c2064f7 [IPV6]: Set skb->... |
229 |
skb->priority = sk->sk_priority; |
4a19ec580 [NET]: Introducin... |
230 |
skb->mark = sk->sk_mark; |
a2c2064f7 [IPV6]: Set skb->... |
231 |
|
1da177e4c Linux-2.6.12-rc2 |
232 |
mtu = dst_mtu(dst); |
283d07ac2 ipv6: Do not drop... |
233 |
if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { |
adf30907d net: skb->dst acc... |
234 |
IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), |
edf391ff1 snmp: add missing... |
235 |
IPSTATS_MIB_OUT, skb->len); |
b2e0b385d netfilter: ipv6: ... |
236 237 |
return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, dst_output); |
1da177e4c Linux-2.6.12-rc2 |
238 239 240 241 242 243 |
} if (net_ratelimit()) printk(KERN_DEBUG "IPv6: sending pkt_too_big to self "); skb->dev = dst->dev; |
3ffe533c8 ipv6: drop unused... |
244 |
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
adf30907d net: skb->dst acc... |
245 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); |
1da177e4c Linux-2.6.12-rc2 |
246 247 248 |
kfree_skb(skb); return -EMSGSIZE; } |
7159039a1 [IPV6]: Decentral... |
249 |
EXPORT_SYMBOL(ip6_xmit); |
1da177e4c Linux-2.6.12-rc2 |
250 251 252 253 254 255 256 257 |
/* * To avoid extra problems ND packets are send through this * routine. It's code duplication but I really want to avoid * extra checks since ipv6_build_header is used by TCP (which * is for us performance critical) */ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, |
9acd9f3ae [IPV6]: Make addr... |
258 |
const struct in6_addr *saddr, const struct in6_addr *daddr, |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 262 |
int proto, int len) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6hdr *hdr; |
1da177e4c Linux-2.6.12-rc2 |
263 264 265 |
skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; |
55f79cc0c [IPV6]: Reset the... |
266 267 |
skb_reset_network_header(skb); skb_put(skb, sizeof(struct ipv6hdr)); |
0660e03f6 [SK_BUFF]: Introd... |
268 |
hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
269 |
|
ae08e1f09 [IPV6]: ip6_outpu... |
270 |
*(__be32*)hdr = htonl(0x60000000); |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 274 |
hdr->payload_len = htons(len); hdr->nexthdr = proto; hdr->hop_limit = np->hop_limit; |
4e3fd7a06 net: remove ipv6_... |
275 276 |
hdr->saddr = *saddr; hdr->daddr = *daddr; |
1da177e4c Linux-2.6.12-rc2 |
277 278 279 280 281 282 283 284 285 286 287 288 |
return 0; } static int ip6_call_ra_chain(struct sk_buff *skb, int sel) { struct ip6_ra_chain *ra; struct sock *last = NULL; read_lock(&ip6_ra_lock); for (ra = ip6_ra_chain; ra; ra = ra->next) { struct sock *sk = ra->sk; |
0bd1b59b1 [IPV6]: Check int... |
289 290 291 |
if (sk && ra->sel == sel && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == skb->dev->ifindex)) { |
1da177e4c Linux-2.6.12-rc2 |
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
if (last) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) rawv6_rcv(last, skb2); } last = sk; } } if (last) { rawv6_rcv(last, skb); read_unlock(&ip6_ra_lock); return 1; } read_unlock(&ip6_ra_lock); return 0; } |
e21e0b5f1 [IPV6] NDISC: Han... |
309 310 |
static int ip6_forward_proxy_check(struct sk_buff *skb) { |
0660e03f6 [SK_BUFF]: Introd... |
311 |
struct ipv6hdr *hdr = ipv6_hdr(skb); |
e21e0b5f1 [IPV6] NDISC: Han... |
312 |
u8 nexthdr = hdr->nexthdr; |
75f2811c6 ipv6: Add fragmen... |
313 |
__be16 frag_off; |
e21e0b5f1 [IPV6] NDISC: Han... |
314 315 316 |
int offset; if (ipv6_ext_hdr(nexthdr)) { |
75f2811c6 ipv6: Add fragmen... |
317 |
offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off); |
e21e0b5f1 [IPV6] NDISC: Han... |
318 319 320 321 322 323 324 |
if (offset < 0) return 0; } else offset = sizeof(struct ipv6hdr); if (nexthdr == IPPROTO_ICMPV6) { struct icmp6hdr *icmp6; |
d56f90a7c [SK_BUFF]: Introd... |
325 326 |
if (!pskb_may_pull(skb, (skb_network_header(skb) + offset + 1 - skb->data))) |
e21e0b5f1 [IPV6] NDISC: Han... |
327 |
return 0; |
d56f90a7c [SK_BUFF]: Introd... |
328 |
icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); |
e21e0b5f1 [IPV6] NDISC: Han... |
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
switch (icmp6->icmp6_type) { case NDISC_ROUTER_SOLICITATION: case NDISC_ROUTER_ADVERTISEMENT: case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_REDIRECT: /* For reaction involving unicast neighbor discovery * message destined to the proxied address, pass it to * input function. */ return 1; default: break; } } |
74553b09d [IPV6]: Don't for... |
345 346 347 348 349 350 351 352 353 |
/* * The proxying router can't forward traffic sent to a link-local * address, so signal the sender and discard the packet. This * behavior is clarified by the MIPv6 specification. */ if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) { dst_link_failure(skb); return -1; } |
e21e0b5f1 [IPV6] NDISC: Han... |
354 355 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
356 357 358 359 360 361 362 |
static inline int ip6_forward_finish(struct sk_buff *skb) { return dst_output(skb); } int ip6_forward(struct sk_buff *skb) { |
adf30907d net: skb->dst acc... |
363 |
struct dst_entry *dst = skb_dst(skb); |
0660e03f6 [SK_BUFF]: Introd... |
364 |
struct ipv6hdr *hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
365 |
struct inet6_skb_parm *opt = IP6CB(skb); |
c346dca10 [NET] NETNS: Omit... |
366 |
struct net *net = dev_net(dst->dev); |
69cce1d14 net: Abstract dst... |
367 |
struct neighbour *n; |
14f3ad6f4 ipv6: Use 1280 as... |
368 |
u32 mtu; |
1ab1457c4 [NET] IPV6: Fix w... |
369 |
|
53b7997fd ipv6 netns: Make ... |
370 |
if (net->ipv6.devconf_all->forwarding == 0) |
1da177e4c Linux-2.6.12-rc2 |
371 |
goto error; |
4497b0763 net: Discard and ... |
372 373 |
if (skb_warn_if_lro(skb)) goto drop; |
1da177e4c Linux-2.6.12-rc2 |
374 |
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { |
3bd653c84 netns: add net pa... |
375 |
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
376 377 |
goto drop; } |
72b43d089 inet6: prevent ne... |
378 379 |
if (skb->pkt_type != PACKET_HOST) goto drop; |
35fc92a9d [NET]: Allow forw... |
380 |
skb_forward_csum(skb); |
1da177e4c Linux-2.6.12-rc2 |
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
/* * We DO NOT make any processing on * RA packets, pushing them to user level AS IS * without ane WARRANTY that application will be able * to interpret them. The reason is that we * cannot make anything clever here. * * We are not end-node, so that if packet contains * AH/ESP, we cannot make anything. * Defragmentation also would be mistake, RA packets * cannot be fragmented, because there is no warranty * that different fragments will go along one path. --ANK */ if (opt->ra) { |
d56f90a7c [SK_BUFF]: Introd... |
396 |
u8 *ptr = skb_network_header(skb) + opt->ra; |
1da177e4c Linux-2.6.12-rc2 |
397 398 399 400 401 402 403 404 405 406 |
if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3])) return 0; } /* * check and decrement ttl */ if (hdr->hop_limit <= 1) { /* Force OUTPUT device used as source address */ skb->dev = dst->dev; |
3ffe533c8 ipv6: drop unused... |
407 |
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
483a47d2f ipv6: added net a... |
408 409 |
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
1da177e4c Linux-2.6.12-rc2 |
410 411 412 413 |
kfree_skb(skb); return -ETIMEDOUT; } |
fbea49e1e [IPV6] NDISC: Add... |
414 |
/* XXX: idev->cnf.proxy_ndp? */ |
53b7997fd ipv6 netns: Make ... |
415 |
if (net->ipv6.devconf_all->proxy_ndp && |
8a3edd800 [NETNS][IPV6] fix... |
416 |
pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) { |
74553b09d [IPV6]: Don't for... |
417 418 |
int proxied = ip6_forward_proxy_check(skb); if (proxied > 0) |
e21e0b5f1 [IPV6] NDISC: Han... |
419 |
return ip6_input(skb); |
74553b09d [IPV6]: Don't for... |
420 |
else if (proxied < 0) { |
3bd653c84 netns: add net pa... |
421 422 |
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
74553b09d [IPV6]: Don't for... |
423 424 |
goto drop; } |
e21e0b5f1 [IPV6] NDISC: Han... |
425 |
} |
1da177e4c Linux-2.6.12-rc2 |
426 |
if (!xfrm6_route_forward(skb)) { |
3bd653c84 netns: add net pa... |
427 |
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
428 429 |
goto drop; } |
adf30907d net: skb->dst acc... |
430 |
dst = skb_dst(skb); |
1da177e4c Linux-2.6.12-rc2 |
431 432 433 |
/* IPv6 specs say nothing about it, but it is clear that we cannot send redirects to source routed frames. |
1e5dc1461 [IPV6] IPSEC: Omi... |
434 |
We don't send redirects to frames decapsulated from IPsec. |
1da177e4c Linux-2.6.12-rc2 |
435 |
*/ |
272174550 net: Rename dst_g... |
436 |
n = dst_get_neighbour_noref(dst); |
69cce1d14 net: Abstract dst... |
437 |
if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) { |
1da177e4c Linux-2.6.12-rc2 |
438 439 |
struct in6_addr *target = NULL; struct rt6_info *rt; |
1da177e4c Linux-2.6.12-rc2 |
440 441 442 443 444 445 446 447 448 449 450 |
/* * incoming and outgoing devices are the same * send a redirect. */ rt = (struct rt6_info *) dst; if ((rt->rt6i_flags & RTF_GATEWAY)) target = (struct in6_addr*)&n->primary_key; else target = &hdr->daddr; |
92d868292 inetpeer: Move IC... |
451 452 |
if (!rt->rt6i_peer) rt6_bind_peer(rt, 1); |
1da177e4c Linux-2.6.12-rc2 |
453 454 455 |
/* Limit redirects both by destination (here) and by source (inside ndisc_send_redirect) */ |
92d868292 inetpeer: Move IC... |
456 |
if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) |
1da177e4c Linux-2.6.12-rc2 |
457 |
ndisc_send_redirect(skb, n, target); |
5bb1ab09e [IPV6]: Send ICMP... |
458 459 |
} else { int addrtype = ipv6_addr_type(&hdr->saddr); |
1da177e4c Linux-2.6.12-rc2 |
460 |
/* This check is security critical. */ |
f81b2e7d8 ipv6: Do not forw... |
461 462 |
if (addrtype == IPV6_ADDR_ANY || addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) |
5bb1ab09e [IPV6]: Send ICMP... |
463 464 465 |
goto error; if (addrtype & IPV6_ADDR_LINKLOCAL) { icmpv6_send(skb, ICMPV6_DEST_UNREACH, |
3ffe533c8 ipv6: drop unused... |
466 |
ICMPV6_NOT_NEIGHBOUR, 0); |
5bb1ab09e [IPV6]: Send ICMP... |
467 468 |
goto error; } |
1da177e4c Linux-2.6.12-rc2 |
469 |
} |
14f3ad6f4 ipv6: Use 1280 as... |
470 471 472 |
mtu = dst_mtu(dst); if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; |
0aa682715 ipv6: Add GSO sup... |
473 |
if (skb->len > mtu && !skb_is_gso(skb)) { |
1da177e4c Linux-2.6.12-rc2 |
474 475 |
/* Again, force OUTPUT device used as source address */ skb->dev = dst->dev; |
14f3ad6f4 ipv6: Use 1280 as... |
476 |
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
483a47d2f ipv6: added net a... |
477 478 479 480 |
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS); |
1da177e4c Linux-2.6.12-rc2 |
481 482 483 484 485 |
kfree_skb(skb); return -EMSGSIZE; } if (skb_cow(skb, dst->dev->hard_header_len)) { |
3bd653c84 netns: add net pa... |
486 |
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
487 488 |
goto drop; } |
0660e03f6 [SK_BUFF]: Introd... |
489 |
hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
490 491 |
/* Mangling hops number delayed to point after skb COW */ |
1ab1457c4 [NET] IPV6: Fix w... |
492 |
|
1da177e4c Linux-2.6.12-rc2 |
493 |
hdr->hop_limit--; |
483a47d2f ipv6: added net a... |
494 |
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); |
b2e0b385d netfilter: ipv6: ... |
495 |
return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev, |
6e23ae2a4 [NETFILTER]: Intr... |
496 |
ip6_forward_finish); |
1da177e4c Linux-2.6.12-rc2 |
497 498 |
error: |
483a47d2f ipv6: added net a... |
499 |
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS); |
1da177e4c Linux-2.6.12-rc2 |
500 501 502 503 504 505 506 507 508 509 |
drop: kfree_skb(skb); return -EINVAL; } static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) { to->pkt_type = from->pkt_type; to->priority = from->priority; to->protocol = from->protocol; |
adf30907d net: skb->dst acc... |
510 511 |
skb_dst_drop(to); skb_dst_set(to, dst_clone(skb_dst(from))); |
1da177e4c Linux-2.6.12-rc2 |
512 |
to->dev = from->dev; |
82e91ffef [NET]: Turn nfmar... |
513 |
to->mark = from->mark; |
1da177e4c Linux-2.6.12-rc2 |
514 515 516 517 |
#ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif |
e7ac05f34 [NETFILTER]: nf_c... |
518 |
nf_copy(to, from); |
ba9dda3ab [NETFILTER]: x_ta... |
519 520 521 522 |
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) to->nf_trace = from->nf_trace; #endif |
984bc16cc [SECMARK]: Add se... |
523 |
skb_copy_secmark(to, from); |
1da177e4c Linux-2.6.12-rc2 |
524 525 526 527 528 |
} int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); |
0660e03f6 [SK_BUFF]: Introd... |
529 530 |
struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); |
27a884dc3 [SK_BUFF]: Conver... |
531 |
unsigned int packet_len = skb->tail - skb->network_header; |
1da177e4c Linux-2.6.12-rc2 |
532 |
int found_rhdr = 0; |
0660e03f6 [SK_BUFF]: Introd... |
533 |
*nexthdr = &ipv6_hdr(skb)->nexthdr; |
1da177e4c Linux-2.6.12-rc2 |
534 535 536 537 538 539 |
while (offset + 1 <= packet_len) { switch (**nexthdr) { case NEXTHDR_HOP: |
27637df92 [IPV6] IPSEC: Sup... |
540 |
break; |
1da177e4c Linux-2.6.12-rc2 |
541 |
case NEXTHDR_ROUTING: |
27637df92 [IPV6] IPSEC: Sup... |
542 543 |
found_rhdr = 1; break; |
1da177e4c Linux-2.6.12-rc2 |
544 |
case NEXTHDR_DEST: |
59fbb3a61 [IPV6] MIP6: Load... |
545 |
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
27637df92 [IPV6] IPSEC: Sup... |
546 547 548 549 550 |
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) break; #endif if (found_rhdr) return offset; |
1da177e4c Linux-2.6.12-rc2 |
551 552 553 554 |
break; default : return offset; } |
27637df92 [IPV6] IPSEC: Sup... |
555 556 557 |
offset += ipv6_optlen(exthdr); *nexthdr = &exthdr->nexthdr; |
d56f90a7c [SK_BUFF]: Introd... |
558 559 |
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + offset); |
1da177e4c Linux-2.6.12-rc2 |
560 561 562 563 |
} return offset; } |
87c48fa3b ipv6: make fragme... |
564 565 566 567 |
void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) { static atomic_t ipv6_fragmentation_id; int old, new; |
e688a6048 net: introduce DS... |
568 |
if (rt && !(rt->dst.flags & DST_NOPEER)) { |
87c48fa3b ipv6: make fragme... |
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
struct inet_peer *peer; if (!rt->rt6i_peer) rt6_bind_peer(rt, 1); peer = rt->rt6i_peer; if (peer) { fhdr->identification = htonl(inet_getid(peer, 0)); return; } } do { old = atomic_read(&ipv6_fragmentation_id); new = old + 1; if (!new) new = 1; } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old); fhdr->identification = htonl(new); } |
ad0081e43 ipv6: Fragment lo... |
587 |
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
1da177e4c Linux-2.6.12-rc2 |
588 |
{ |
1da177e4c Linux-2.6.12-rc2 |
589 |
struct sk_buff *frag; |
adf30907d net: skb->dst acc... |
590 |
struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); |
d91675f9c [IPV6]: Do not ig... |
591 |
struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; |
1da177e4c Linux-2.6.12-rc2 |
592 593 594 |
struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; unsigned int mtu, hlen, left, len; |
a7ae19922 ipv6: Remove all ... |
595 |
int hroom, troom; |
ae08e1f09 [IPV6]: ip6_outpu... |
596 |
__be32 frag_id = 0; |
1da177e4c Linux-2.6.12-rc2 |
597 598 |
int ptr, offset = 0, err=0; u8 *prevhdr, nexthdr = 0; |
adf30907d net: skb->dst acc... |
599 |
struct net *net = dev_net(skb_dst(skb)->dev); |
1da177e4c Linux-2.6.12-rc2 |
600 |
|
1da177e4c Linux-2.6.12-rc2 |
601 602 |
hlen = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; |
628a5c561 [INET]: Add IP(V6... |
603 |
mtu = ip6_skb_dst_mtu(skb); |
b881ef760 [IPV6]: MTU disco... |
604 605 |
/* We must not fragment if the socket is set to force MTU discovery |
14f3ad6f4 ipv6: Use 1280 as... |
606 |
* or if the skb it not generated by a local socket. |
b881ef760 [IPV6]: MTU disco... |
607 |
*/ |
f2228f785 ipv6: allow to se... |
608 |
if (!skb->local_df && skb->len > mtu) { |
adf30907d net: skb->dst acc... |
609 |
skb->dev = skb_dst(skb)->dev; |
3ffe533c8 ipv6: drop unused... |
610 |
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
adf30907d net: skb->dst acc... |
611 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
3bd653c84 netns: add net pa... |
612 |
IPSTATS_MIB_FRAGFAILS); |
b881ef760 [IPV6]: MTU disco... |
613 614 615 |
kfree_skb(skb); return -EMSGSIZE; } |
d91675f9c [IPV6]: Do not ig... |
616 617 618 619 620 |
if (np && np->frag_size < mtu) { if (np->frag_size) mtu = np->frag_size; } mtu -= hlen + sizeof(struct frag_hdr); |
1da177e4c Linux-2.6.12-rc2 |
621 |
|
21dc33015 net: Rename skb_h... |
622 |
if (skb_has_frag_list(skb)) { |
1da177e4c Linux-2.6.12-rc2 |
623 |
int first_len = skb_pagelen(skb); |
3d13008e7 ip: fix truesize ... |
624 |
struct sk_buff *frag2; |
1da177e4c Linux-2.6.12-rc2 |
625 626 627 628 629 |
if (first_len - hlen > mtu || ((first_len - hlen) & 7) || skb_cloned(skb)) goto slow_path; |
4d9092bb4 ipv6: Use frag li... |
630 |
skb_walk_frags(skb, frag) { |
1da177e4c Linux-2.6.12-rc2 |
631 632 633 634 |
/* Correct geometry. */ if (frag->len > mtu || ((frag->len & 7) && frag->next) || skb_headroom(frag) < hlen) |
3d13008e7 ip: fix truesize ... |
635 |
goto slow_path_clean; |
1da177e4c Linux-2.6.12-rc2 |
636 |
|
1da177e4c Linux-2.6.12-rc2 |
637 638 |
/* Partially cloned skb? */ if (skb_shared(frag)) |
3d13008e7 ip: fix truesize ... |
639 |
goto slow_path_clean; |
2fdba6b08 [IPV4/IPV6] Ensur... |
640 641 642 |
BUG_ON(frag->sk); if (skb->sk) { |
2fdba6b08 [IPV4/IPV6] Ensur... |
643 644 |
frag->sk = skb->sk; frag->destructor = sock_wfree; |
2fdba6b08 [IPV4/IPV6] Ensur... |
645 |
} |
3d13008e7 ip: fix truesize ... |
646 |
skb->truesize -= frag->truesize; |
1da177e4c Linux-2.6.12-rc2 |
647 648 649 650 651 |
} err = 0; offset = 0; frag = skb_shinfo(skb)->frag_list; |
4d9092bb4 ipv6: Use frag li... |
652 |
skb_frag_list_init(skb); |
1da177e4c Linux-2.6.12-rc2 |
653 |
/* BUILD HEADER */ |
9a217a1c7 [IPV6]: Repair IP... |
654 |
*prevhdr = NEXTHDR_FRAGMENT; |
d56f90a7c [SK_BUFF]: Introd... |
655 |
tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); |
1da177e4c Linux-2.6.12-rc2 |
656 |
if (!tmp_hdr) { |
adf30907d net: skb->dst acc... |
657 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
3bd653c84 netns: add net pa... |
658 |
IPSTATS_MIB_FRAGFAILS); |
1da177e4c Linux-2.6.12-rc2 |
659 660 |
return -ENOMEM; } |
1da177e4c Linux-2.6.12-rc2 |
661 662 |
__skb_pull(skb, hlen); fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr)); |
e2d1bca7e [SK_BUFF]: Use sk... |
663 664 |
__skb_push(skb, hlen); skb_reset_network_header(skb); |
d56f90a7c [SK_BUFF]: Introd... |
665 |
memcpy(skb_network_header(skb), tmp_hdr, hlen); |
1da177e4c Linux-2.6.12-rc2 |
666 |
|
87c48fa3b ipv6: make fragme... |
667 |
ipv6_select_ident(fh, rt); |
1da177e4c Linux-2.6.12-rc2 |
668 669 670 671 672 673 674 675 |
fh->nexthdr = nexthdr; fh->reserved = 0; fh->frag_off = htons(IP6_MF); frag_id = fh->identification; first_len = skb_pagelen(skb); skb->data_len = first_len - skb_headlen(skb); skb->len = first_len; |
0660e03f6 [SK_BUFF]: Introd... |
676 677 |
ipv6_hdr(skb)->payload_len = htons(first_len - sizeof(struct ipv6hdr)); |
a11d206d0 [IPV6]: Per-inter... |
678 |
|
d8d1f30b9 net-next: remove ... |
679 |
dst_hold(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
680 681 682 683 684 685 |
for (;;) { /* Prepare header of the next frame, * before previous one went down. */ if (frag) { frag->ip_summed = CHECKSUM_NONE; |
badff6d01 [SK_BUFF]: Introd... |
686 |
skb_reset_transport_header(frag); |
1da177e4c Linux-2.6.12-rc2 |
687 |
fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr)); |
e2d1bca7e [SK_BUFF]: Use sk... |
688 689 |
__skb_push(frag, hlen); skb_reset_network_header(frag); |
d56f90a7c [SK_BUFF]: Introd... |
690 691 |
memcpy(skb_network_header(frag), tmp_hdr, hlen); |
1da177e4c Linux-2.6.12-rc2 |
692 693 694 695 696 697 698 |
offset += skb->len - hlen - sizeof(struct frag_hdr); fh->nexthdr = nexthdr; fh->reserved = 0; fh->frag_off = htons(offset); if (frag->next != NULL) fh->frag_off |= htons(IP6_MF); fh->identification = frag_id; |
0660e03f6 [SK_BUFF]: Introd... |
699 700 701 |
ipv6_hdr(frag)->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); |
1da177e4c Linux-2.6.12-rc2 |
702 703 |
ip6_copy_metadata(frag, skb); } |
1ab1457c4 [NET] IPV6: Fix w... |
704 |
|
1da177e4c Linux-2.6.12-rc2 |
705 |
err = output(skb); |
dafee4908 [IPV6]: SNMPv2 "i... |
706 |
if(!err) |
d8d1f30b9 net-next: remove ... |
707 |
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
3bd653c84 netns: add net pa... |
708 |
IPSTATS_MIB_FRAGCREATES); |
dafee4908 [IPV6]: SNMPv2 "i... |
709 |
|
1da177e4c Linux-2.6.12-rc2 |
710 711 712 713 714 715 716 |
if (err || !frag) break; skb = frag; frag = skb->next; skb->next = NULL; } |
a51482bde [NET]: kfree cleanup |
717 |
kfree(tmp_hdr); |
1da177e4c Linux-2.6.12-rc2 |
718 719 |
if (err == 0) { |
d8d1f30b9 net-next: remove ... |
720 |
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
3bd653c84 netns: add net pa... |
721 |
IPSTATS_MIB_FRAGOKS); |
d8d1f30b9 net-next: remove ... |
722 |
dst_release(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
723 724 725 726 727 728 729 730 |
return 0; } while (frag) { skb = frag->next; kfree_skb(frag); frag = skb; } |
d8d1f30b9 net-next: remove ... |
731 |
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
3bd653c84 netns: add net pa... |
732 |
IPSTATS_MIB_FRAGFAILS); |
d8d1f30b9 net-next: remove ... |
733 |
dst_release(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
734 |
return err; |
3d13008e7 ip: fix truesize ... |
735 736 737 738 739 740 741 742 743 |
slow_path_clean: skb_walk_frags(skb, frag2) { if (frag2 == frag) break; frag2->sk = NULL; frag2->destructor = NULL; skb->truesize += frag2->truesize; } |
1da177e4c Linux-2.6.12-rc2 |
744 745 746 747 748 749 750 751 752 753 754 |
} slow_path: left = skb->len - hlen; /* Space per frame */ ptr = hlen; /* Where to start from */ /* * Fragment the datagram. */ *prevhdr = NEXTHDR_FRAGMENT; |
a7ae19922 ipv6: Remove all ... |
755 756 |
hroom = LL_RESERVED_SPACE(rt->dst.dev); troom = rt->dst.dev->needed_tailroom; |
1da177e4c Linux-2.6.12-rc2 |
757 758 759 760 761 762 763 764 765 |
/* * Keep copying data until we run out. */ while(left > 0) { len = left; /* IF: it doesn't fit, use 'mtu' - the data space left */ if (len > mtu) len = mtu; |
25985edce Fix common misspe... |
766 |
/* IF: we are not sending up to and including the packet end |
1da177e4c Linux-2.6.12-rc2 |
767 768 769 770 771 772 773 |
then align the next start on an eight byte boundary */ if (len < left) { len &= ~7; } /* * Allocate buffer. */ |
a7ae19922 ipv6: Remove all ... |
774 775 |
if ((frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) + hroom + troom, GFP_ATOMIC)) == NULL) { |
64ce20730 [NET]: Make NETDE... |
776 777 |
NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment! "); |
adf30907d net: skb->dst acc... |
778 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
a11d206d0 [IPV6]: Per-inter... |
779 |
IPSTATS_MIB_FRAGFAILS); |
1da177e4c Linux-2.6.12-rc2 |
780 781 782 783 784 785 786 787 788 |
err = -ENOMEM; goto fail; } /* * Set up data on packet */ ip6_copy_metadata(frag, skb); |
a7ae19922 ipv6: Remove all ... |
789 |
skb_reserve(frag, hroom); |
1da177e4c Linux-2.6.12-rc2 |
790 |
skb_put(frag, len + hlen + sizeof(struct frag_hdr)); |
c1d2bbe1c [SK_BUFF]: Introd... |
791 |
skb_reset_network_header(frag); |
badff6d01 [SK_BUFF]: Introd... |
792 |
fh = (struct frag_hdr *)(skb_network_header(frag) + hlen); |
b0e380b1d [SK_BUFF]: unions... |
793 794 |
frag->transport_header = (frag->network_header + hlen + sizeof(struct frag_hdr)); |
1da177e4c Linux-2.6.12-rc2 |
795 796 797 798 799 800 801 802 803 804 805 |
/* * Charge the memory for the fragment to any owner * it might possess */ if (skb->sk) skb_set_owner_w(frag, skb->sk); /* * Copy the packet header into the new buffer. */ |
d626f62b1 [SK_BUFF]: Introd... |
806 |
skb_copy_from_linear_data(skb, skb_network_header(frag), hlen); |
1da177e4c Linux-2.6.12-rc2 |
807 808 809 810 811 812 |
/* * Build fragment header. */ fh->nexthdr = nexthdr; fh->reserved = 0; |
f36d6ab18 [IPV6]: Fix ipv6 ... |
813 |
if (!frag_id) { |
87c48fa3b ipv6: make fragme... |
814 |
ipv6_select_ident(fh, rt); |
1da177e4c Linux-2.6.12-rc2 |
815 816 817 818 819 820 821 |
frag_id = fh->identification; } else fh->identification = frag_id; /* * Copy a block of the IP datagram. */ |
8984e41d1 [IPV6]: Fix kerne... |
822 |
if (skb_copy_bits(skb, ptr, skb_transport_header(frag), len)) |
1da177e4c Linux-2.6.12-rc2 |
823 824 825 826 827 828 |
BUG(); left -= len; fh->frag_off = htons(offset); if (left > 0) fh->frag_off |= htons(IP6_MF); |
0660e03f6 [SK_BUFF]: Introd... |
829 830 |
ipv6_hdr(frag)->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); |
1da177e4c Linux-2.6.12-rc2 |
831 832 833 834 835 836 837 |
ptr += len; offset += len; /* * Put this fragment into the sending queue. */ |
1da177e4c Linux-2.6.12-rc2 |
838 839 840 |
err = output(frag); if (err) goto fail; |
dafee4908 [IPV6]: SNMPv2 "i... |
841 |
|
adf30907d net: skb->dst acc... |
842 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
3bd653c84 netns: add net pa... |
843 |
IPSTATS_MIB_FRAGCREATES); |
1da177e4c Linux-2.6.12-rc2 |
844 |
} |
adf30907d net: skb->dst acc... |
845 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
a11d206d0 [IPV6]: Per-inter... |
846 |
IPSTATS_MIB_FRAGOKS); |
1da177e4c Linux-2.6.12-rc2 |
847 |
kfree_skb(skb); |
1da177e4c Linux-2.6.12-rc2 |
848 849 850 |
return err; fail: |
adf30907d net: skb->dst acc... |
851 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
a11d206d0 [IPV6]: Per-inter... |
852 |
IPSTATS_MIB_FRAGFAILS); |
1ab1457c4 [NET] IPV6: Fix w... |
853 |
kfree_skb(skb); |
1da177e4c Linux-2.6.12-rc2 |
854 855 |
return err; } |
b71d1d426 inet: constify ip... |
856 857 858 |
static inline int ip6_rt_check(const struct rt6key *rt_key, const struct in6_addr *fl_addr, const struct in6_addr *addr_cache) |
cf6b19825 [IPV6] ROUTE: Int... |
859 |
{ |
a02cec215 net: return opera... |
860 861 |
return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)); |
cf6b19825 [IPV6] ROUTE: Int... |
862 |
} |
497c615ab [IPV6]: Audit all... |
863 864 |
static struct dst_entry *ip6_sk_dst_check(struct sock *sk, struct dst_entry *dst, |
b71d1d426 inet: constify ip... |
865 |
const struct flowi6 *fl6) |
1da177e4c Linux-2.6.12-rc2 |
866 |
{ |
497c615ab [IPV6]: Audit all... |
867 868 |
struct ipv6_pinfo *np = inet6_sk(sk); struct rt6_info *rt = (struct rt6_info *)dst; |
1da177e4c Linux-2.6.12-rc2 |
869 |
|
497c615ab [IPV6]: Audit all... |
870 871 872 873 874 875 876 877 |
if (!dst) goto out; /* Yes, checking route validity in not connected * case is not very simple. Take into account, * that we do not support routing by source, TOS, * and MSG_DONTROUTE --ANK (980726) * |
cf6b19825 [IPV6] ROUTE: Int... |
878 879 |
* 1. ip6_rt_check(): If route was host route, * check that cached destination is current. |
497c615ab [IPV6]: Audit all... |
880 881 882 883 884 885 886 887 888 889 |
* If it is network route, we still may * check its validity using saved pointer * to the last used address: daddr_cache. * We do not want to save whole address now, * (because main consumer of this service * is tcp, which has not this problem), * so that the last trick works only on connected * sockets. * 2. oif also should be the same. */ |
4c9483b2f ipv6: Convert to ... |
890 |
if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) || |
8e1ef0a95 [IPV6]: Cache sou... |
891 |
#ifdef CONFIG_IPV6_SUBTREES |
4c9483b2f ipv6: Convert to ... |
892 |
ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) || |
8e1ef0a95 [IPV6]: Cache sou... |
893 |
#endif |
4c9483b2f ipv6: Convert to ... |
894 |
(fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex)) { |
497c615ab [IPV6]: Audit all... |
895 896 |
dst_release(dst); dst = NULL; |
1da177e4c Linux-2.6.12-rc2 |
897 |
} |
497c615ab [IPV6]: Audit all... |
898 899 900 901 902 |
out: return dst; } static int ip6_dst_lookup_tail(struct sock *sk, |
4c9483b2f ipv6: Convert to ... |
903 |
struct dst_entry **dst, struct flowi6 *fl6) |
497c615ab [IPV6]: Audit all... |
904 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
905 |
struct net *net = sock_net(sk); |
69cce1d14 net: Abstract dst... |
906 907 908 909 |
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD struct neighbour *n; #endif int err; |
497c615ab [IPV6]: Audit all... |
910 |
|
1da177e4c Linux-2.6.12-rc2 |
911 |
if (*dst == NULL) |
4c9483b2f ipv6: Convert to ... |
912 |
*dst = ip6_route_output(net, sk, fl6); |
1da177e4c Linux-2.6.12-rc2 |
913 914 915 |
if ((err = (*dst)->error)) goto out_err_release; |
4c9483b2f ipv6: Convert to ... |
916 |
if (ipv6_addr_any(&fl6->saddr)) { |
c3968a857 ipv6: RTA_PREFSRC... |
917 918 919 920 |
struct rt6_info *rt = (struct rt6_info *) *dst; err = ip6_route_get_saddr(net, rt, &fl6->daddr, sk ? inet6_sk(sk)->srcprefs : 0, &fl6->saddr); |
44456d37b [PATCH] turn many... |
921 |
if (err) |
1da177e4c Linux-2.6.12-rc2 |
922 |
goto out_err_release; |
1da177e4c Linux-2.6.12-rc2 |
923 |
} |
95c385b4d [IPV6] ADDRCONF: ... |
924 |
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
e550dfb0c ipv6: Fix OOPS in... |
925 926 927 928 929 930 931 932 |
/* * Here if the dst entry we've looked up * has a neighbour entry that is in the INCOMPLETE * state and the src address from the flow is * marked as OPTIMISTIC, we release the found * dst entry and replace it instead with the * dst entry of the nexthop router */ |
f2c31e32b net: fix NULL der... |
933 |
rcu_read_lock(); |
272174550 net: Rename dst_g... |
934 |
n = dst_get_neighbour_noref(*dst); |
69cce1d14 net: Abstract dst... |
935 |
if (n && !(n->nud_state & NUD_VALID)) { |
e550dfb0c ipv6: Fix OOPS in... |
936 |
struct inet6_ifaddr *ifp; |
4c9483b2f ipv6: Convert to ... |
937 |
struct flowi6 fl_gw6; |
e550dfb0c ipv6: Fix OOPS in... |
938 |
int redirect; |
f2c31e32b net: fix NULL der... |
939 |
rcu_read_unlock(); |
4c9483b2f ipv6: Convert to ... |
940 |
ifp = ipv6_get_ifaddr(net, &fl6->saddr, |
e550dfb0c ipv6: Fix OOPS in... |
941 942 943 944 945 946 947 948 949 950 951 952 |
(*dst)->dev, 1); redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); if (ifp) in6_ifa_put(ifp); if (redirect) { /* * We need to get the dst entry for the * default router instead */ dst_release(*dst); |
4c9483b2f ipv6: Convert to ... |
953 954 955 |
memcpy(&fl_gw6, fl6, sizeof(struct flowi6)); memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr)); *dst = ip6_route_output(net, sk, &fl_gw6); |
e550dfb0c ipv6: Fix OOPS in... |
956 957 |
if ((err = (*dst)->error)) goto out_err_release; |
95c385b4d [IPV6] ADDRCONF: ... |
958 |
} |
f2c31e32b net: fix NULL der... |
959 960 |
} else { rcu_read_unlock(); |
e550dfb0c ipv6: Fix OOPS in... |
961 |
} |
95c385b4d [IPV6] ADDRCONF: ... |
962 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
963 964 965 |
return 0; out_err_release: |
ca46f9c83 [IPv6] SNMP: Incr... |
966 |
if (err == -ENETUNREACH) |
483a47d2f ipv6: added net a... |
967 |
IP6_INC_STATS_BH(net, NULL, IPSTATS_MIB_OUTNOROUTES); |
1da177e4c Linux-2.6.12-rc2 |
968 969 970 971 |
dst_release(*dst); *dst = NULL; return err; } |
34a0b3cdc [IPV6]: make two ... |
972 |
|
497c615ab [IPV6]: Audit all... |
973 974 975 976 |
/** * ip6_dst_lookup - perform route lookup on flow * @sk: socket which provides route info * @dst: pointer to dst_entry * for result |
4c9483b2f ipv6: Convert to ... |
977 |
* @fl6: flow to lookup |
497c615ab [IPV6]: Audit all... |
978 979 980 981 982 |
* * This function performs a route lookup on the given flow. * * It returns zero on success, or a standard errno code on error. */ |
4c9483b2f ipv6: Convert to ... |
983 |
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6) |
497c615ab [IPV6]: Audit all... |
984 985 |
{ *dst = NULL; |
4c9483b2f ipv6: Convert to ... |
986 |
return ip6_dst_lookup_tail(sk, dst, fl6); |
497c615ab [IPV6]: Audit all... |
987 |
} |
3cf3dc6c2 [IPV6]: Export so... |
988 |
EXPORT_SYMBOL_GPL(ip6_dst_lookup); |
497c615ab [IPV6]: Audit all... |
989 |
/** |
68d0c6d34 ipv6: Consolidate... |
990 991 |
* ip6_dst_lookup_flow - perform route lookup on flow with ipsec * @sk: socket which provides route info |
4c9483b2f ipv6: Convert to ... |
992 |
* @fl6: flow to lookup |
68d0c6d34 ipv6: Consolidate... |
993 |
* @final_dst: final destination address for ipsec lookup |
a1414715f ipv6: Change fina... |
994 |
* @can_sleep: we are in a sleepable context |
68d0c6d34 ipv6: Consolidate... |
995 996 997 998 999 1000 |
* * This function performs a route lookup on the given flow. * * It returns a valid dst pointer on success, or a pointer encoded * error code. */ |
4c9483b2f ipv6: Convert to ... |
1001 |
struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
68d0c6d34 ipv6: Consolidate... |
1002 |
const struct in6_addr *final_dst, |
a1414715f ipv6: Change fina... |
1003 |
bool can_sleep) |
68d0c6d34 ipv6: Consolidate... |
1004 1005 1006 |
{ struct dst_entry *dst = NULL; int err; |
4c9483b2f ipv6: Convert to ... |
1007 |
err = ip6_dst_lookup_tail(sk, &dst, fl6); |
68d0c6d34 ipv6: Consolidate... |
1008 1009 1010 |
if (err) return ERR_PTR(err); if (final_dst) |
4e3fd7a06 net: remove ipv6_... |
1011 |
fl6->daddr = *final_dst; |
2774c131b xfrm: Handle blac... |
1012 |
if (can_sleep) |
4c9483b2f ipv6: Convert to ... |
1013 |
fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; |
2774c131b xfrm: Handle blac... |
1014 |
|
4c9483b2f ipv6: Convert to ... |
1015 |
return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); |
68d0c6d34 ipv6: Consolidate... |
1016 1017 1018 1019 1020 |
} EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); /** * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow |
497c615ab [IPV6]: Audit all... |
1021 |
* @sk: socket which provides the dst cache and route info |
4c9483b2f ipv6: Convert to ... |
1022 |
* @fl6: flow to lookup |
68d0c6d34 ipv6: Consolidate... |
1023 |
* @final_dst: final destination address for ipsec lookup |
a1414715f ipv6: Change fina... |
1024 |
* @can_sleep: we are in a sleepable context |
497c615ab [IPV6]: Audit all... |
1025 1026 1027 1028 1029 1030 |
* * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. * It will take the socket dst lock when operating on the dst cache. * As a result, this function can only be used in process context. * |
68d0c6d34 ipv6: Consolidate... |
1031 1032 |
* It returns a valid dst pointer on success, or a pointer encoded * error code. |
497c615ab [IPV6]: Audit all... |
1033 |
*/ |
4c9483b2f ipv6: Convert to ... |
1034 |
struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
68d0c6d34 ipv6: Consolidate... |
1035 |
const struct in6_addr *final_dst, |
a1414715f ipv6: Change fina... |
1036 |
bool can_sleep) |
497c615ab [IPV6]: Audit all... |
1037 |
{ |
68d0c6d34 ipv6: Consolidate... |
1038 1039 |
struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); int err; |
497c615ab [IPV6]: Audit all... |
1040 |
|
4c9483b2f ipv6: Convert to ... |
1041 |
dst = ip6_sk_dst_check(sk, dst, fl6); |
68d0c6d34 ipv6: Consolidate... |
1042 |
|
4c9483b2f ipv6: Convert to ... |
1043 |
err = ip6_dst_lookup_tail(sk, &dst, fl6); |
68d0c6d34 ipv6: Consolidate... |
1044 1045 1046 |
if (err) return ERR_PTR(err); if (final_dst) |
4e3fd7a06 net: remove ipv6_... |
1047 |
fl6->daddr = *final_dst; |
2774c131b xfrm: Handle blac... |
1048 |
if (can_sleep) |
4c9483b2f ipv6: Convert to ... |
1049 |
fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; |
2774c131b xfrm: Handle blac... |
1050 |
|
4c9483b2f ipv6: Convert to ... |
1051 |
return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); |
497c615ab [IPV6]: Audit all... |
1052 |
} |
68d0c6d34 ipv6: Consolidate... |
1053 |
EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); |
497c615ab [IPV6]: Audit all... |
1054 |
|
34a0b3cdc [IPV6]: make two ... |
1055 |
static inline int ip6_ufo_append_data(struct sock *sk, |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1056 1057 1058 |
int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int hh_len, int fragheaderlen, |
87c48fa3b ipv6: make fragme... |
1059 1060 |
int transhdrlen, int mtu,unsigned int flags, struct rt6_info *rt) |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 |
{ struct sk_buff *skb; int err; /* There is support for UDP large send offload by network * device, so create one single skb packet containing complete * udp datagram */ if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { skb = sock_alloc_send_skb(sk, hh_len + fragheaderlen + transhdrlen + 20, (flags & MSG_DONTWAIT), &err); if (skb == NULL) |
504744e4e ipv6: fix error p... |
1075 |
return err; |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1076 1077 1078 1079 1080 1081 1082 1083 |
/* reserve space for Hardware header */ skb_reserve(skb, hh_len); /* create space for UDP/IP header */ skb_put(skb,fragheaderlen + transhdrlen); /* initialize network header pointer */ |
c1d2bbe1c [SK_BUFF]: Introd... |
1084 |
skb_reset_network_header(skb); |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1085 1086 |
/* initialize protocol header pointer */ |
b0e380b1d [SK_BUFF]: unions... |
1087 |
skb->transport_header = skb->network_header + fragheaderlen; |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1088 |
|
84fa7933a [NET]: Replace CH... |
1089 |
skb->ip_summed = CHECKSUM_PARTIAL; |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1090 |
skb->csum = 0; |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1091 1092 1093 1094 1095 1096 |
} err = skb_append_datato_frags(sk,skb, getfrag, from, (length - transhdrlen)); if (!err) { struct frag_hdr fhdr; |
c31d53269 udpv6: Fix gso_si... |
1097 1098 1099 1100 1101 |
/* Specify the length of each IPv6 datagram fragment. * It has to be a multiple of 8. */ skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - sizeof(struct frag_hdr)) & ~7; |
f83ef8c0b [IPV6]: Added GSO... |
1102 |
skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
87c48fa3b ipv6: make fragme... |
1103 |
ipv6_select_ident(&fhdr, rt); |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 |
skb_shinfo(skb)->ip6_frag_id = fhdr.identification; __skb_queue_tail(&sk->sk_write_queue, skb); return 0; } /* There is not enough support do UPD LSO, * so follow normal path */ kfree_skb(skb); return err; } |
1da177e4c Linux-2.6.12-rc2 |
1116 |
|
0178b695f ipv6: Copy cork o... |
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 |
static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, gfp_t gfp) { return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; } static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, gfp_t gfp) { return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; } |
41a1f8ea4 [IPV6]: Support I... |
1128 1129 1130 |
int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, |
4c9483b2f ipv6: Convert to ... |
1131 |
int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, |
13b52cd44 IPv6: Add dontfra... |
1132 |
struct rt6_info *rt, unsigned int flags, int dontfrag) |
1da177e4c Linux-2.6.12-rc2 |
1133 1134 1135 |
{ struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); |
bdc712b4c inet: Decrease ov... |
1136 |
struct inet_cork *cork; |
1da177e4c Linux-2.6.12-rc2 |
1137 1138 1139 |
struct sk_buff *skb; unsigned int maxfraglen, fragheaderlen; int exthdrlen; |
299b07676 ipv6: Fix IPsec s... |
1140 |
int dst_exthdrlen; |
1da177e4c Linux-2.6.12-rc2 |
1141 1142 1143 1144 1145 1146 |
int hh_len; int mtu; int copy; int err; int offset = 0; int csummode = CHECKSUM_NONE; |
a693e6989 net: TX timestamp... |
1147 |
__u8 tx_flags = 0; |
1da177e4c Linux-2.6.12-rc2 |
1148 1149 1150 |
if (flags&MSG_PROBE) return 0; |
bdc712b4c inet: Decrease ov... |
1151 |
cork = &inet->cork.base; |
1da177e4c Linux-2.6.12-rc2 |
1152 1153 1154 1155 1156 |
if (skb_queue_empty(&sk->sk_write_queue)) { /* * setup for corking */ if (opt) { |
0178b695f ipv6: Copy cork o... |
1157 |
if (WARN_ON(np->cork.opt)) |
1da177e4c Linux-2.6.12-rc2 |
1158 |
return -EINVAL; |
0178b695f ipv6: Copy cork o... |
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 |
np->cork.opt = kmalloc(opt->tot_len, sk->sk_allocation); if (unlikely(np->cork.opt == NULL)) return -ENOBUFS; np->cork.opt->tot_len = opt->tot_len; np->cork.opt->opt_flen = opt->opt_flen; np->cork.opt->opt_nflen = opt->opt_nflen; np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt, sk->sk_allocation); if (opt->dst0opt && !np->cork.opt->dst0opt) return -ENOBUFS; np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt, sk->sk_allocation); if (opt->dst1opt && !np->cork.opt->dst1opt) return -ENOBUFS; np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt, sk->sk_allocation); if (opt->hopopt && !np->cork.opt->hopopt) return -ENOBUFS; np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt, sk->sk_allocation); if (opt->srcrt && !np->cork.opt->srcrt) return -ENOBUFS; |
1da177e4c Linux-2.6.12-rc2 |
1187 1188 |
/* need source address above miyazawa*/ } |
d8d1f30b9 net-next: remove ... |
1189 |
dst_hold(&rt->dst); |
bdc712b4c inet: Decrease ov... |
1190 |
cork->dst = &rt->dst; |
4c9483b2f ipv6: Convert to ... |
1191 |
inet->cork.fl.u.ip6 = *fl6; |
1da177e4c Linux-2.6.12-rc2 |
1192 |
np->cork.hop_limit = hlimit; |
41a1f8ea4 [IPV6]: Support I... |
1193 |
np->cork.tclass = tclass; |
628a5c561 [INET]: Add IP(V6... |
1194 |
mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? |
299b07676 ipv6: Fix IPsec s... |
1195 |
rt->dst.dev->mtu : dst_mtu(&rt->dst); |
c75036093 [IPV6]: remove us... |
1196 |
if (np->frag_size < mtu) { |
d91675f9c [IPV6]: Do not ig... |
1197 1198 1199 |
if (np->frag_size) mtu = np->frag_size; } |
bdc712b4c inet: Decrease ov... |
1200 |
cork->fragsize = mtu; |
d8d1f30b9 net-next: remove ... |
1201 |
if (dst_allfrag(rt->dst.path)) |
bdc712b4c inet: Decrease ov... |
1202 1203 |
cork->flags |= IPCORK_ALLFRAG; cork->length = 0; |
1da177e4c Linux-2.6.12-rc2 |
1204 1205 |
sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; |
299b07676 ipv6: Fix IPsec s... |
1206 |
exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len; |
1da177e4c Linux-2.6.12-rc2 |
1207 1208 |
length += exthdrlen; transhdrlen += exthdrlen; |
299b07676 ipv6: Fix IPsec s... |
1209 |
dst_exthdrlen = rt->dst.header_len; |
1da177e4c Linux-2.6.12-rc2 |
1210 |
} else { |
bdc712b4c inet: Decrease ov... |
1211 |
rt = (struct rt6_info *)cork->dst; |
4c9483b2f ipv6: Convert to ... |
1212 |
fl6 = &inet->cork.fl.u.ip6; |
0178b695f ipv6: Copy cork o... |
1213 |
opt = np->cork.opt; |
1da177e4c Linux-2.6.12-rc2 |
1214 1215 |
transhdrlen = 0; exthdrlen = 0; |
299b07676 ipv6: Fix IPsec s... |
1216 |
dst_exthdrlen = 0; |
bdc712b4c inet: Decrease ov... |
1217 |
mtu = cork->fragsize; |
1da177e4c Linux-2.6.12-rc2 |
1218 |
} |
d8d1f30b9 net-next: remove ... |
1219 |
hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
1da177e4c Linux-2.6.12-rc2 |
1220 |
|
a1b051405 [XFRM] IPv6: Fix ... |
1221 |
fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + |
b4ce92775 [IPV6]: Move nfhe... |
1222 |
(opt ? opt->opt_nflen : 0); |
1da177e4c Linux-2.6.12-rc2 |
1223 1224 1225 |
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
bdc712b4c inet: Decrease ov... |
1226 |
if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { |
4c9483b2f ipv6: Convert to ... |
1227 |
ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen); |
1da177e4c Linux-2.6.12-rc2 |
1228 1229 1230 |
return -EMSGSIZE; } } |
a693e6989 net: TX timestamp... |
1231 1232 1233 1234 1235 1236 |
/* For UDP, check if TX timestamp is enabled */ if (sk->sk_type == SOCK_DGRAM) { err = sock_tx_timestamp(sk, &tx_flags); if (err) goto error; } |
1da177e4c Linux-2.6.12-rc2 |
1237 1238 1239 1240 1241 1242 1243 |
/* * Let's try using as much space as possible. * Use MTU if total length of the message fits into the MTU. * Otherwise, we need to reserve fragment header and * fragment alignment (= 8-15 octects, in total). * * Note that we may need to "move" the data from the tail of |
1ab1457c4 [NET] IPV6: Fix w... |
1244 |
* of the buffer to the new fragment when we split |
1da177e4c Linux-2.6.12-rc2 |
1245 1246 |
* the message. * |
1ab1457c4 [NET] IPV6: Fix w... |
1247 |
* FIXME: It may be fragmented into multiple chunks |
1da177e4c Linux-2.6.12-rc2 |
1248 1249 |
* at once if non-fragmentable extension headers * are too large. |
1ab1457c4 [NET] IPV6: Fix w... |
1250 |
* --yoshfuji |
1da177e4c Linux-2.6.12-rc2 |
1251 |
*/ |
bdc712b4c inet: Decrease ov... |
1252 |
cork->length += length; |
4b340ae20 IPv6: Complete IP... |
1253 1254 1255 |
if (length > mtu) { int proto = sk->sk_protocol; if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ |
4c9483b2f ipv6: Convert to ... |
1256 |
ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); |
4b340ae20 IPv6: Complete IP... |
1257 1258 |
return -EMSGSIZE; } |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1259 |
|
4b340ae20 IPv6: Complete IP... |
1260 |
if (proto == IPPROTO_UDP && |
d8d1f30b9 net-next: remove ... |
1261 |
(rt->dst.dev->features & NETIF_F_UFO)) { |
4b340ae20 IPv6: Complete IP... |
1262 1263 1264 |
err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len, fragheaderlen, |
87c48fa3b ipv6: make fragme... |
1265 |
transhdrlen, mtu, flags, rt); |
4b340ae20 IPv6: Complete IP... |
1266 1267 1268 1269 |
if (err) goto error; return 0; } |
e89e9cf53 [IPv4/IPv6]: UFO ... |
1270 |
} |
1da177e4c Linux-2.6.12-rc2 |
1271 1272 1273 1274 1275 1276 |
if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) goto alloc_new_skb; while (length > 0) { /* Check if the remaining data fits into current packet. */ |
bdc712b4c inet: Decrease ov... |
1277 |
copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; |
1da177e4c Linux-2.6.12-rc2 |
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 |
if (copy < length) copy = maxfraglen - skb->len; if (copy <= 0) { char *data; unsigned int datalen; unsigned int fraglen; unsigned int fraggap; unsigned int alloclen; struct sk_buff *skb_prev; alloc_new_skb: skb_prev = skb; /* There's no room in the current skb */ if (skb_prev) fraggap = skb_prev->len - maxfraglen; else fraggap = 0; /* * If remaining data exceeds the mtu, * we know we need more fragment(s). */ datalen = length + fraggap; |
bdc712b4c inet: Decrease ov... |
1302 |
if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) |
1da177e4c Linux-2.6.12-rc2 |
1303 1304 1305 1306 |
datalen = maxfraglen - fragheaderlen; fraglen = datalen + fragheaderlen; if ((flags & MSG_MORE) && |
d8d1f30b9 net-next: remove ... |
1307 |
!(rt->dst.dev->features&NETIF_F_SG)) |
1da177e4c Linux-2.6.12-rc2 |
1308 1309 1310 |
alloclen = mtu; else alloclen = datalen + fragheaderlen; |
299b07676 ipv6: Fix IPsec s... |
1311 |
alloclen += dst_exthdrlen; |
1da177e4c Linux-2.6.12-rc2 |
1312 1313 1314 1315 1316 1317 |
/* * The last fragment gets additional space at tail. * Note: we overallocate on fragments with MSG_MODE * because we have no idea if we're the last one. */ if (datalen == length + fraggap) |
d8d1f30b9 net-next: remove ... |
1318 |
alloclen += rt->dst.trailer_len; |
1da177e4c Linux-2.6.12-rc2 |
1319 1320 1321 |
/* * We just reserve space for fragment header. |
1ab1457c4 [NET] IPV6: Fix w... |
1322 |
* Note: this may be overallocation if the message |
1da177e4c Linux-2.6.12-rc2 |
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 |
* (without MSG_MORE) fits into the MTU. */ alloclen += sizeof(struct frag_hdr); if (transhdrlen) { skb = sock_alloc_send_skb(sk, alloclen + hh_len, (flags & MSG_DONTWAIT), &err); } else { skb = NULL; if (atomic_read(&sk->sk_wmem_alloc) <= 2 * sk->sk_sndbuf) skb = sock_wmalloc(sk, alloclen + hh_len, 1, sk->sk_allocation); if (unlikely(skb == NULL)) err = -ENOBUFS; |
a693e6989 net: TX timestamp... |
1340 1341 1342 1343 1344 1345 |
else { /* Only the initial fragment * is time stamped. */ tx_flags = 0; } |
1da177e4c Linux-2.6.12-rc2 |
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 |
} if (skb == NULL) goto error; /* * Fill in the control structures */ skb->ip_summed = csummode; skb->csum = 0; /* reserve for fragmentation */ skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); |
a693e6989 net: TX timestamp... |
1356 1357 |
if (sk->sk_type == SOCK_DGRAM) skb_shinfo(skb)->tx_flags = tx_flags; |
1da177e4c Linux-2.6.12-rc2 |
1358 1359 1360 |
/* * Find where to start putting bytes */ |
299b07676 ipv6: Fix IPsec s... |
1361 1362 1363 |
data = skb_put(skb, fraglen + dst_exthdrlen); skb_set_network_header(skb, exthdrlen + dst_exthdrlen); data += fragheaderlen + dst_exthdrlen; |
b0e380b1d [SK_BUFF]: unions... |
1364 1365 |
skb->transport_header = (skb->network_header + fragheaderlen); |
1da177e4c Linux-2.6.12-rc2 |
1366 1367 1368 1369 1370 1371 1372 |
if (fraggap) { skb->csum = skb_copy_and_csum_bits( skb_prev, maxfraglen, data + transhdrlen, fraggap, 0); skb_prev->csum = csum_sub(skb_prev->csum, skb->csum); data += fraggap; |
e9fa4f7bd [INET]: Use pskb_... |
1373 |
pskb_trim_unique(skb_prev, maxfraglen); |
1da177e4c Linux-2.6.12-rc2 |
1374 1375 |
} copy = datalen - transhdrlen - fraggap; |
299b07676 ipv6: Fix IPsec s... |
1376 |
|
1da177e4c Linux-2.6.12-rc2 |
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 |
if (copy < 0) { err = -EINVAL; kfree_skb(skb); goto error; } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { err = -EFAULT; kfree_skb(skb); goto error; } offset += copy; length -= datalen - fraggap; transhdrlen = 0; exthdrlen = 0; |
299b07676 ipv6: Fix IPsec s... |
1391 |
dst_exthdrlen = 0; |
1da177e4c Linux-2.6.12-rc2 |
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 |
csummode = CHECKSUM_NONE; /* * Put the packet on the pending queue */ __skb_queue_tail(&sk->sk_write_queue, skb); continue; } if (copy > length) copy = length; |
d8d1f30b9 net-next: remove ... |
1403 |
if (!(rt->dst.dev->features&NETIF_F_SG)) { |
1da177e4c Linux-2.6.12-rc2 |
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 |
unsigned int off; off = skb->len; if (getfrag(from, skb_put(skb, copy), offset, copy, off, skb) < 0) { __skb_trim(skb, off); err = -EFAULT; goto error; } } else { int i = skb_shinfo(skb)->nr_frags; skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; struct page *page = sk->sk_sndmsg_page; int off = sk->sk_sndmsg_off; unsigned int left; if (page && (left = PAGE_SIZE - off) > 0) { if (copy >= left) copy = left; |
408dadf03 net: ipv6: conver... |
1423 |
if (page != skb_frag_page(frag)) { |
1da177e4c Linux-2.6.12-rc2 |
1424 1425 1426 1427 |
if (i == MAX_SKB_FRAGS) { err = -EMSGSIZE; goto error; } |
1da177e4c Linux-2.6.12-rc2 |
1428 |
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0); |
408dadf03 net: ipv6: conver... |
1429 |
skb_frag_ref(skb, i); |
1da177e4c Linux-2.6.12-rc2 |
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 |
frag = &skb_shinfo(skb)->frags[i]; } } else if(i < MAX_SKB_FRAGS) { if (copy > PAGE_SIZE) copy = PAGE_SIZE; page = alloc_pages(sk->sk_allocation, 0); if (page == NULL) { err = -ENOMEM; goto error; } sk->sk_sndmsg_page = page; sk->sk_sndmsg_off = 0; skb_fill_page_desc(skb, i, page, 0, 0); frag = &skb_shinfo(skb)->frags[i]; |
1da177e4c Linux-2.6.12-rc2 |
1445 1446 1447 1448 |
} else { err = -EMSGSIZE; goto error; } |
9e903e085 net: add skb frag... |
1449 1450 |
if (getfrag(from, skb_frag_address(frag) + skb_frag_size(frag), |
408dadf03 net: ipv6: conver... |
1451 |
offset, copy, skb->len, skb) < 0) { |
1da177e4c Linux-2.6.12-rc2 |
1452 1453 1454 1455 |
err = -EFAULT; goto error; } sk->sk_sndmsg_off += copy; |
9e903e085 net: add skb frag... |
1456 |
skb_frag_size_add(frag, copy); |
1da177e4c Linux-2.6.12-rc2 |
1457 1458 |
skb->len += copy; skb->data_len += copy; |
f945fa7ad [INET]: Fix trues... |
1459 1460 |
skb->truesize += copy; atomic_add(copy, &sk->sk_wmem_alloc); |
1da177e4c Linux-2.6.12-rc2 |
1461 1462 1463 1464 1465 1466 |
} offset += copy; length -= copy; } return 0; error: |
bdc712b4c inet: Decrease ov... |
1467 |
cork->length -= length; |
3bd653c84 netns: add net pa... |
1468 |
IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
1469 1470 |
return err; } |
bf138862b [IPV6]: Consolida... |
1471 1472 |
static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) { |
0178b695f ipv6: Copy cork o... |
1473 1474 1475 1476 1477 1478 1479 1480 |
if (np->cork.opt) { kfree(np->cork.opt->dst0opt); kfree(np->cork.opt->dst1opt); kfree(np->cork.opt->hopopt); kfree(np->cork.opt->srcrt); kfree(np->cork.opt); np->cork.opt = NULL; } |
bdc712b4c inet: Decrease ov... |
1481 1482 1483 1484 |
if (inet->cork.base.dst) { dst_release(inet->cork.base.dst); inet->cork.base.dst = NULL; inet->cork.base.flags &= ~IPCORK_ALLFRAG; |
bf138862b [IPV6]: Consolida... |
1485 1486 1487 |
} memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); } |
1da177e4c Linux-2.6.12-rc2 |
1488 1489 1490 1491 1492 1493 1494 |
int ip6_push_pending_frames(struct sock *sk) { struct sk_buff *skb, *tmp_skb; struct sk_buff **tail_skb; struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); |
3bd653c84 netns: add net pa... |
1495 |
struct net *net = sock_net(sk); |
1da177e4c Linux-2.6.12-rc2 |
1496 1497 |
struct ipv6hdr *hdr; struct ipv6_txoptions *opt = np->cork.opt; |
bdc712b4c inet: Decrease ov... |
1498 |
struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; |
4c9483b2f ipv6: Convert to ... |
1499 1500 |
struct flowi6 *fl6 = &inet->cork.fl.u.ip6; unsigned char proto = fl6->flowi6_proto; |
1da177e4c Linux-2.6.12-rc2 |
1501 1502 1503 1504 1505 1506 1507 |
int err = 0; if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) goto out; tail_skb = &(skb_shinfo(skb)->frag_list); /* move skb->data to ip header from ext header */ |
d56f90a7c [SK_BUFF]: Introd... |
1508 |
if (skb->data < skb_network_header(skb)) |
bbe735e42 [SK_BUFF]: Introd... |
1509 |
__skb_pull(skb, skb_network_offset(skb)); |
1da177e4c Linux-2.6.12-rc2 |
1510 |
while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { |
cfe1fc775 [SK_BUFF]: Introd... |
1511 |
__skb_pull(tmp_skb, skb_network_header_len(skb)); |
1da177e4c Linux-2.6.12-rc2 |
1512 1513 1514 1515 |
*tail_skb = tmp_skb; tail_skb = &(tmp_skb->next); skb->len += tmp_skb->len; skb->data_len += tmp_skb->len; |
1da177e4c Linux-2.6.12-rc2 |
1516 |
skb->truesize += tmp_skb->truesize; |
1da177e4c Linux-2.6.12-rc2 |
1517 1518 |
tmp_skb->destructor = NULL; tmp_skb->sk = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1519 |
} |
28a89453b [IPV6]: Fix IPsec... |
1520 |
/* Allow local fragmentation. */ |
b5c15fc00 [IPV6]: Fix rever... |
1521 |
if (np->pmtudisc < IPV6_PMTUDISC_DO) |
28a89453b [IPV6]: Fix IPsec... |
1522 |
skb->local_df = 1; |
4e3fd7a06 net: remove ipv6_... |
1523 |
*final_dst = fl6->daddr; |
cfe1fc775 [SK_BUFF]: Introd... |
1524 |
__skb_pull(skb, skb_network_header_len(skb)); |
1da177e4c Linux-2.6.12-rc2 |
1525 1526 1527 1528 |
if (opt && opt->opt_flen) ipv6_push_frag_opts(skb, opt, &proto); if (opt && opt->opt_nflen) ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst); |
e2d1bca7e [SK_BUFF]: Use sk... |
1529 1530 |
skb_push(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); |
0660e03f6 [SK_BUFF]: Introd... |
1531 |
hdr = ipv6_hdr(skb); |
1ab1457c4 [NET] IPV6: Fix w... |
1532 |
|
4c9483b2f ipv6: Convert to ... |
1533 |
*(__be32*)hdr = fl6->flowlabel | |
41a1f8ea4 [IPV6]: Support I... |
1534 |
htonl(0x60000000 | ((int)np->cork.tclass << 20)); |
1da177e4c Linux-2.6.12-rc2 |
1535 |
|
1da177e4c Linux-2.6.12-rc2 |
1536 1537 |
hdr->hop_limit = np->cork.hop_limit; hdr->nexthdr = proto; |
4e3fd7a06 net: remove ipv6_... |
1538 1539 |
hdr->saddr = fl6->saddr; hdr->daddr = *final_dst; |
1da177e4c Linux-2.6.12-rc2 |
1540 |
|
a2c2064f7 [IPV6]: Set skb->... |
1541 |
skb->priority = sk->sk_priority; |
4a19ec580 [NET]: Introducin... |
1542 |
skb->mark = sk->sk_mark; |
a2c2064f7 [IPV6]: Set skb->... |
1543 |
|
d8d1f30b9 net-next: remove ... |
1544 |
skb_dst_set(skb, dst_clone(&rt->dst)); |
edf391ff1 snmp: add missing... |
1545 |
IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); |
14878f75a [IPV6]: Add ICMPM... |
1546 |
if (proto == IPPROTO_ICMPV6) { |
adf30907d net: skb->dst acc... |
1547 |
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
14878f75a [IPV6]: Add ICMPM... |
1548 |
|
5a57d4c7f ipv6: added net a... |
1549 |
ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type); |
e41b5368e ipv6: added net a... |
1550 |
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); |
14878f75a [IPV6]: Add ICMPM... |
1551 |
} |
ef76bc23e [IPV6]: Add ip6_l... |
1552 |
err = ip6_local_out(skb); |
1da177e4c Linux-2.6.12-rc2 |
1553 1554 |
if (err) { if (err > 0) |
6ce9e7b5f ip: Report qdisc ... |
1555 |
err = net_xmit_errno(err); |
1da177e4c Linux-2.6.12-rc2 |
1556 1557 1558 1559 1560 |
if (err) goto error; } out: |
bf138862b [IPV6]: Consolida... |
1561 |
ip6_cork_release(inet, np); |
1da177e4c Linux-2.6.12-rc2 |
1562 1563 |
return err; error: |
062549149 ipv6: ip6_push_pe... |
1564 |
IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
1565 1566 1567 1568 1569 |
goto out; } void ip6_flush_pending_frames(struct sock *sk) { |
1da177e4c Linux-2.6.12-rc2 |
1570 1571 1572 |
struct sk_buff *skb; while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { |
adf30907d net: skb->dst acc... |
1573 1574 |
if (skb_dst(skb)) IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), |
e1f52208b [IPv6]: Fix NULL ... |
1575 |
IPSTATS_MIB_OUTDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
1576 1577 |
kfree_skb(skb); } |
bf138862b [IPV6]: Consolida... |
1578 |
ip6_cork_release(inet_sk(sk), inet6_sk(sk)); |
1da177e4c Linux-2.6.12-rc2 |
1579 |
} |