diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 44 |
1 files changed, 15 insertions, 29 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 87f8419a68fd..cd48801a8d6f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -57,18 +57,6 @@ | |||
57 | 57 | ||
58 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); | 58 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); |
59 | 59 | ||
60 | static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr) | ||
61 | { | ||
62 | static u32 ipv6_fragmentation_id = 1; | ||
63 | static DEFINE_SPINLOCK(ip6_id_lock); | ||
64 | |||
65 | spin_lock_bh(&ip6_id_lock); | ||
66 | fhdr->identification = htonl(ipv6_fragmentation_id); | ||
67 | if (++ipv6_fragmentation_id == 0) | ||
68 | ipv6_fragmentation_id = 1; | ||
69 | spin_unlock_bh(&ip6_id_lock); | ||
70 | } | ||
71 | |||
72 | int __ip6_local_out(struct sk_buff *skb) | 60 | int __ip6_local_out(struct sk_buff *skb) |
73 | { | 61 | { |
74 | int len; | 62 | int len; |
@@ -206,7 +194,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
206 | struct ipv6hdr *hdr; | 194 | struct ipv6hdr *hdr; |
207 | u8 proto = fl->proto; | 195 | u8 proto = fl->proto; |
208 | int seg_len = skb->len; | 196 | int seg_len = skb->len; |
209 | int hlimit, tclass; | 197 | int hlimit = -1; |
198 | int tclass = 0; | ||
210 | u32 mtu; | 199 | u32 mtu; |
211 | 200 | ||
212 | if (opt) { | 201 | if (opt) { |
@@ -249,19 +238,13 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
249 | /* | 238 | /* |
250 | * Fill in the IPv6 header | 239 | * Fill in the IPv6 header |
251 | */ | 240 | */ |
252 | 241 | if (np) { | |
253 | hlimit = -1; | 242 | tclass = np->tclass; |
254 | if (np) | ||
255 | hlimit = np->hop_limit; | 243 | hlimit = np->hop_limit; |
244 | } | ||
256 | if (hlimit < 0) | 245 | if (hlimit < 0) |
257 | hlimit = ip6_dst_hoplimit(dst); | 246 | hlimit = ip6_dst_hoplimit(dst); |
258 | 247 | ||
259 | tclass = -1; | ||
260 | if (np) | ||
261 | tclass = np->tclass; | ||
262 | if (tclass < 0) | ||
263 | tclass = 0; | ||
264 | |||
265 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; | 248 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; |
266 | 249 | ||
267 | hdr->payload_len = htons(seg_len); | 250 | hdr->payload_len = htons(seg_len); |
@@ -706,7 +689,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
706 | skb_reset_network_header(skb); | 689 | skb_reset_network_header(skb); |
707 | memcpy(skb_network_header(skb), tmp_hdr, hlen); | 690 | memcpy(skb_network_header(skb), tmp_hdr, hlen); |
708 | 691 | ||
709 | ipv6_select_ident(skb, fh); | 692 | ipv6_select_ident(fh); |
710 | fh->nexthdr = nexthdr; | 693 | fh->nexthdr = nexthdr; |
711 | fh->reserved = 0; | 694 | fh->reserved = 0; |
712 | fh->frag_off = htons(IP6_MF); | 695 | fh->frag_off = htons(IP6_MF); |
@@ -844,7 +827,7 @@ slow_path: | |||
844 | fh->nexthdr = nexthdr; | 827 | fh->nexthdr = nexthdr; |
845 | fh->reserved = 0; | 828 | fh->reserved = 0; |
846 | if (!frag_id) { | 829 | if (!frag_id) { |
847 | ipv6_select_ident(skb, fh); | 830 | ipv6_select_ident(fh); |
848 | frag_id = fh->identification; | 831 | frag_id = fh->identification; |
849 | } else | 832 | } else |
850 | fh->identification = frag_id; | 833 | fh->identification = frag_id; |
@@ -1087,11 +1070,13 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1087 | if (!err) { | 1070 | if (!err) { |
1088 | struct frag_hdr fhdr; | 1071 | struct frag_hdr fhdr; |
1089 | 1072 | ||
1090 | /* specify the length of each IP datagram fragment*/ | 1073 | /* Specify the length of each IPv6 datagram fragment. |
1091 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen - | 1074 | * It has to be a multiple of 8. |
1092 | sizeof(struct frag_hdr); | 1075 | */ |
1076 | skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - | ||
1077 | sizeof(struct frag_hdr)) & ~7; | ||
1093 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; | 1078 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
1094 | ipv6_select_ident(skb, &fhdr); | 1079 | ipv6_select_ident(&fhdr); |
1095 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; | 1080 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; |
1096 | __skb_queue_tail(&sk->sk_write_queue, skb); | 1081 | __skb_queue_tail(&sk->sk_write_queue, skb); |
1097 | 1082 | ||
@@ -1526,7 +1511,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1526 | err = ip6_local_out(skb); | 1511 | err = ip6_local_out(skb); |
1527 | if (err) { | 1512 | if (err) { |
1528 | if (err > 0) | 1513 | if (err > 0) |
1529 | err = np->recverr ? net_xmit_errno(err) : 0; | 1514 | err = net_xmit_errno(err); |
1530 | if (err) | 1515 | if (err) |
1531 | goto error; | 1516 | goto error; |
1532 | } | 1517 | } |
@@ -1535,6 +1520,7 @@ out: | |||
1535 | ip6_cork_release(inet, np); | 1520 | ip6_cork_release(inet, np); |
1536 | return err; | 1521 | return err; |
1537 | error: | 1522 | error: |
1523 | IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | ||
1538 | goto out; | 1524 | goto out; |
1539 | } | 1525 | } |
1540 | 1526 | ||