[IPV6]: Support IPV6_{RECV,}TCLASS socket options / ancillary data.
Based on patch from David L Stevens <dlstevens@us.ibm.com> Signed-off-by: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
This commit is contained in:
parent
333fad5364
commit
41a1f8ea4f
11 changed files with 104 additions and 24 deletions
|
@ -219,9 +219,7 @@ struct in6_flowlabel_req
|
||||||
#define IPV6_DSTOPTS 63
|
#define IPV6_DSTOPTS 63
|
||||||
#define IPV6_RECVHOPLIMIT 64
|
#define IPV6_RECVHOPLIMIT 64
|
||||||
#define IPV6_HOPLIMIT 65
|
#define IPV6_HOPLIMIT 65
|
||||||
#if 0
|
|
||||||
#define IPV6_RECVTCLASS 66
|
#define IPV6_RECVTCLASS 66
|
||||||
#define IPV6_TCLASS 67
|
#define IPV6_TCLASS 67
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -245,7 +245,8 @@ struct ipv6_pinfo {
|
||||||
ohopopts:1,
|
ohopopts:1,
|
||||||
dstopts:1,
|
dstopts:1,
|
||||||
odstopts:1,
|
odstopts:1,
|
||||||
rxflow:1;
|
rxflow:1,
|
||||||
|
rxtclass:1;
|
||||||
} bits;
|
} bits;
|
||||||
__u16 all;
|
__u16 all;
|
||||||
} rxopt;
|
} rxopt;
|
||||||
|
@ -256,6 +257,7 @@ struct ipv6_pinfo {
|
||||||
sndflow:1,
|
sndflow:1,
|
||||||
pmtudisc:2,
|
pmtudisc:2,
|
||||||
ipv6only:1;
|
ipv6only:1;
|
||||||
|
__u8 tclass;
|
||||||
|
|
||||||
__u32 dst_cookie;
|
__u32 dst_cookie;
|
||||||
|
|
||||||
|
@ -269,6 +271,7 @@ struct ipv6_pinfo {
|
||||||
struct ipv6_txoptions *opt;
|
struct ipv6_txoptions *opt;
|
||||||
struct rt6_info *rt;
|
struct rt6_info *rt;
|
||||||
int hop_limit;
|
int hop_limit;
|
||||||
|
int tclass;
|
||||||
} cork;
|
} cork;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -377,6 +377,7 @@ extern int ip6_append_data(struct sock *sk,
|
||||||
int length,
|
int length,
|
||||||
int transhdrlen,
|
int transhdrlen,
|
||||||
int hlimit,
|
int hlimit,
|
||||||
|
int tclass,
|
||||||
struct ipv6_txoptions *opt,
|
struct ipv6_txoptions *opt,
|
||||||
struct flowi *fl,
|
struct flowi *fl,
|
||||||
struct rt6_info *rt,
|
struct rt6_info *rt,
|
||||||
|
|
|
@ -37,7 +37,7 @@ extern int datagram_recv_ctl(struct sock *sk,
|
||||||
extern int datagram_send_ctl(struct msghdr *msg,
|
extern int datagram_send_ctl(struct msghdr *msg,
|
||||||
struct flowi *fl,
|
struct flowi *fl,
|
||||||
struct ipv6_txoptions *opt,
|
struct ipv6_txoptions *opt,
|
||||||
int *hlimit);
|
int *hlimit, int *tclass);
|
||||||
|
|
||||||
#define LOOPBACK4_IPV6 __constant_htonl(0x7f000006)
|
#define LOOPBACK4_IPV6 __constant_htonl(0x7f000006)
|
||||||
|
|
||||||
|
|
|
@ -390,6 +390,11 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
|
||||||
put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
|
put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (np->rxopt.bits.rxtclass) {
|
||||||
|
int tclass = (ntohl(*(u32 *)skb->nh.ipv6h) >> 20) & 0xff;
|
||||||
|
put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
|
||||||
|
}
|
||||||
|
|
||||||
if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
|
if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
|
||||||
u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
|
u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
|
||||||
put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
|
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)
|
||||||
|
|
||||||
int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
|
int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
|
||||||
struct ipv6_txoptions *opt,
|
struct ipv6_txoptions *opt,
|
||||||
int *hlimit)
|
int *hlimit, int *tclass)
|
||||||
{
|
{
|
||||||
struct in6_pktinfo *src_info;
|
struct in6_pktinfo *src_info;
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
|
@ -682,6 +687,24 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
|
||||||
*hlimit = *(int *)CMSG_DATA(cmsg);
|
*hlimit = *(int *)CMSG_DATA(cmsg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IPV6_TCLASS:
|
||||||
|
{
|
||||||
|
int tc;
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
|
if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
|
||||||
|
goto exit_f;
|
||||||
|
}
|
||||||
|
|
||||||
|
tc = *(int *)CMSG_DATA(cmsg);
|
||||||
|
if (tc < 0 || tc > 0xff)
|
||||||
|
goto exit_f;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
*tclass = tc;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
|
LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
|
||||||
cmsg->cmsg_type);
|
cmsg->cmsg_type);
|
||||||
|
|
|
@ -287,7 +287,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
|
||||||
int iif = 0;
|
int iif = 0;
|
||||||
int addr_type = 0;
|
int addr_type = 0;
|
||||||
int len;
|
int len;
|
||||||
int hlimit;
|
int hlimit, tclass;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
|
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,
|
||||||
if (hlimit < 0)
|
if (hlimit < 0)
|
||||||
hlimit = ipv6_get_hoplimit(dst->dev);
|
hlimit = ipv6_get_hoplimit(dst->dev);
|
||||||
|
|
||||||
|
tclass = np->cork.tclass;
|
||||||
|
if (tclass < 0)
|
||||||
|
tclass = 0;
|
||||||
|
|
||||||
msg.skb = skb;
|
msg.skb = skb;
|
||||||
msg.offset = skb->nh.raw - skb->data;
|
msg.offset = skb->nh.raw - skb->data;
|
||||||
|
|
||||||
|
@ -400,7 +404,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
|
||||||
err = ip6_append_data(sk, icmpv6_getfrag, &msg,
|
err = ip6_append_data(sk, icmpv6_getfrag, &msg,
|
||||||
len + sizeof(struct icmp6hdr),
|
len + sizeof(struct icmp6hdr),
|
||||||
sizeof(struct icmp6hdr),
|
sizeof(struct icmp6hdr),
|
||||||
hlimit, NULL, &fl, (struct rt6_info*)dst,
|
hlimit, tclass, NULL, &fl, (struct rt6_info*)dst,
|
||||||
MSG_DONTWAIT);
|
MSG_DONTWAIT);
|
||||||
if (err) {
|
if (err) {
|
||||||
ip6_flush_pending_frames(sk);
|
ip6_flush_pending_frames(sk);
|
||||||
|
@ -434,6 +438,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||||
struct dst_entry *dst;
|
struct dst_entry *dst;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int hlimit;
|
int hlimit;
|
||||||
|
int tclass;
|
||||||
|
|
||||||
saddr = &skb->nh.ipv6h->daddr;
|
saddr = &skb->nh.ipv6h->daddr;
|
||||||
|
|
||||||
|
@ -475,13 +480,17 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||||
if (hlimit < 0)
|
if (hlimit < 0)
|
||||||
hlimit = ipv6_get_hoplimit(dst->dev);
|
hlimit = ipv6_get_hoplimit(dst->dev);
|
||||||
|
|
||||||
|
tclass = np->cork.tclass;
|
||||||
|
if (tclass < 0)
|
||||||
|
tclass = 0;
|
||||||
|
|
||||||
idev = in6_dev_get(skb->dev);
|
idev = in6_dev_get(skb->dev);
|
||||||
|
|
||||||
msg.skb = skb;
|
msg.skb = skb;
|
||||||
msg.offset = 0;
|
msg.offset = 0;
|
||||||
|
|
||||||
err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
|
err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
|
||||||
sizeof(struct icmp6hdr), hlimit, NULL, &fl,
|
sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl,
|
||||||
(struct rt6_info*)dst, MSG_DONTWAIT);
|
(struct rt6_info*)dst, MSG_DONTWAIT);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -314,7 +314,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
|
||||||
msg.msg_control = (void*)(fl->opt+1);
|
msg.msg_control = (void*)(fl->opt+1);
|
||||||
flowi.oif = 0;
|
flowi.oif = 0;
|
||||||
|
|
||||||
err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk);
|
err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk, &junk);
|
||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
|
@ -166,7 +166,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
|
||||||
struct ipv6hdr *hdr;
|
struct ipv6hdr *hdr;
|
||||||
u8 proto = fl->proto;
|
u8 proto = fl->proto;
|
||||||
int seg_len = skb->len;
|
int seg_len = skb->len;
|
||||||
int hlimit;
|
int hlimit, tclass;
|
||||||
u32 mtu;
|
u32 mtu;
|
||||||
|
|
||||||
if (opt) {
|
if (opt) {
|
||||||
|
@ -202,7 +202,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
|
||||||
* Fill in the IPv6 header
|
* Fill in the IPv6 header
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*(u32*)hdr = htonl(0x60000000) | fl->fl6_flowlabel;
|
|
||||||
hlimit = -1;
|
hlimit = -1;
|
||||||
if (np)
|
if (np)
|
||||||
hlimit = np->hop_limit;
|
hlimit = np->hop_limit;
|
||||||
|
@ -211,6 +210,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
|
||||||
if (hlimit < 0)
|
if (hlimit < 0)
|
||||||
hlimit = ipv6_get_hoplimit(dst->dev);
|
hlimit = ipv6_get_hoplimit(dst->dev);
|
||||||
|
|
||||||
|
tclass = -1;
|
||||||
|
if (np)
|
||||||
|
tclass = np->tclass;
|
||||||
|
if (tclass < 0)
|
||||||
|
tclass = 0;
|
||||||
|
|
||||||
|
*(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel;
|
||||||
|
|
||||||
hdr->payload_len = htons(seg_len);
|
hdr->payload_len = htons(seg_len);
|
||||||
hdr->nexthdr = proto;
|
hdr->nexthdr = proto;
|
||||||
hdr->hop_limit = hlimit;
|
hdr->hop_limit = hlimit;
|
||||||
|
@ -762,10 +769,11 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),
|
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,
|
void *from, int length, int transhdrlen,
|
||||||
int hlimit, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt,
|
int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl,
|
||||||
unsigned int flags)
|
struct rt6_info *rt, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct inet_sock *inet = inet_sk(sk);
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
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
|
||||||
np->cork.rt = rt;
|
np->cork.rt = rt;
|
||||||
inet->cork.fl = *fl;
|
inet->cork.fl = *fl;
|
||||||
np->cork.hop_limit = hlimit;
|
np->cork.hop_limit = hlimit;
|
||||||
|
np->cork.tclass = tclass;
|
||||||
inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
|
inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
|
||||||
if (dst_allfrag(rt->u.dst.path))
|
if (dst_allfrag(rt->u.dst.path))
|
||||||
inet->cork.flags |= IPCORK_ALLFRAG;
|
inet->cork.flags |= IPCORK_ALLFRAG;
|
||||||
|
@ -1084,7 +1093,8 @@ int ip6_push_pending_frames(struct sock *sk)
|
||||||
|
|
||||||
skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
|
skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
|
||||||
|
|
||||||
*(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000);
|
*(u32*)hdr = fl->fl6_flowlabel |
|
||||||
|
htonl(0x60000000 | ((int)np->cork.tclass << 20));
|
||||||
|
|
||||||
if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
|
if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
|
||||||
hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
|
hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
|
||||||
|
|
|
@ -264,6 +264,18 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
|
||||||
retv = 0;
|
retv = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IPV6_TCLASS:
|
||||||
|
if (val < 0 || val > 0xff)
|
||||||
|
goto e_inval;
|
||||||
|
np->tclass = val;
|
||||||
|
retv = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IPV6_RECVTCLASS:
|
||||||
|
np->rxopt.bits.rxtclass = valbool;
|
||||||
|
retv = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case IPV6_FLOWINFO:
|
case IPV6_FLOWINFO:
|
||||||
np->rxopt.bits.rxflow = valbool;
|
np->rxopt.bits.rxflow = valbool;
|
||||||
retv = 0;
|
retv = 0;
|
||||||
|
@ -364,7 +376,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
|
||||||
msg.msg_controllen = optlen;
|
msg.msg_controllen = optlen;
|
||||||
msg.msg_control = (void*)(opt+1);
|
msg.msg_control = (void*)(opt+1);
|
||||||
|
|
||||||
retv = datagram_send_ctl(&msg, &fl, opt, &junk);
|
retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk);
|
||||||
if (retv)
|
if (retv)
|
||||||
goto done;
|
goto done;
|
||||||
update:
|
update:
|
||||||
|
@ -787,6 +799,14 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||||
val = np->rxopt.bits.odstopts;
|
val = np->rxopt.bits.odstopts;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IPV6_TCLASS:
|
||||||
|
val = np->tclass;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IPV6_RECVTCLASS:
|
||||||
|
val = np->rxopt.bits.rxtclass;
|
||||||
|
break;
|
||||||
|
|
||||||
case IPV6_FLOWINFO:
|
case IPV6_FLOWINFO:
|
||||||
val = np->rxopt.bits.rxflow;
|
val = np->rxopt.bits.rxflow;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -655,6 +655,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
struct flowi fl;
|
struct flowi fl;
|
||||||
int addr_len = msg->msg_namelen;
|
int addr_len = msg->msg_namelen;
|
||||||
int hlimit = -1;
|
int hlimit = -1;
|
||||||
|
int tclass = -1;
|
||||||
u16 proto;
|
u16 proto;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -740,7 +741,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
memset(opt, 0, sizeof(struct ipv6_txoptions));
|
memset(opt, 0, sizeof(struct ipv6_txoptions));
|
||||||
opt->tot_len = sizeof(struct ipv6_txoptions);
|
opt->tot_len = sizeof(struct ipv6_txoptions);
|
||||||
|
|
||||||
err = datagram_send_ctl(msg, &fl, opt, &hlimit);
|
err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fl6_sock_release(flowlabel);
|
fl6_sock_release(flowlabel);
|
||||||
return err;
|
return err;
|
||||||
|
@ -797,6 +798,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
hlimit = ipv6_get_hoplimit(dst->dev);
|
hlimit = ipv6_get_hoplimit(dst->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tclass < 0) {
|
||||||
|
tclass = np->cork.tclass;
|
||||||
|
if (tclass < 0)
|
||||||
|
tclass = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg->msg_flags&MSG_CONFIRM)
|
if (msg->msg_flags&MSG_CONFIRM)
|
||||||
goto do_confirm;
|
goto do_confirm;
|
||||||
|
|
||||||
|
@ -805,8 +812,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags);
|
err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags);
|
||||||
} else {
|
} else {
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0,
|
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
|
||||||
hlimit, opt, &fl, (struct rt6_info*)dst, msg->msg_flags);
|
len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
|
||||||
|
msg->msg_flags);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
ip6_flush_pending_frames(sk);
|
ip6_flush_pending_frames(sk);
|
||||||
|
|
|
@ -637,6 +637,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
int addr_len = msg->msg_namelen;
|
int addr_len = msg->msg_namelen;
|
||||||
int ulen = len;
|
int ulen = len;
|
||||||
int hlimit = -1;
|
int hlimit = -1;
|
||||||
|
int tclass = -1;
|
||||||
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
|
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -758,7 +759,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
memset(opt, 0, sizeof(struct ipv6_txoptions));
|
memset(opt, 0, sizeof(struct ipv6_txoptions));
|
||||||
opt->tot_len = sizeof(*opt);
|
opt->tot_len = sizeof(*opt);
|
||||||
|
|
||||||
err = datagram_send_ctl(msg, fl, opt, &hlimit);
|
err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fl6_sock_release(flowlabel);
|
fl6_sock_release(flowlabel);
|
||||||
return err;
|
return err;
|
||||||
|
@ -814,6 +815,12 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
hlimit = ipv6_get_hoplimit(dst->dev);
|
hlimit = ipv6_get_hoplimit(dst->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tclass < 0) {
|
||||||
|
tclass = np->tclass;
|
||||||
|
if (tclass < 0)
|
||||||
|
tclass = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg->msg_flags&MSG_CONFIRM)
|
if (msg->msg_flags&MSG_CONFIRM)
|
||||||
goto do_confirm;
|
goto do_confirm;
|
||||||
back_from_confirm:
|
back_from_confirm:
|
||||||
|
@ -833,8 +840,9 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
|
||||||
|
|
||||||
do_append_data:
|
do_append_data:
|
||||||
up->len += ulen;
|
up->len += ulen;
|
||||||
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr),
|
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
|
||||||
hlimit, opt, fl, (struct rt6_info*)dst,
|
sizeof(struct udphdr), hlimit, tclass, opt, fl,
|
||||||
|
(struct rt6_info*)dst,
|
||||||
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
|
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
|
||||||
if (err)
|
if (err)
|
||||||
udp_v6_flush_pending_frames(sk);
|
udp_v6_flush_pending_frames(sk);
|
||||||
|
|
Loading…
Reference in a new issue