diff options
-rw-r--r-- | include/linux/in6.h | 2 | ||||
-rw-r--r-- | include/linux/ipv6.h | 5 | ||||
-rw-r--r-- | include/net/ipv6.h | 1 | ||||
-rw-r--r-- | include/net/transp_v6.h | 2 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 25 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 15 | ||||
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 24 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 22 | ||||
-rw-r--r-- | net/ipv6/raw.c | 14 | ||||
-rw-r--r-- | net/ipv6/udp.c | 16 |
11 files changed, 104 insertions, 24 deletions
diff --git a/include/linux/in6.h b/include/linux/in6.h index c11022f2f2ac..bd32b79d6295 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h | |||
@@ -219,9 +219,7 @@ struct in6_flowlabel_req | |||
219 | #define IPV6_DSTOPTS 63 | 219 | #define IPV6_DSTOPTS 63 |
220 | #define IPV6_RECVHOPLIMIT 64 | 220 | #define IPV6_RECVHOPLIMIT 64 |
221 | #define IPV6_HOPLIMIT 65 | 221 | #define IPV6_HOPLIMIT 65 |
222 | #if 0 | ||
223 | #define IPV6_RECVTCLASS 66 | 222 | #define IPV6_RECVTCLASS 66 |
224 | #define IPV6_TCLASS 67 | 223 | #define IPV6_TCLASS 67 |
225 | #endif | ||
226 | 224 | ||
227 | #endif | 225 | #endif |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 2581f1c94df5..6c5f7b39a4b0 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -245,7 +245,8 @@ struct ipv6_pinfo { | |||
245 | ohopopts:1, | 245 | ohopopts:1, |
246 | dstopts:1, | 246 | dstopts:1, |
247 | odstopts:1, | 247 | odstopts:1, |
248 | rxflow:1; | 248 | rxflow:1, |
249 | rxtclass:1; | ||
249 | } bits; | 250 | } bits; |
250 | __u16 all; | 251 | __u16 all; |
251 | } rxopt; | 252 | } rxopt; |
@@ -256,6 +257,7 @@ struct ipv6_pinfo { | |||
256 | sndflow:1, | 257 | sndflow:1, |
257 | pmtudisc:2, | 258 | pmtudisc:2, |
258 | ipv6only:1; | 259 | ipv6only:1; |
260 | __u8 tclass; | ||
259 | 261 | ||
260 | __u32 dst_cookie; | 262 | __u32 dst_cookie; |
261 | 263 | ||
@@ -269,6 +271,7 @@ struct ipv6_pinfo { | |||
269 | struct ipv6_txoptions *opt; | 271 | struct ipv6_txoptions *opt; |
270 | struct rt6_info *rt; | 272 | struct rt6_info *rt; |
271 | int hop_limit; | 273 | int hop_limit; |
274 | int tclass; | ||
272 | } cork; | 275 | } cork; |
273 | }; | 276 | }; |
274 | 277 | ||
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8a9fe9434e94..65ec86678a08 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -377,6 +377,7 @@ extern int ip6_append_data(struct sock *sk, | |||
377 | int length, | 377 | int length, |
378 | int transhdrlen, | 378 | int transhdrlen, |
379 | int hlimit, | 379 | int hlimit, |
380 | int tclass, | ||
380 | struct ipv6_txoptions *opt, | 381 | struct ipv6_txoptions *opt, |
381 | struct flowi *fl, | 382 | struct flowi *fl, |
382 | struct rt6_info *rt, | 383 | struct rt6_info *rt, |
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 8b075ab7a26c..4e86f2de6638 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h | |||
@@ -37,7 +37,7 @@ extern int datagram_recv_ctl(struct sock *sk, | |||
37 | extern int datagram_send_ctl(struct msghdr *msg, | 37 | extern int datagram_send_ctl(struct msghdr *msg, |
38 | struct flowi *fl, | 38 | struct flowi *fl, |
39 | struct ipv6_txoptions *opt, | 39 | struct ipv6_txoptions *opt, |
40 | int *hlimit); | 40 | int *hlimit, int *tclass); |
41 | 41 | ||
42 | #define LOOPBACK4_IPV6 __constant_htonl(0x7f000006) | 42 | #define LOOPBACK4_IPV6 __constant_htonl(0x7f000006) |
43 | 43 | ||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 832476bbc5cb..157cec648032 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -390,6 +390,11 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
390 | put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); | 390 | put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); |
391 | } | 391 | } |
392 | 392 | ||
393 | if (np->rxopt.bits.rxtclass) { | ||
394 | int tclass = (ntohl(*(u32 *)skb->nh.ipv6h) >> 20) & 0xff; | ||
395 | put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); | ||
396 | } | ||
397 | |||
393 | if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { | 398 | if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) { |
394 | u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK; | 399 | u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK; |
395 | put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); | 400 | put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); |
@@ -479,7 +484,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
479 | 484 | ||
480 | int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | 485 | int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, |
481 | struct ipv6_txoptions *opt, | 486 | struct ipv6_txoptions *opt, |
482 | int *hlimit) | 487 | int *hlimit, int *tclass) |
483 | { | 488 | { |
484 | struct in6_pktinfo *src_info; | 489 | struct in6_pktinfo *src_info; |
485 | struct cmsghdr *cmsg; | 490 | struct cmsghdr *cmsg; |
@@ -682,6 +687,24 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
682 | *hlimit = *(int *)CMSG_DATA(cmsg); | 687 | *hlimit = *(int *)CMSG_DATA(cmsg); |
683 | break; | 688 | break; |
684 | 689 | ||
690 | case IPV6_TCLASS: | ||
691 | { | ||
692 | int tc; | ||
693 | |||
694 | err = -EINVAL; | ||
695 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { | ||
696 | goto exit_f; | ||
697 | } | ||
698 | |||
699 | tc = *(int *)CMSG_DATA(cmsg); | ||
700 | if (tc < 0 || tc > 0xff) | ||
701 | goto exit_f; | ||
702 | |||
703 | err = 0; | ||
704 | *tclass = tc; | ||
705 | |||
706 | break; | ||
707 | } | ||
685 | default: | 708 | default: |
686 | LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", | 709 | LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", |
687 | cmsg->cmsg_type); | 710 | cmsg->cmsg_type); |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index fa8f1bb0aa52..34e99c55e856 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -287,7 +287,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
287 | int iif = 0; | 287 | int iif = 0; |
288 | int addr_type = 0; | 288 | int addr_type = 0; |
289 | int len; | 289 | int len; |
290 | int hlimit; | 290 | int hlimit, tclass; |
291 | int err = 0; | 291 | int err = 0; |
292 | 292 | ||
293 | if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) | 293 | if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) |
@@ -385,6 +385,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
385 | if (hlimit < 0) | 385 | if (hlimit < 0) |
386 | hlimit = ipv6_get_hoplimit(dst->dev); | 386 | hlimit = ipv6_get_hoplimit(dst->dev); |
387 | 387 | ||
388 | tclass = np->cork.tclass; | ||
389 | if (tclass < 0) | ||
390 | tclass = 0; | ||
391 | |||
388 | msg.skb = skb; | 392 | msg.skb = skb; |
389 | msg.offset = skb->nh.raw - skb->data; | 393 | msg.offset = skb->nh.raw - skb->data; |
390 | 394 | ||
@@ -400,7 +404,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
400 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, | 404 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, |
401 | len + sizeof(struct icmp6hdr), | 405 | len + sizeof(struct icmp6hdr), |
402 | sizeof(struct icmp6hdr), | 406 | sizeof(struct icmp6hdr), |
403 | hlimit, NULL, &fl, (struct rt6_info*)dst, | 407 | hlimit, tclass, NULL, &fl, (struct rt6_info*)dst, |
404 | MSG_DONTWAIT); | 408 | MSG_DONTWAIT); |
405 | if (err) { | 409 | if (err) { |
406 | ip6_flush_pending_frames(sk); | 410 | ip6_flush_pending_frames(sk); |
@@ -434,6 +438,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
434 | struct dst_entry *dst; | 438 | struct dst_entry *dst; |
435 | int err = 0; | 439 | int err = 0; |
436 | int hlimit; | 440 | int hlimit; |
441 | int tclass; | ||
437 | 442 | ||
438 | saddr = &skb->nh.ipv6h->daddr; | 443 | saddr = &skb->nh.ipv6h->daddr; |
439 | 444 | ||
@@ -475,13 +480,17 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
475 | if (hlimit < 0) | 480 | if (hlimit < 0) |
476 | hlimit = ipv6_get_hoplimit(dst->dev); | 481 | hlimit = ipv6_get_hoplimit(dst->dev); |
477 | 482 | ||
483 | tclass = np->cork.tclass; | ||
484 | if (tclass < 0) | ||
485 | tclass = 0; | ||
486 | |||
478 | idev = in6_dev_get(skb->dev); | 487 | idev = in6_dev_get(skb->dev); |
479 | 488 | ||
480 | msg.skb = skb; | 489 | msg.skb = skb; |
481 | msg.offset = 0; | 490 | msg.offset = 0; |
482 | 491 | ||
483 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), | 492 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), |
484 | sizeof(struct icmp6hdr), hlimit, NULL, &fl, | 493 | sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl, |
485 | (struct rt6_info*)dst, MSG_DONTWAIT); | 494 | (struct rt6_info*)dst, MSG_DONTWAIT); |
486 | 495 | ||
487 | if (err) { | 496 | if (err) { |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 2d5ce376c265..a7db762de14a 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -314,7 +314,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * | |||
314 | msg.msg_control = (void*)(fl->opt+1); | 314 | msg.msg_control = (void*)(fl->opt+1); |
315 | flowi.oif = 0; | 315 | flowi.oif = 0; |
316 | 316 | ||
317 | err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk); | 317 | err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk, &junk); |
318 | if (err) | 318 | if (err) |
319 | goto done; | 319 | goto done; |
320 | err = -EINVAL; | 320 | err = -EINVAL; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 01ef94f7c7f1..2f589f24c093 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -166,7 +166,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
166 | struct ipv6hdr *hdr; | 166 | struct ipv6hdr *hdr; |
167 | u8 proto = fl->proto; | 167 | u8 proto = fl->proto; |
168 | int seg_len = skb->len; | 168 | int seg_len = skb->len; |
169 | int hlimit; | 169 | int hlimit, tclass; |
170 | u32 mtu; | 170 | u32 mtu; |
171 | 171 | ||
172 | if (opt) { | 172 | if (opt) { |
@@ -202,7 +202,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
202 | * Fill in the IPv6 header | 202 | * Fill in the IPv6 header |
203 | */ | 203 | */ |
204 | 204 | ||
205 | *(u32*)hdr = htonl(0x60000000) | fl->fl6_flowlabel; | ||
206 | hlimit = -1; | 205 | hlimit = -1; |
207 | if (np) | 206 | if (np) |
208 | hlimit = np->hop_limit; | 207 | hlimit = np->hop_limit; |
@@ -211,6 +210,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
211 | if (hlimit < 0) | 210 | if (hlimit < 0) |
212 | hlimit = ipv6_get_hoplimit(dst->dev); | 211 | hlimit = ipv6_get_hoplimit(dst->dev); |
213 | 212 | ||
213 | tclass = -1; | ||
214 | if (np) | ||
215 | tclass = np->tclass; | ||
216 | if (tclass < 0) | ||
217 | tclass = 0; | ||
218 | |||
219 | *(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; | ||
220 | |||
214 | hdr->payload_len = htons(seg_len); | 221 | hdr->payload_len = htons(seg_len); |
215 | hdr->nexthdr = proto; | 222 | hdr->nexthdr = proto; |
216 | hdr->hop_limit = hlimit; | 223 | hdr->hop_limit = hlimit; |
@@ -762,10 +769,11 @@ out_err_release: | |||
762 | return err; | 769 | return err; |
763 | } | 770 | } |
764 | 771 | ||
765 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), | 772 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, |
766 | void *from, int length, int transhdrlen, | 773 | int offset, int len, int odd, struct sk_buff *skb), |
767 | int hlimit, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt, | 774 | void *from, int length, int transhdrlen, |
768 | unsigned int flags) | 775 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, |
776 | struct rt6_info *rt, unsigned int flags) | ||
769 | { | 777 | { |
770 | struct inet_sock *inet = inet_sk(sk); | 778 | struct inet_sock *inet = inet_sk(sk); |
771 | struct ipv6_pinfo *np = inet6_sk(sk); | 779 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -803,6 +811,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse | |||
803 | np->cork.rt = rt; | 811 | np->cork.rt = rt; |
804 | inet->cork.fl = *fl; | 812 | inet->cork.fl = *fl; |
805 | np->cork.hop_limit = hlimit; | 813 | np->cork.hop_limit = hlimit; |
814 | np->cork.tclass = tclass; | ||
806 | inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path); | 815 | inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path); |
807 | if (dst_allfrag(rt->u.dst.path)) | 816 | if (dst_allfrag(rt->u.dst.path)) |
808 | inet->cork.flags |= IPCORK_ALLFRAG; | 817 | inet->cork.flags |= IPCORK_ALLFRAG; |
@@ -1084,7 +1093,8 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1084 | 1093 | ||
1085 | skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); | 1094 | skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); |
1086 | 1095 | ||
1087 | *(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000); | 1096 | *(u32*)hdr = fl->fl6_flowlabel | |
1097 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); | ||
1088 | 1098 | ||
1089 | if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) | 1099 | if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) |
1090 | hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); | 1100 | hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index dc1d9914bf7d..8567873d0dd8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -264,6 +264,18 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
264 | retv = 0; | 264 | retv = 0; |
265 | break; | 265 | break; |
266 | 266 | ||
267 | case IPV6_TCLASS: | ||
268 | if (val < 0 || val > 0xff) | ||
269 | goto e_inval; | ||
270 | np->tclass = val; | ||
271 | retv = 0; | ||
272 | break; | ||
273 | |||
274 | case IPV6_RECVTCLASS: | ||
275 | np->rxopt.bits.rxtclass = valbool; | ||
276 | retv = 0; | ||
277 | break; | ||
278 | |||
267 | case IPV6_FLOWINFO: | 279 | case IPV6_FLOWINFO: |
268 | np->rxopt.bits.rxflow = valbool; | 280 | np->rxopt.bits.rxflow = valbool; |
269 | retv = 0; | 281 | retv = 0; |
@@ -364,7 +376,7 @@ sticky_done: | |||
364 | msg.msg_controllen = optlen; | 376 | msg.msg_controllen = optlen; |
365 | msg.msg_control = (void*)(opt+1); | 377 | msg.msg_control = (void*)(opt+1); |
366 | 378 | ||
367 | retv = datagram_send_ctl(&msg, &fl, opt, &junk); | 379 | retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk); |
368 | if (retv) | 380 | if (retv) |
369 | goto done; | 381 | goto done; |
370 | update: | 382 | update: |
@@ -787,6 +799,14 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
787 | val = np->rxopt.bits.odstopts; | 799 | val = np->rxopt.bits.odstopts; |
788 | break; | 800 | break; |
789 | 801 | ||
802 | case IPV6_TCLASS: | ||
803 | val = np->tclass; | ||
804 | break; | ||
805 | |||
806 | case IPV6_RECVTCLASS: | ||
807 | val = np->rxopt.bits.rxtclass; | ||
808 | break; | ||
809 | |||
790 | case IPV6_FLOWINFO: | 810 | case IPV6_FLOWINFO: |
791 | val = np->rxopt.bits.rxflow; | 811 | val = np->rxopt.bits.rxflow; |
792 | break; | 812 | break; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e527a1652d7c..2ad37893334a 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -655,6 +655,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
655 | struct flowi fl; | 655 | struct flowi fl; |
656 | int addr_len = msg->msg_namelen; | 656 | int addr_len = msg->msg_namelen; |
657 | int hlimit = -1; | 657 | int hlimit = -1; |
658 | int tclass = -1; | ||
658 | u16 proto; | 659 | u16 proto; |
659 | int err; | 660 | int err; |
660 | 661 | ||
@@ -740,7 +741,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
740 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 741 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
741 | opt->tot_len = sizeof(struct ipv6_txoptions); | 742 | opt->tot_len = sizeof(struct ipv6_txoptions); |
742 | 743 | ||
743 | err = datagram_send_ctl(msg, &fl, opt, &hlimit); | 744 | err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); |
744 | if (err < 0) { | 745 | if (err < 0) { |
745 | fl6_sock_release(flowlabel); | 746 | fl6_sock_release(flowlabel); |
746 | return err; | 747 | return err; |
@@ -797,6 +798,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
797 | hlimit = ipv6_get_hoplimit(dst->dev); | 798 | hlimit = ipv6_get_hoplimit(dst->dev); |
798 | } | 799 | } |
799 | 800 | ||
801 | if (tclass < 0) { | ||
802 | tclass = np->cork.tclass; | ||
803 | if (tclass < 0) | ||
804 | tclass = 0; | ||
805 | } | ||
806 | |||
800 | if (msg->msg_flags&MSG_CONFIRM) | 807 | if (msg->msg_flags&MSG_CONFIRM) |
801 | goto do_confirm; | 808 | goto do_confirm; |
802 | 809 | ||
@@ -805,8 +812,9 @@ back_from_confirm: | |||
805 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags); | 812 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags); |
806 | } else { | 813 | } else { |
807 | lock_sock(sk); | 814 | lock_sock(sk); |
808 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, | 815 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, |
809 | hlimit, opt, &fl, (struct rt6_info*)dst, msg->msg_flags); | 816 | len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst, |
817 | msg->msg_flags); | ||
810 | 818 | ||
811 | if (err) | 819 | if (err) |
812 | ip6_flush_pending_frames(sk); | 820 | ip6_flush_pending_frames(sk); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index aa6eaf3f18a6..dbd18a9d1669 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -637,6 +637,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
637 | int addr_len = msg->msg_namelen; | 637 | int addr_len = msg->msg_namelen; |
638 | int ulen = len; | 638 | int ulen = len; |
639 | int hlimit = -1; | 639 | int hlimit = -1; |
640 | int tclass = -1; | ||
640 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 641 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
641 | int err; | 642 | int err; |
642 | 643 | ||
@@ -758,7 +759,7 @@ do_udp_sendmsg: | |||
758 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 759 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
759 | opt->tot_len = sizeof(*opt); | 760 | opt->tot_len = sizeof(*opt); |
760 | 761 | ||
761 | err = datagram_send_ctl(msg, fl, opt, &hlimit); | 762 | err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass); |
762 | if (err < 0) { | 763 | if (err < 0) { |
763 | fl6_sock_release(flowlabel); | 764 | fl6_sock_release(flowlabel); |
764 | return err; | 765 | return err; |
@@ -814,6 +815,12 @@ do_udp_sendmsg: | |||
814 | hlimit = ipv6_get_hoplimit(dst->dev); | 815 | hlimit = ipv6_get_hoplimit(dst->dev); |
815 | } | 816 | } |
816 | 817 | ||
818 | if (tclass < 0) { | ||
819 | tclass = np->tclass; | ||
820 | if (tclass < 0) | ||
821 | tclass = 0; | ||
822 | } | ||
823 | |||
817 | if (msg->msg_flags&MSG_CONFIRM) | 824 | if (msg->msg_flags&MSG_CONFIRM) |
818 | goto do_confirm; | 825 | goto do_confirm; |
819 | back_from_confirm: | 826 | back_from_confirm: |
@@ -833,9 +840,10 @@ back_from_confirm: | |||
833 | 840 | ||
834 | do_append_data: | 841 | do_append_data: |
835 | up->len += ulen; | 842 | up->len += ulen; |
836 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), | 843 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, |
837 | hlimit, opt, fl, (struct rt6_info*)dst, | 844 | sizeof(struct udphdr), hlimit, tclass, opt, fl, |
838 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 845 | (struct rt6_info*)dst, |
846 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | ||
839 | if (err) | 847 | if (err) |
840 | udp_v6_flush_pending_frames(sk); | 848 | udp_v6_flush_pending_frames(sk); |
841 | else if (!corkreq) | 849 | else if (!corkreq) |