|
@@ -195,37 +195,37 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
|
|
|
const struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
struct in6_addr *first_hop = &fl6->daddr;
|
|
|
struct dst_entry *dst = skb_dst(skb);
|
|
|
+ unsigned int head_room;
|
|
|
struct ipv6hdr *hdr;
|
|
|
u8 proto = fl6->flowi6_proto;
|
|
|
int seg_len = skb->len;
|
|
|
int hlimit = -1;
|
|
|
u32 mtu;
|
|
|
|
|
|
- if (opt) {
|
|
|
- unsigned int head_room;
|
|
|
+ head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
|
|
|
+ if (opt)
|
|
|
+ head_room += opt->opt_nflen + opt->opt_flen;
|
|
|
|
|
|
- /* 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);
|
|
|
- if (!skb2) {
|
|
|
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
|
|
- IPSTATS_MIB_OUTDISCARDS);
|
|
|
- kfree_skb(skb);
|
|
|
- return -ENOBUFS;
|
|
|
- }
|
|
|
- if (skb->sk)
|
|
|
- skb_set_owner_w(skb2, skb->sk);
|
|
|
- consume_skb(skb);
|
|
|
- skb = skb2;
|
|
|
+ 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;
|
|
|
}
|
|
|
+ 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;
|
|
|
+
|
|
|
if (opt->opt_flen)
|
|
|
ipv6_push_frag_opts(skb, opt, &proto);
|
|
|
+
|
|
|
if (opt->opt_nflen)
|
|
|
ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
|
|
|
&fl6->saddr);
|