Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
2e66fc41
Commit
2e66fc41
authored
Sep 08, 2005
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
git://git.skbuff.net/gitroot/yoshfuji/linux-2.6-git-rfc3542
parents
42ca89c1
41a1f8ea
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
525 additions
and
71 deletions
+525
-71
include/linux/in6.h
include/linux/in6.h
+30
-6
include/linux/ipv6.h
include/linux/ipv6.h
+12
-3
include/net/ipv6.h
include/net/ipv6.h
+5
-0
include/net/transp_v6.h
include/net/transp_v6.h
+1
-1
net/ipv6/datagram.c
net/ipv6/datagram.c
+126
-9
net/ipv6/exthdrs.c
net/ipv6/exthdrs.c
+104
-3
net/ipv6/icmp.c
net/ipv6/icmp.c
+12
-3
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_flowlabel.c
+9
-5
net/ipv6/ip6_output.c
net/ipv6/ip6_output.c
+17
-7
net/ipv6/ipv6_sockglue.c
net/ipv6/ipv6_sockglue.c
+174
-12
net/ipv6/raw.c
net/ipv6/raw.c
+12
-5
net/ipv6/tcp_ipv6.c
net/ipv6/tcp_ipv6.c
+10
-11
net/ipv6/udp.c
net/ipv6/udp.c
+13
-6
No files found.
include/linux/in6.h
View file @
2e66fc41
...
@@ -148,13 +148,13 @@ struct in6_flowlabel_req
...
@@ -148,13 +148,13 @@ struct in6_flowlabel_req
*/
*/
#define IPV6_ADDRFORM 1
#define IPV6_ADDRFORM 1
#define IPV6_
PKTINFO
2
#define IPV6_
2292PKTINFO
2
#define IPV6_
HOPOPTS
3
#define IPV6_
2292HOPOPTS
3
#define IPV6_
DSTOPTS
4
#define IPV6_
2292DSTOPTS
4
#define IPV6_RTHDR 5
#define IPV6_
2292
RTHDR 5
#define IPV6_
PKTOPTIONS
6
#define IPV6_
2292PKTOPTIONS
6
#define IPV6_CHECKSUM 7
#define IPV6_CHECKSUM 7
#define IPV6_
HOPLIMIT
8
#define IPV6_
2292HOPLIMIT
8
#define IPV6_NEXTHOP 9
#define IPV6_NEXTHOP 9
#define IPV6_AUTHHDR 10
/* obsolete */
#define IPV6_AUTHHDR 10
/* obsolete */
#define IPV6_FLOWINFO 11
#define IPV6_FLOWINFO 11
...
@@ -198,4 +198,28 @@ struct in6_flowlabel_req
...
@@ -198,4 +198,28 @@ struct in6_flowlabel_req
* MCAST_MSFILTER 48
* MCAST_MSFILTER 48
*/
*/
/* RFC3542 advanced socket options (50-67) */
#define IPV6_RECVPKTINFO 50
#define IPV6_PKTINFO 51
#if 0
#define IPV6_RECVPATHMTU 52
#define IPV6_PATHMTU 53
#define IPV6_DONTFRAG 54
#define IPV6_USE_MIN_MTU 55
#endif
#define IPV6_RECVHOPOPTS 56
#define IPV6_HOPOPTS 57
#if 0
#define IPV6_RECVRTHDRDSTOPTS 58 /* Unused, see net/ipv6/datagram.c */
#endif
#define IPV6_RTHDRDSTOPTS 59
#define IPV6_RECVRTHDR 60
#define IPV6_RTHDR 61
#define IPV6_RECVDSTOPTS 62
#define IPV6_DSTOPTS 63
#define IPV6_RECVHOPLIMIT 64
#define IPV6_HOPLIMIT 65
#define IPV6_RECVTCLASS 66
#define IPV6_TCLASS 67
#endif
#endif
include/linux/ipv6.h
View file @
2e66fc41
...
@@ -189,6 +189,7 @@ struct inet6_skb_parm {
...
@@ -189,6 +189,7 @@ struct inet6_skb_parm {
__u16
dst0
;
__u16
dst0
;
__u16
srcrt
;
__u16
srcrt
;
__u16
dst1
;
__u16
dst1
;
__u16
lastopt
;
};
};
#define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb))
#define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb))
...
@@ -234,14 +235,20 @@ struct ipv6_pinfo {
...
@@ -234,14 +235,20 @@ struct ipv6_pinfo {
/* pktoption flags */
/* pktoption flags */
union
{
union
{
struct
{
struct
{
__u8
srcrt
:
2
,
__u16
srcrt
:
2
,
osrcrt:
2
,
rxinfo:
1
,
rxinfo:
1
,
rxoinfo:
1
,
rxhlim:
1
,
rxhlim:
1
,
rxohlim:
1
,
hopopts:
1
,
hopopts:
1
,
ohopopts:
1
,
dstopts:
1
,
dstopts:
1
,
rxflow:
1
;
odstopts:
1
,
rxflow:
1
,
rxtclass:
1
;
}
bits
;
}
bits
;
__u
8
all
;
__u
16
all
;
}
rxopt
;
}
rxopt
;
/* sockopt flags */
/* sockopt flags */
...
@@ -250,6 +257,7 @@ struct ipv6_pinfo {
...
@@ -250,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
;
...
@@ -263,6 +271,7 @@ struct ipv6_pinfo {
...
@@ -263,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
;
};
};
...
...
include/net/ipv6.h
View file @
2e66fc41
...
@@ -233,6 +233,10 @@ extern int ip6_ra_control(struct sock *sk, int sel,
...
@@ -233,6 +233,10 @@ extern int ip6_ra_control(struct sock *sk, int sel,
extern
int
ipv6_parse_hopopts
(
struct
sk_buff
*
skb
,
int
);
extern
int
ipv6_parse_hopopts
(
struct
sk_buff
*
skb
,
int
);
extern
struct
ipv6_txoptions
*
ipv6_dup_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
);
extern
struct
ipv6_txoptions
*
ipv6_dup_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
);
extern
struct
ipv6_txoptions
*
ipv6_renew_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
,
int
newtype
,
struct
ipv6_opt_hdr
__user
*
newopt
,
int
newoptlen
);
extern
int
ip6_frag_nqueues
;
extern
int
ip6_frag_nqueues
;
extern
atomic_t
ip6_frag_mem
;
extern
atomic_t
ip6_frag_mem
;
...
@@ -373,6 +377,7 @@ extern int ip6_append_data(struct sock *sk,
...
@@ -373,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
,
...
...
include/net/transp_v6.h
View file @
2e66fc41
...
@@ -37,7 +37,7 @@ extern int datagram_recv_ctl(struct sock *sk,
...
@@ -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)
...
...
net/ipv6/datagram.c
View file @
2e66fc41
...
@@ -390,32 +390,101 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
...
@@ -390,32 +390,101 @@ 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
);
}
}
/* HbH is allowed only once */
if
(
np
->
rxopt
.
bits
.
hopopts
&&
opt
->
hop
)
{
if
(
np
->
rxopt
.
bits
.
hopopts
&&
opt
->
hop
)
{
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
hop
;
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
hop
;
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_HOPOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_HOPOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
}
}
if
(
np
->
rxopt
.
bits
.
dstopts
&&
opt
->
dst0
)
{
if
(
opt
->
lastopt
&&
(
np
->
rxopt
.
bits
.
dstopts
||
np
->
rxopt
.
bits
.
srcrt
))
{
/*
* Silly enough, but we need to reparse in order to
* report extension headers (except for HbH)
* in order.
*
* Also note that IPV6_RECVRTHDRDSTOPTS is NOT
* (and WILL NOT be) defined because
* IPV6_RECVDSTOPTS is more generic. --yoshfuji
*/
unsigned
int
off
=
sizeof
(
struct
ipv6hdr
);
u8
nexthdr
=
skb
->
nh
.
ipv6h
->
nexthdr
;
while
(
off
<=
opt
->
lastopt
)
{
unsigned
len
;
u8
*
ptr
=
skb
->
nh
.
raw
+
off
;
switch
(
nexthdr
)
{
case
IPPROTO_DSTOPTS
:
nexthdr
=
ptr
[
0
];
len
=
(
ptr
[
1
]
+
1
)
<<
3
;
if
(
np
->
rxopt
.
bits
.
dstopts
)
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_DSTOPTS
,
len
,
ptr
);
break
;
case
IPPROTO_ROUTING
:
nexthdr
=
ptr
[
0
];
len
=
(
ptr
[
1
]
+
1
)
<<
3
;
if
(
np
->
rxopt
.
bits
.
srcrt
)
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_RTHDR
,
len
,
ptr
);
break
;
case
IPPROTO_AH
:
nexthdr
=
ptr
[
0
];
len
=
(
ptr
[
1
]
+
1
)
<<
2
;
break
;
default:
nexthdr
=
ptr
[
0
];
len
=
(
ptr
[
1
]
+
1
)
<<
3
;
break
;
}
off
+=
len
;
}
}
/* socket options in old style */
if
(
np
->
rxopt
.
bits
.
rxoinfo
)
{
struct
in6_pktinfo
src_info
;
src_info
.
ipi6_ifindex
=
opt
->
iif
;
ipv6_addr_copy
(
&
src_info
.
ipi6_addr
,
&
skb
->
nh
.
ipv6h
->
daddr
);
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_2292PKTINFO
,
sizeof
(
src_info
),
&
src_info
);
}
if
(
np
->
rxopt
.
bits
.
rxohlim
)
{
int
hlim
=
skb
->
nh
.
ipv6h
->
hop_limit
;
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_2292HOPLIMIT
,
sizeof
(
hlim
),
&
hlim
);
}
if
(
np
->
rxopt
.
bits
.
ohopopts
&&
opt
->
hop
)
{
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
hop
;
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_2292HOPOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
}
if
(
np
->
rxopt
.
bits
.
odstopts
&&
opt
->
dst0
)
{
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
dst0
;
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
dst0
;
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_DSTOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_
2292
DSTOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
}
}
if
(
np
->
rxopt
.
bits
.
srcrt
&&
opt
->
srcrt
)
{
if
(
np
->
rxopt
.
bits
.
o
srcrt
&&
opt
->
srcrt
)
{
struct
ipv6_rt_hdr
*
rthdr
=
(
struct
ipv6_rt_hdr
*
)(
skb
->
nh
.
raw
+
opt
->
srcrt
);
struct
ipv6_rt_hdr
*
rthdr
=
(
struct
ipv6_rt_hdr
*
)(
skb
->
nh
.
raw
+
opt
->
srcrt
);
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_RTHDR
,
(
rthdr
->
hdrlen
+
1
)
<<
3
,
rthdr
);
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_
2292
RTHDR
,
(
rthdr
->
hdrlen
+
1
)
<<
3
,
rthdr
);
}
}
if
(
np
->
rxopt
.
bits
.
dstopts
&&
opt
->
dst1
)
{
if
(
np
->
rxopt
.
bits
.
o
dstopts
&&
opt
->
dst1
)
{
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
dst1
;
u8
*
ptr
=
skb
->
nh
.
raw
+
opt
->
dst1
;
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_DSTOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
put_cmsg
(
msg
,
SOL_IPV6
,
IPV6_
2292
DSTOPTS
,
(
ptr
[
1
]
+
1
)
<<
3
,
ptr
);
}
}
return
0
;
return
0
;
}
}
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
;
...
@@ -438,6 +507,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -438,6 +507,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
switch
(
cmsg
->
cmsg_type
)
{
switch
(
cmsg
->
cmsg_type
)
{
case
IPV6_PKTINFO
:
case
IPV6_PKTINFO
:
case
IPV6_2292PKTINFO
:
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
in6_pktinfo
)))
{
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
in6_pktinfo
)))
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
exit_f
;
goto
exit_f
;
...
@@ -492,6 +562,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -492,6 +562,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
fl
->
fl6_flowlabel
=
IPV6_FLOWINFO_MASK
&
*
(
u32
*
)
CMSG_DATA
(
cmsg
);
fl
->
fl6_flowlabel
=
IPV6_FLOWINFO_MASK
&
*
(
u32
*
)
CMSG_DATA
(
cmsg
);
break
;
break
;
case
IPV6_2292HOPOPTS
:
case
IPV6_HOPOPTS
:
case
IPV6_HOPOPTS
:
if
(
opt
->
hopopt
||
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_opt_hdr
)))
{
if
(
opt
->
hopopt
||
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_opt_hdr
)))
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
...
@@ -512,7 +583,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -512,7 +583,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
opt
->
hopopt
=
hdr
;
opt
->
hopopt
=
hdr
;
break
;
break
;
case
IPV6_DSTOPTS
:
case
IPV6_
2292
DSTOPTS
:
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_opt_hdr
)))
{
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_opt_hdr
)))
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
exit_f
;
goto
exit_f
;
...
@@ -536,6 +607,33 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -536,6 +607,33 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
opt
->
dst1opt
=
hdr
;
opt
->
dst1opt
=
hdr
;
break
;
break
;
case
IPV6_DSTOPTS
:
case
IPV6_RTHDRDSTOPTS
:
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_opt_hdr
)))
{
err
=
-
EINVAL
;
goto
exit_f
;
}
hdr
=
(
struct
ipv6_opt_hdr
*
)
CMSG_DATA
(
cmsg
);
len
=
((
hdr
->
hdrlen
+
1
)
<<
3
);
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
len
))
{
err
=
-
EINVAL
;
goto
exit_f
;
}
if
(
!
capable
(
CAP_NET_RAW
))
{
err
=
-
EPERM
;
goto
exit_f
;
}
if
(
cmsg
->
cmsg_type
==
IPV6_DSTOPTS
)
{
opt
->
opt_flen
+=
len
;
opt
->
dst1opt
=
hdr
;
}
else
{
opt
->
opt_nflen
+=
len
;
opt
->
dst0opt
=
hdr
;
}
break
;
case
IPV6_2292RTHDR
:
case
IPV6_RTHDR
:
case
IPV6_RTHDR
:
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_rt_hdr
)))
{
if
(
cmsg
->
cmsg_len
<
CMSG_LEN
(
sizeof
(
struct
ipv6_rt_hdr
)))
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
...
@@ -568,7 +666,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -568,7 +666,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
opt
->
opt_nflen
+=
len
;
opt
->
opt_nflen
+=
len
;
opt
->
srcrt
=
rthdr
;
opt
->
srcrt
=
rthdr
;
if
(
opt
->
dst1opt
)
{
if
(
cmsg
->
cmsg_type
==
IPV6_2292RTHDR
&&
opt
->
dst1opt
)
{
int
dsthdrlen
=
((
opt
->
dst1opt
->
hdrlen
+
1
)
<<
3
);
int
dsthdrlen
=
((
opt
->
dst1opt
->
hdrlen
+
1
)
<<
3
);
opt
->
opt_nflen
+=
dsthdrlen
;
opt
->
opt_nflen
+=
dsthdrlen
;
...
@@ -579,6 +677,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -579,6 +677,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
break
;
break
;
case
IPV6_2292HOPLIMIT
:
case
IPV6_HOPLIMIT
:
case
IPV6_HOPLIMIT
:
if
(
cmsg
->
cmsg_len
!=
CMSG_LEN
(
sizeof
(
int
)))
{
if
(
cmsg
->
cmsg_len
!=
CMSG_LEN
(
sizeof
(
int
)))
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
...
@@ -588,6 +687,24 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
...
@@ -588,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
);
...
...
net/ipv6/exthdrs.c
View file @
2e66fc41
...
@@ -164,6 +164,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
...
@@ -164,6 +164,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
return
-
1
;
return
-
1
;
}
}
opt
->
lastopt
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
opt
->
dst1
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
opt
->
dst1
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
if
(
ip6_parse_tlv
(
tlvprocdestopt_lst
,
skb
))
{
if
(
ip6_parse_tlv
(
tlvprocdestopt_lst
,
skb
))
{
...
@@ -243,6 +244,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
...
@@ -243,6 +244,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
looped_back:
looped_back:
if
(
hdr
->
segments_left
==
0
)
{
if
(
hdr
->
segments_left
==
0
)
{
opt
->
lastopt
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
opt
->
srcrt
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
opt
->
srcrt
=
skb
->
h
.
raw
-
skb
->
nh
.
raw
;
skb
->
h
.
raw
+=
(
hdr
->
hdrlen
+
1
)
<<
3
;
skb
->
h
.
raw
+=
(
hdr
->
hdrlen
+
1
)
<<
3
;
opt
->
dst0
=
opt
->
dst1
;
opt
->
dst0
=
opt
->
dst1
;
...
@@ -538,10 +540,15 @@ void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
...
@@ -538,10 +540,15 @@ void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
u8
*
proto
,
u8
*
proto
,
struct
in6_addr
**
daddr
)
struct
in6_addr
**
daddr
)
{
{
if
(
opt
->
srcrt
)
if
(
opt
->
srcrt
)
{
ipv6_push_rthdr
(
skb
,
proto
,
opt
->
srcrt
,
daddr
);
ipv6_push_rthdr
(
skb
,
proto
,
opt
->
srcrt
,
daddr
);
if
(
opt
->
dst0opt
)
/*
ipv6_push_exthdr
(
skb
,
proto
,
NEXTHDR_DEST
,
opt
->
dst0opt
);
* IPV6_RTHDRDSTOPTS is ignored
* unless IPV6_RTHDR is set (RFC3542).
*/
if
(
opt
->
dst0opt
)
ipv6_push_exthdr
(
skb
,
proto
,
NEXTHDR_DEST
,
opt
->
dst0opt
);
}
if
(
opt
->
hopopt
)
if
(
opt
->
hopopt
)
ipv6_push_exthdr
(
skb
,
proto
,
NEXTHDR_HOP
,
opt
->
hopopt
);
ipv6_push_exthdr
(
skb
,
proto
,
NEXTHDR_HOP
,
opt
->
hopopt
);
}
}
...
@@ -572,3 +579,97 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
...
@@ -572,3 +579,97 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
}
}
return
opt2
;
return
opt2
;
}
}
static
int
ipv6_renew_option
(
void
*
ohdr
,
struct
ipv6_opt_hdr
__user
*
newopt
,
int
newoptlen
,
int
inherit
,
struct
ipv6_opt_hdr
**
hdr
,
char
**
p
)
{
if
(
inherit
)
{
if
(
ohdr
)
{
memcpy
(
*
p
,
ohdr
,
ipv6_optlen
((
struct
ipv6_opt_hdr
*
)
ohdr
));
*
hdr
=
(
struct
ipv6_opt_hdr
*
)
*
p
;
*
p
+=
CMSG_ALIGN
(
ipv6_optlen
(
*
(
struct
ipv6_opt_hdr
**
)
hdr
));
}
}
else
{
if
(
newopt
)
{
if
(
copy_from_user
(
*
p
,
newopt
,
newoptlen
))
return
-
EFAULT
;
*
hdr
=
(
struct
ipv6_opt_hdr
*
)
*
p
;
if
(
ipv6_optlen
(
*
(
struct
ipv6_opt_hdr
**
)
hdr
)
>
newoptlen
)
return
-
EINVAL
;
*
p
+=
CMSG_ALIGN
(
newoptlen
);
}
}
return
0
;
}
struct
ipv6_txoptions
*
ipv6_renew_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
,
int
newtype
,
struct
ipv6_opt_hdr
__user
*
newopt
,
int
newoptlen
)
{
int
tot_len
=
0
;
char
*
p
;
struct
ipv6_txoptions
*
opt2
;
int
err
;
if
(
newtype
!=
IPV6_HOPOPTS
&&
opt
->
hopopt
)
tot_len
+=
CMSG_ALIGN
(
ipv6_optlen
(
opt
->
hopopt
));
if
(
newtype
!=
IPV6_RTHDRDSTOPTS
&&
opt
->
dst0opt
)
tot_len
+=
CMSG_ALIGN
(
ipv6_optlen
(
opt
->
dst0opt
));
if
(
newtype
!=
IPV6_RTHDR
&&
opt
->
srcrt
)
tot_len
+=
CMSG_ALIGN
(
ipv6_optlen
(
opt
->
srcrt
));
if
(
newtype
!=
IPV6_DSTOPTS
&&
opt
->
dst1opt
)
tot_len
+=
CMSG_ALIGN
(
ipv6_optlen
(
opt
->
dst1opt
));
if
(
newopt
&&
newoptlen
)
tot_len
+=
CMSG_ALIGN
(
newoptlen
);
if
(
!
tot_len
)
return
NULL
;
opt2
=
sock_kmalloc
(
sk
,
tot_len
,
GFP_ATOMIC
);
if
(
!
opt2
)
return
ERR_PTR
(
-
ENOBUFS
);
memset
(
opt2
,
0
,
tot_len
);
opt2
->
tot_len
=
tot_len
;
p
=
(
char
*
)(
opt2
+
1
);
err
=
ipv6_renew_option
(
opt
->
hopopt
,
newopt
,
newoptlen
,
newtype
!=
IPV6_HOPOPTS
,
&
opt2
->
hopopt
,
&
p
);
if
(
err
)
goto
out
;
err
=
ipv6_renew_option
(
opt
->
dst0opt
,
newopt
,
newoptlen
,
newtype
!=
IPV6_RTHDRDSTOPTS
,
&
opt2
->
dst0opt
,
&
p
);
if
(
err
)
goto
out
;
err
=
ipv6_renew_option
(
opt
->
srcrt
,
newopt
,
newoptlen
,
newtype
!=
IPV6_RTHDR
,
(
struct
ipv6_opt_hdr
**
)
opt2
->
srcrt
,
&
p
);
if
(
err
)
goto
out
;
err
=
ipv6_renew_option
(
opt
->
dst1opt
,
newopt
,
newoptlen
,
newtype
!=
IPV6_DSTOPTS
,
&
opt2
->
dst1opt
,
&
p
);
if
(
err
)
goto
out
;
opt2
->
opt_nflen
=
(
opt2
->
hopopt
?
ipv6_optlen
(
opt2
->
hopopt
)
:
0
)
+
(
opt2
->
dst0opt
?
ipv6_optlen
(
opt2
->
dst0opt
)
:
0
)
+
(
opt2
->
srcrt
?
ipv6_optlen
(
opt2
->
srcrt
)
:
0
);
opt2
->
opt_flen
=
(
opt2
->
dst1opt
?
ipv6_optlen
(
opt2
->
dst1opt
)
:
0
);
return
opt2
;
out:
sock_kfree_s
(
sk
,
p
,
tot_len
);
return
ERR_PTR
(
err
);
}
net/ipv6/icmp.c
View file @
2e66fc41
...
@@ -287,7 +287,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
...
@@ -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,
...
@@ -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,
...
@@ -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)
...
@@ -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)
...
@@ -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
)
{
...
...
net/ipv6/ip6_flowlabel.c
View file @
2e66fc41
...
@@ -225,16 +225,20 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
...
@@ -225,16 +225,20 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
struct
ip6_flowlabel
*
fl
,
struct
ip6_flowlabel
*
fl
,
struct
ipv6_txoptions
*
fopt
)
struct
ipv6_txoptions
*
fopt
)
{
{
struct
ipv6_txoptions
*
fl_opt
=
fl
->
opt
;
struct
ipv6_txoptions
*
fl_opt
=
fl
?
fl
->
opt
:
NULL
;
if
(
fopt
==
NULL
||
fopt
->
opt_flen
==
0
)
if
(
fopt
==
NULL
||
fopt
->
opt_flen
==
0
)
{
return
fl_opt
;
if
(
!
fl_opt
||
!
fl_opt
->
dst0opt
||
fl_opt
->
srcrt
)
return
fl_opt
;
}
if
(
fl_opt
!=
NULL
)
{
if
(
fl_opt
!=
NULL
)
{
opt_space
->
hopopt
=
fl_opt
->
hopopt
;
opt_space
->
hopopt
=
fl_opt
->
hopopt
;
opt_space
->
dst0opt
=
fl_opt
->
dst0opt
;
opt_space
->
dst0opt
=
fl_opt
->
srcrt
?
fl_opt
->
dst0opt
:
NULL
;
opt_space
->
srcrt
=
fl_opt
->
srcrt
;
opt_space
->
srcrt
=
fl_opt
->
srcrt
;
opt_space
->
opt_nflen
=
fl_opt
->
opt_nflen
;
opt_space
->
opt_nflen
=
fl_opt
->
opt_nflen
;
if
(
fl_opt
->
dst0opt
&&
!
fl_opt
->
srcrt
)
opt_space
->
opt_nflen
-=
ipv6_optlen
(
fl_opt
->
dst0opt
);
}
else
{
}
else
{
if
(
fopt
->
opt_nflen
==
0
)
if
(
fopt
->
opt_nflen
==
0
)
return
fopt
;
return
fopt
;
...
@@ -310,7 +314,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
...
@@ -310,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
;
...
...
net/ipv6/ip6_output.c
View file @
2e66fc41
...
@@ -166,7 +166,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
...
@@ -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,
...
@@ -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,
...
@@ -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)
...
@@ -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
,
void
*
from
,
int
length
,
int
transhdrlen
,
int
offset
,
int
len
,
int
odd
,
struct
sk_buff
*
skb
),
int
hlimit
,
struct
ipv6_txoptions
*
opt
,
struct
flowi
*
fl
,
struct
rt6_info
*
rt
,
void
*
from
,
int
length
,
int
transhdrlen
,
unsigned
int
flags
)
int
hlimit
,
int
tclass
,
struct
ipv6_txoptions
*
opt
,
struct
flowi
*
fl
,
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
...
@@ -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)
...
@@ -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
));
...
...
net/ipv6/ipv6_sockglue.c
View file @
2e66fc41
...
@@ -210,39 +210,139 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
...
@@ -210,39 +210,139 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
retv
=
0
;
retv
=
0
;
break
;
break
;
case
IPV6_PKTINFO
:
case
IPV6_
RECV
PKTINFO
:
np
->
rxopt
.
bits
.
rxinfo
=
valbool
;
np
->
rxopt
.
bits
.
rxinfo
=
valbool
;
retv
=
0
;
retv
=
0
;
break
;
break
;
case
IPV6_2292PKTINFO
:
np
->
rxopt
.
bits
.
rxoinfo
=
valbool
;
retv
=
0
;
break
;
case
IPV6_HOPLIMIT
:
case
IPV6_
RECV
HOPLIMIT
:
np
->
rxopt
.
bits
.
rxhlim
=
valbool
;
np
->
rxopt
.
bits
.
rxhlim
=
valbool
;
retv
=
0
;
retv
=
0
;
break
;
break
;
case
IPV6_RTHDR
:
case
IPV6_2292HOPLIMIT
:
np
->
rxopt
.
bits
.
rxohlim
=
valbool
;
retv
=
0
;
break
;
case
IPV6_RECVRTHDR
:
if
(
val
<
0
||
val
>
2
)
if
(
val
<
0
||
val
>
2
)
goto
e_inval
;
goto
e_inval
;
np
->
rxopt
.
bits
.
srcrt
=
val
;
np
->
rxopt
.
bits
.
srcrt
=
val
;
retv
=
0
;
retv
=
0
;
break
;
break
;
case
IPV6_HOPOPTS
:
case
IPV6_2292RTHDR
:
if
(
val
<
0
||
val
>
2
)
goto
e_inval
;
np
->
rxopt
.
bits
.
osrcrt
=
val
;
retv
=
0
;
break
;
case
IPV6_RECVHOPOPTS
:
np
->
rxopt
.
bits
.
hopopts
=
valbool
;
np
->
rxopt
.
bits
.
hopopts
=
valbool
;
retv
=
0
;
retv
=
0
;
break
;
break
;
case
IPV6_DSTOPTS
:
case
IPV6_2292HOPOPTS
:
np
->
rxopt
.
bits
.
ohopopts
=
valbool
;
retv
=
0
;
break
;
case
IPV6_RECVDSTOPTS
:
np
->
rxopt
.
bits
.
dstopts
=
valbool
;
np
->
rxopt
.
bits
.
dstopts
=
valbool
;
retv
=
0
;
retv
=
0
;
break
;
break
;
case
IPV6_2292DSTOPTS
:
np
->
rxopt
.
bits
.
odstopts
=
valbool
;
retv
=
0
;
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
;
break
;
break
;
case
IPV6_PKTOPTIONS
:
case
IPV6_HOPOPTS
:
case
IPV6_RTHDRDSTOPTS
:
case
IPV6_RTHDR
:
case
IPV6_DSTOPTS
:
{
struct
ipv6_txoptions
*
opt
;
if
(
optlen
==
0
)
optval
=
0
;
/* hop-by-hop / destination options are privileged option */
retv
=
-
EPERM
;
if
(
optname
!=
IPV6_RTHDR
&&
!
capable
(
CAP_NET_RAW
))
break
;
retv
=
-
EINVAL
;
if
(
optlen
&
0x7
||
optlen
>
8
*
255
)
break
;
opt
=
ipv6_renew_options
(
sk
,
np
->
opt
,
optname
,
(
struct
ipv6_opt_hdr
__user
*
)
optval
,
optlen
);
if
(
IS_ERR
(
opt
))
{
retv
=
PTR_ERR
(
opt
);
break
;
}
/* routing header option needs extra check */
if
(
optname
==
IPV6_RTHDR
&&
opt
->
srcrt
)
{
struct
ipv6_rt_hdr
*
rthdr
=
opt
->
srcrt
;
if
(
rthdr
->
type
)
goto
sticky_done
;
if
((
rthdr
->
hdrlen
&
1
)
||
(
rthdr
->
hdrlen
>>
1
)
!=
rthdr
->
segments_left
)
goto
sticky_done
;
}
retv
=
0
;
if
(
sk
->
sk_type
==
SOCK_STREAM
)
{
if
(
opt
)
{
struct
tcp_sock
*
tp
=
tcp_sk
(
sk
);
if
(
!
((
1
<<
sk
->
sk_state
)
&
(
TCPF_LISTEN
|
TCPF_CLOSE
))
&&
inet_sk
(
sk
)
->
daddr
!=
LOOPBACK4_IPV6
)
{
tp
->
ext_header_len
=
opt
->
opt_flen
+
opt
->
opt_nflen
;
tcp_sync_mss
(
sk
,
tp
->
pmtu_cookie
);
}
}
opt
=
xchg
(
&
np
->
opt
,
opt
);
sk_dst_reset
(
sk
);
}
else
{
write_lock
(
&
sk
->
sk_dst_lock
);
opt
=
xchg
(
&
np
->
opt
,
opt
);
write_unlock
(
&
sk
->
sk_dst_lock
);
sk_dst_reset
(
sk
);
}
sticky_done:
if
(
opt
)
sock_kfree_s
(
sk
,
opt
,
opt
->
tot_len
);
break
;
}
case
IPV6_2292PKTOPTIONS
:
{
{
struct
ipv6_txoptions
*
opt
=
NULL
;
struct
ipv6_txoptions
*
opt
=
NULL
;
struct
msghdr
msg
;
struct
msghdr
msg
;
...
@@ -276,7 +376,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
...
@@ -276,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:
...
@@ -529,6 +629,17 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
...
@@ -529,6 +629,17 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
return
-
EINVAL
;
return
-
EINVAL
;
}
}
int
ipv6_getsockopt_sticky
(
struct
sock
*
sk
,
struct
ipv6_opt_hdr
*
hdr
,
char
__user
*
optval
,
int
len
)
{
if
(
!
hdr
)
return
0
;
len
=
min_t
(
int
,
len
,
ipv6_optlen
(
hdr
));
if
(
copy_to_user
(
optval
,
hdr
,
ipv6_optlen
(
hdr
)))
return
-
EFAULT
;
return
len
;
}
int
ipv6_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
int
ipv6_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
__user
*
optval
,
int
__user
*
optlen
)
char
__user
*
optval
,
int
__user
*
optlen
)
{
{
...
@@ -567,7 +678,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
...
@@ -567,7 +678,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
return
err
;
return
err
;
}
}
case
IPV6_PKTOPTIONS
:
case
IPV6_
2292
PKTOPTIONS
:
{
{
struct
msghdr
msg
;
struct
msghdr
msg
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
...
@@ -601,6 +712,16 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
...
@@ -601,6 +712,16 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
int
hlim
=
np
->
mcast_hops
;
int
hlim
=
np
->
mcast_hops
;
put_cmsg
(
&
msg
,
SOL_IPV6
,
IPV6_HOPLIMIT
,
sizeof
(
hlim
),
&
hlim
);
put_cmsg
(
&
msg
,
SOL_IPV6
,
IPV6_HOPLIMIT
,
sizeof
(
hlim
),
&
hlim
);
}
}
if
(
np
->
rxopt
.
bits
.
rxoinfo
)
{
struct
in6_pktinfo
src_info
;
src_info
.
ipi6_ifindex
=
np
->
mcast_oif
;
ipv6_addr_copy
(
&
src_info
.
ipi6_addr
,
&
np
->
daddr
);
put_cmsg
(
&
msg
,
SOL_IPV6
,
IPV6_2292PKTINFO
,
sizeof
(
src_info
),
&
src_info
);
}
if
(
np
->
rxopt
.
bits
.
rxohlim
)
{
int
hlim
=
np
->
mcast_hops
;
put_cmsg
(
&
msg
,
SOL_IPV6
,
IPV6_2292HOPLIMIT
,
sizeof
(
hlim
),
&
hlim
);
}
}
}
len
-=
msg
.
msg_controllen
;
len
-=
msg
.
msg_controllen
;
return
put_user
(
len
,
optlen
);
return
put_user
(
len
,
optlen
);
...
@@ -625,26 +746,67 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
...
@@ -625,26 +746,67 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
val
=
np
->
ipv6only
;
val
=
np
->
ipv6only
;
break
;
break
;
case
IPV6_PKTINFO
:
case
IPV6_
RECV
PKTINFO
:
val
=
np
->
rxopt
.
bits
.
rxinfo
;
val
=
np
->
rxopt
.
bits
.
rxinfo
;
break
;
break
;
case
IPV6_HOPLIMIT
:
case
IPV6_2292PKTINFO
:
val
=
np
->
rxopt
.
bits
.
rxoinfo
;
break
;
case
IPV6_RECVHOPLIMIT
:
val
=
np
->
rxopt
.
bits
.
rxhlim
;
val
=
np
->
rxopt
.
bits
.
rxhlim
;
break
;
break
;
case
IPV6_RTHDR
:
case
IPV6_2292HOPLIMIT
:
val
=
np
->
rxopt
.
bits
.
rxohlim
;
break
;
case
IPV6_RECVRTHDR
:
val
=
np
->
rxopt
.
bits
.
srcrt
;
val
=
np
->
rxopt
.
bits
.
srcrt
;
break
;
break
;
case
IPV6_2292RTHDR
:
val
=
np
->
rxopt
.
bits
.
osrcrt
;
break
;
case
IPV6_HOPOPTS
:
case
IPV6_HOPOPTS
:
case
IPV6_RTHDRDSTOPTS
:
case
IPV6_RTHDR
:
case
IPV6_DSTOPTS
:
{
lock_sock
(
sk
);
len
=
ipv6_getsockopt_sticky
(
sk
,
np
->
opt
->
hopopt
,
optval
,
len
);
release_sock
(
sk
);
return
put_user
(
len
,
optlen
);
}
case
IPV6_RECVHOPOPTS
:
val
=
np
->
rxopt
.
bits
.
hopopts
;
val
=
np
->
rxopt
.
bits
.
hopopts
;
break
;
break
;
case
IPV6_DSTOPTS
:
case
IPV6_2292HOPOPTS
:
val
=
np
->
rxopt
.
bits
.
ohopopts
;
break
;
case
IPV6_RECVDSTOPTS
:
val
=
np
->
rxopt
.
bits
.
dstopts
;
val
=
np
->
rxopt
.
bits
.
dstopts
;
break
;
break
;
case
IPV6_2292DSTOPTS
:
val
=
np
->
rxopt
.
bits
.
odstopts
;
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
;
...
...
net/ipv6/raw.c
View file @
2e66fc41
...
@@ -655,6 +655,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -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,
...
@@ -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
;
...
@@ -755,8 +756,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -755,8 +756,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
}
}
if
(
opt
==
NULL
)
if
(
opt
==
NULL
)
opt
=
np
->
opt
;
opt
=
np
->
opt
;
if
(
flowlabel
)
opt
=
fl6_merge_options
(
&
opt_space
,
flowlabel
,
opt
);
opt
=
fl6_merge_options
(
&
opt_space
,
flowlabel
,
opt
);
fl
.
proto
=
proto
;
fl
.
proto
=
proto
;
rawv6_probe_proto_opt
(
&
fl
,
msg
);
rawv6_probe_proto_opt
(
&
fl
,
msg
);
...
@@ -798,6 +798,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -798,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
;
...
@@ -806,8 +812,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -806,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
);
...
...
net/ipv6/tcp_ipv6.c
View file @
2e66fc41
...
@@ -849,7 +849,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
...
@@ -849,7 +849,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
if
(
dst
==
NULL
)
{
if
(
dst
==
NULL
)
{
opt
=
np
->
opt
;
opt
=
np
->
opt
;
if
(
opt
==
NULL
&&
if
(
opt
==
NULL
&&
np
->
rxopt
.
bits
.
srcrt
==
2
&&
np
->
rxopt
.
bits
.
o
srcrt
==
2
&&
treq
->
pktopts
)
{
treq
->
pktopts
)
{
struct
sk_buff
*
pktopts
=
treq
->
pktopts
;
struct
sk_buff
*
pktopts
=
treq
->
pktopts
;
struct
inet6_skb_parm
*
rxopt
=
IP6CB
(
pktopts
);
struct
inet6_skb_parm
*
rxopt
=
IP6CB
(
pktopts
);
...
@@ -915,11 +915,10 @@ static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
...
@@ -915,11 +915,10 @@ static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
struct
inet6_skb_parm
*
opt
=
IP6CB
(
skb
);
struct
inet6_skb_parm
*
opt
=
IP6CB
(
skb
);
if
(
np
->
rxopt
.
all
)
{
if
(
np
->
rxopt
.
all
)
{
if
((
opt
->
hop
&&
np
->
rxopt
.
bits
.
hopopts
)
||
if
((
opt
->
hop
&&
(
np
->
rxopt
.
bits
.
hopopts
||
np
->
rxopt
.
bits
.
ohopopts
))
||
((
IPV6_FLOWINFO_MASK
&*
(
u32
*
)
skb
->
nh
.
raw
)
&&
((
IPV6_FLOWINFO_MASK
&
*
(
u32
*
)
skb
->
nh
.
raw
)
&&
np
->
rxopt
.
bits
.
rxflow
)
||
np
->
rxopt
.
bits
.
rxflow
)
||
(
opt
->
srcrt
&&
(
np
->
rxopt
.
bits
.
srcrt
||
np
->
rxopt
.
bits
.
osrcrt
))
||
(
opt
->
srcrt
&&
np
->
rxopt
.
bits
.
srcrt
)
||
((
opt
->
dst1
||
opt
->
dst0
)
&&
(
np
->
rxopt
.
bits
.
dstopts
||
np
->
rxopt
.
bits
.
odstopts
)))
((
opt
->
dst1
||
opt
->
dst0
)
&&
np
->
rxopt
.
bits
.
dstopts
))
return
1
;
return
1
;
}
}
return
0
;
return
0
;
...
@@ -1190,8 +1189,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
...
@@ -1190,8 +1189,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
TCP_ECN_create_request
(
req
,
skb
->
h
.
th
);
TCP_ECN_create_request
(
req
,
skb
->
h
.
th
);
treq
->
pktopts
=
NULL
;
treq
->
pktopts
=
NULL
;
if
(
ipv6_opt_accepted
(
sk
,
skb
)
||
if
(
ipv6_opt_accepted
(
sk
,
skb
)
||
np
->
rxopt
.
bits
.
rxinfo
||
np
->
rxopt
.
bits
.
rxinfo
||
np
->
rxopt
.
bits
.
rxoinfo
||
np
->
rxopt
.
bits
.
rxhlim
)
{
np
->
rxopt
.
bits
.
rxhlim
||
np
->
rxopt
.
bits
.
rxohlim
)
{
atomic_inc
(
&
skb
->
users
);
atomic_inc
(
&
skb
->
users
);
treq
->
pktopts
=
skb
;
treq
->
pktopts
=
skb
;
}
}
...
@@ -1288,7 +1287,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
...
@@ -1288,7 +1287,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if
(
sk_acceptq_is_full
(
sk
))
if
(
sk_acceptq_is_full
(
sk
))
goto
out_overflow
;
goto
out_overflow
;
if
(
np
->
rxopt
.
bits
.
srcrt
==
2
&&
if
(
np
->
rxopt
.
bits
.
o
srcrt
==
2
&&
opt
==
NULL
&&
treq
->
pktopts
)
{
opt
==
NULL
&&
treq
->
pktopts
)
{
struct
inet6_skb_parm
*
rxopt
=
IP6CB
(
treq
->
pktopts
);
struct
inet6_skb_parm
*
rxopt
=
IP6CB
(
treq
->
pktopts
);
if
(
rxopt
->
srcrt
)
if
(
rxopt
->
srcrt
)
...
@@ -1544,9 +1543,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
...
@@ -1544,9 +1543,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
tp
=
tcp_sk
(
sk
);
tp
=
tcp_sk
(
sk
);
if
(
TCP_SKB_CB
(
opt_skb
)
->
end_seq
==
tp
->
rcv_nxt
&&
if
(
TCP_SKB_CB
(
opt_skb
)
->
end_seq
==
tp
->
rcv_nxt
&&
!
((
1
<<
sk
->
sk_state
)
&
(
TCPF_CLOSE
|
TCPF_LISTEN
)))
{
!
((
1
<<
sk
->
sk_state
)
&
(
TCPF_CLOSE
|
TCPF_LISTEN
)))
{
if
(
np
->
rxopt
.
bits
.
rxinfo
)
if
(
np
->
rxopt
.
bits
.
rxinfo
||
np
->
rxopt
.
bits
.
rxoinfo
)
np
->
mcast_oif
=
inet6_iif
(
opt_skb
);
np
->
mcast_oif
=
inet6_iif
(
opt_skb
);
if
(
np
->
rxopt
.
bits
.
rxhlim
)
if
(
np
->
rxopt
.
bits
.
rxhlim
||
np
->
rxopt
.
bits
.
rxohlim
)
np
->
mcast_hops
=
opt_skb
->
nh
.
ipv6h
->
hop_limit
;
np
->
mcast_hops
=
opt_skb
->
nh
.
ipv6h
->
hop_limit
;
if
(
ipv6_opt_accepted
(
sk
,
opt_skb
))
{
if
(
ipv6_opt_accepted
(
sk
,
opt_skb
))
{
skb_set_owner_r
(
opt_skb
,
sk
);
skb_set_owner_r
(
opt_skb
,
sk
);
...
...
net/ipv6/udp.c
View file @
2e66fc41
...
@@ -637,6 +637,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *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,
...
@@ -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
;
...
@@ -773,8 +774,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -773,8 +774,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
}
}
if
(
opt
==
NULL
)
if
(
opt
==
NULL
)
opt
=
np
->
opt
;
opt
=
np
->
opt
;
if
(
flowlabel
)
opt
=
fl6_merge_options
(
&
opt_space
,
flowlabel
,
opt
);
opt
=
fl6_merge_options
(
&
opt_space
,
flowlabel
,
opt
);
fl
->
proto
=
IPPROTO_UDP
;
fl
->
proto
=
IPPROTO_UDP
;
ipv6_addr_copy
(
&
fl
->
fl6_dst
,
daddr
);
ipv6_addr_copy
(
&
fl
->
fl6_dst
,
daddr
);
...
@@ -815,6 +815,12 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -815,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:
...
@@ -834,9 +840,10 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -834,9 +840,10 @@ 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
,
corkreq
?
msg
->
msg_flags
|
MSG_MORE
:
msg
->
msg_flags
);
(
struct
rt6_info
*
)
dst
,
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
);
else
if
(
!
corkreq
)
else
if
(
!
corkreq
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment