aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/datagram.c25
-rw-r--r--net/ipv6/icmp.c15
-rw-r--r--net/ipv6/ip6_flowlabel.c2
-rw-r--r--net/ipv6/ip6_output.c24
-rw-r--r--net/ipv6/ipv6_sockglue.c22
-rw-r--r--net/ipv6/raw.c14
-rw-r--r--net/ipv6/udp.c16
7 files changed, 98 insertions, 20 deletions
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
480int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, 485int 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
765int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), 772int 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;
370update: 382update:
@@ -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;
819back_from_confirm: 826back_from_confirm:
@@ -833,9 +840,10 @@ back_from_confirm:
833 840
834do_append_data: 841do_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)