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
524354b4
Commit
524354b4
authored
Oct 23, 2002
by
Hideaki Yoshifuji
Committed by
David S. Miller
Oct 23, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[IPV6]: Add IPV6_V6ONLY socket option support.
parent
4f5b0080
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
154 additions
and
32 deletions
+154
-32
Documentation/networking/ip-sysctl.txt
Documentation/networking/ip-sysctl.txt
+9
-0
include/linux/in6.h
include/linux/in6.h
+1
-0
include/linux/ipv6.h
include/linux/ipv6.h
+12
-1
include/linux/sysctl.h
include/linux/sysctl.h
+2
-1
include/net/ipv6.h
include/net/ipv6.h
+3
-0
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_ipv4.c
+15
-7
net/ipv4/udp.c
net/ipv4/udp.c
+13
-7
net/ipv6/af_inet6.c
net/ipv6/af_inet6.c
+4
-1
net/ipv6/ipv6_sockglue.c
net/ipv6/ipv6_sockglue.c
+13
-1
net/ipv6/sysctl_net_ipv6.c
net/ipv6/sysctl_net_ipv6.c
+2
-0
net/ipv6/tcp_ipv6.c
net/ipv6/tcp_ipv6.c
+35
-8
net/ipv6/udp.c
net/ipv6/udp.c
+45
-6
No files found.
Documentation/networking/ip-sysctl.txt
View file @
524354b4
...
...
@@ -462,6 +462,15 @@ ak@muc.de
IPv6 has no global variables such as tcp_*. tcp_* settings under ipv4/ also
apply to IPv6 [XXX?].
bindv6only - BOOLEAN
Default value for IPV6_V6ONLY socket option,
which restricts use of the IPv6 socket to IPv6 communication
only.
TRUE: disable IPv4-mapped address feature
FALSE: enable IPv4-mapped address feature
Default: FALSE (as specified in RFC2553bis)
conf/default/*:
Change the interface-specific default settings.
...
...
include/linux/in6.h
View file @
524354b4
...
...
@@ -156,6 +156,7 @@ struct in6_flowlabel_req
#define IPV6_MTU_DISCOVER 23
#define IPV6_MTU 24
#define IPV6_RECVERR 25
#define IPV6_V6ONLY 26
/* IPV6_MTU_DISCOVER values */
#define IPV6_PMTUDISC_DONT 0
...
...
include/linux/ipv6.h
View file @
524354b4
#ifndef _IPV6_H
#define _IPV6_H
#include <linux/config.h>
#include <linux/in6.h>
#include <asm/byteorder.h>
...
...
@@ -152,7 +153,8 @@ struct ipv6_pinfo {
__u8
mc_loop
:
1
,
recverr:
1
,
sndflow:
1
,
pmtudisc:
2
;
pmtudisc:
2
,
ipv6only:
1
;
struct
ipv6_mc_socklist
*
ipv6_mc_list
;
struct
ipv6_fl_socklist
*
ipv6_fl_list
;
...
...
@@ -195,6 +197,15 @@ struct tcp6_sock {
#define inet6_sk(__sk) ((struct raw6_sock *)__sk)->pinet6
#define raw6_sk(__sk) (&((struct raw6_sock *)__sk)->raw6)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only)
#define ipv6_only_sock(sk) ((sk)->family == PF_INET6 && __ipv6_only_sock(sk))
#else
#define __ipv6_only_sock(sk) 0
#define ipv6_only_sock(sk) 0
#endif
#endif
#endif
include/linux/sysctl.h
View file @
524354b4
...
...
@@ -357,7 +357,8 @@ enum
enum
{
NET_IPV6_CONF
=
16
,
NET_IPV6_NEIGH
=
17
,
NET_IPV6_ROUTE
=
18
NET_IPV6_ROUTE
=
18
,
NET_IPV6_BINDV6ONLY
=
20
,
};
enum
{
...
...
include/net/ipv6.h
View file @
524354b4
...
...
@@ -102,6 +102,9 @@ struct frag_hdr {
#include <net/sock.h>
/* sysctls */
extern
int
sysctl_ipv6_bindv6only
;
extern
struct
ipv6_mib
ipv6_statistics
[
NR_CPUS
*
2
];
#define IP6_INC_STATS(field) SNMP_INC_STATS(ipv6_statistics, field)
#define IP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(ipv6_statistics, field)
...
...
net/ipv4/tcp_ipv4.c
View file @
524354b4
...
...
@@ -47,9 +47,13 @@
* coma.
* Andi Kleen : Fix new listen.
* Andi Kleen : Fix accept error reporting.
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
* a single port at the same time.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/random.h>
...
...
@@ -62,6 +66,7 @@
#include <net/inet_common.h>
#include <linux/inet.h>
#include <linux/ipv6.h>
#include <linux/stddef.h>
#include <linux/ipsec.h>
...
...
@@ -176,7 +181,9 @@ static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
int
sk_reuse
=
sk
->
reuse
;
for
(
;
sk2
;
sk2
=
sk2
->
bind_next
)
{
if
(
sk
!=
sk2
&&
sk
->
bound_dev_if
==
sk2
->
bound_dev_if
)
{
if
(
sk
!=
sk2
&&
!
ipv6_only_sock
(
sk2
)
&&
sk
->
bound_dev_if
==
sk2
->
bound_dev_if
)
{
if
(
!
sk_reuse
||
!
sk2
->
reuse
||
sk2
->
state
==
TCP_LISTEN
)
{
struct
inet_opt
*
inet2
=
inet_sk
(
sk2
);
...
...
@@ -412,25 +419,25 @@ static struct sock *__tcp_v4_lookup_listener(struct sock *sk, u32 daddr,
struct
sock
*
result
=
NULL
;
int
score
,
hiscore
;
hiscore
=
0
;
hiscore
=
-
1
;
for
(;
sk
;
sk
=
sk
->
next
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
if
(
inet
->
num
==
hnum
)
{
if
(
inet
->
num
==
hnum
&&
!
ipv6_only_sock
(
sk
)
)
{
__u32
rcv_saddr
=
inet
->
rcv_saddr
;
score
=
1
;
score
=
(
sk
->
family
==
PF_INET
?
1
:
0
)
;
if
(
rcv_saddr
)
{
if
(
rcv_saddr
!=
daddr
)
continue
;
score
+
+
;
score
+
=
2
;
}
if
(
sk
->
bound_dev_if
)
{
if
(
sk
->
bound_dev_if
!=
dif
)
continue
;
score
+
+
;
score
+
=
2
;
}
if
(
score
==
3
)
if
(
score
==
5
)
return
sk
;
if
(
score
>
hiscore
)
{
hiscore
=
score
;
...
...
@@ -454,6 +461,7 @@ __inline__ struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum,
if
(
inet
->
num
==
hnum
&&
!
sk
->
next
&&
(
!
inet
->
rcv_saddr
||
inet
->
rcv_saddr
==
daddr
)
&&
(
sk
->
family
==
PF_INET
||
!
ipv6_only_sock
(
sk
))
&&
!
sk
->
bound_dev_if
)
goto
sherry_cache
;
sk
=
__tcp_v4_lookup_listener
(
sk
,
daddr
,
hnum
,
dif
);
...
...
net/ipv4/udp.c
View file @
524354b4
...
...
@@ -66,6 +66,9 @@
* datagrams.
* Hirokazu Takahashi : sendfile() on UDP works now.
* Arnaldo C. Melo : convert /proc/net/udp to seq_file
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind
* a single port at the same time.
*
*
* This program is free software; you can redistribute it and/or
...
...
@@ -87,6 +90,7 @@
#include <linux/mm.h>
#include <linux/config.h>
#include <linux/inet.h>
#include <linux/ipv6.h>
#include <linux/netdevice.h>
#include <net/snmp.h>
#include <net/tcp.h>
...
...
@@ -170,6 +174,7 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum)
if
(
inet2
->
num
==
snum
&&
sk2
!=
sk
&&
!
ipv6_only_sock
(
sk2
)
&&
sk2
->
bound_dev_if
==
sk
->
bound_dev_if
&&
(
!
inet2
->
rcv_saddr
||
!
inet
->
rcv_saddr
||
...
...
@@ -228,29 +233,29 @@ struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, i
for
(
sk
=
udp_hash
[
hnum
&
(
UDP_HTABLE_SIZE
-
1
)];
sk
!=
NULL
;
sk
=
sk
->
next
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
if
(
inet
->
num
==
hnum
)
{
int
score
=
0
;
if
(
inet
->
num
==
hnum
&&
!
ipv6_only_sock
(
sk
)
)
{
int
score
=
(
sk
->
family
==
PF_INET
?
1
:
0
)
;
if
(
inet
->
rcv_saddr
)
{
if
(
inet
->
rcv_saddr
!=
daddr
)
continue
;
score
+
+
;
score
+
=
2
;
}
if
(
inet
->
daddr
)
{
if
(
inet
->
daddr
!=
saddr
)
continue
;
score
+
+
;
score
+
=
2
;
}
if
(
inet
->
dport
)
{
if
(
inet
->
dport
!=
sport
)
continue
;
score
+
+
;
score
+
=
2
;
}
if
(
sk
->
bound_dev_if
)
{
if
(
sk
->
bound_dev_if
!=
dif
)
continue
;
score
+
+
;
score
+
=
2
;
}
if
(
score
==
4
)
{
if
(
score
==
9
)
{
result
=
sk
;
break
;
}
else
if
(
score
>
badness
)
{
...
...
@@ -288,6 +293,7 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk,
(
inet
->
daddr
&&
inet
->
daddr
!=
rmt_addr
)
||
(
inet
->
dport
!=
rmt_port
&&
inet
->
dport
)
||
(
inet
->
rcv_saddr
&&
inet
->
rcv_saddr
!=
loc_addr
)
||
ipv6_only_sock
(
s
)
||
(
s
->
bound_dev_if
&&
s
->
bound_dev_if
!=
dif
))
continue
;
break
;
...
...
net/ipv6/af_inet6.c
View file @
524354b4
...
...
@@ -88,6 +88,8 @@ extern void ipv6_sysctl_register(void);
extern
void
ipv6_sysctl_unregister
(
void
);
#endif
int
sysctl_ipv6_bindv6only
;
#ifdef INET_REFCNT_DEBUG
atomic_t
inet6_sock_nr
;
#endif
...
...
@@ -218,7 +220,8 @@ static int inet6_create(struct socket *sock, int protocol)
np
->
mcast_hops
=
-
1
;
np
->
mc_loop
=
1
;
np
->
pmtudisc
=
IPV6_PMTUDISC_WANT
;
np
->
ipv6only
=
sysctl_ipv6_bindv6only
;
/* Init the ipv4 part of the socket since we can have sockets
* using v6 API for ipv4.
*/
...
...
net/ipv6/ipv6_sockglue.c
View file @
524354b4
...
...
@@ -157,7 +157,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
break
;
}
if
(
!
(
ipv6_addr_type
(
&
np
->
daddr
)
&
IPV6_ADDR_MAPPED
))
{
if
(
ipv6_only_sock
(
sk
)
||
!
(
ipv6_addr_type
(
&
np
->
daddr
)
&
IPV6_ADDR_MAPPED
))
{
retv
=
-
EADDRNOTAVAIL
;
break
;
}
...
...
@@ -203,6 +204,13 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
}
goto
e_inval
;
case
IPV6_V6ONLY
:
if
(
inet_sk
(
sk
)
->
num
)
goto
e_inval
;
np
->
ipv6only
=
valbool
;
retv
=
0
;
break
;
case
IPV6_PKTINFO
:
np
->
rxopt
.
bits
.
rxinfo
=
valbool
;
retv
=
0
;
...
...
@@ -475,6 +483,10 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
break
;
}
case
IPV6_V6ONLY
:
val
=
np
->
ipv6only
;
break
;
case
IPV6_PKTINFO
:
val
=
np
->
rxopt
.
bits
.
rxinfo
;
break
;
...
...
net/ipv6/sysctl_net_ipv6.c
View file @
524354b4
...
...
@@ -17,6 +17,8 @@ extern ctl_table ipv6_route_table[];
ctl_table
ipv6_table
[]
=
{
{
NET_IPV6_ROUTE
,
"route"
,
NULL
,
0
,
0555
,
ipv6_route_table
},
{
NET_IPV6_BINDV6ONLY
,
"bindv6only"
,
&
sysctl_ipv6_bindv6only
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
0
}
};
...
...
net/ipv6/tcp_ipv6.c
View file @
524354b4
...
...
@@ -14,6 +14,9 @@
*
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
* a single port at the same time.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -90,14 +93,35 @@ static inline int ipv6_rcv_saddr_equal(struct sock *sk, struct sock *sk2)
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
int
addr_type
=
ipv6_addr_type
(
&
np
->
rcv_saddr
);
return
!
inet_sk
(
sk2
)
->
rcv_saddr
||
addr_type
==
IPV6_ADDR_ANY
||
(
sk2
->
family
==
AF_INET6
&&
!
ipv6_addr_cmp
(
&
np
->
rcv_saddr
,
sk2
->
state
!=
TCP_TIME_WAIT
?
&
inet6_sk
(
sk2
)
->
rcv_saddr
:
&
((
struct
tcp_tw_bucket
*
)
sk
)
->
v6_rcv_saddr
))
||
(
addr_type
==
IPV6_ADDR_MAPPED
&&
sk2
->
family
==
AF_INET
&&
inet_sk
(
sk
)
->
rcv_saddr
==
inet_sk
(
sk2
)
->
rcv_saddr
);
if
(
!
inet_sk
(
sk2
)
->
rcv_saddr
&&
!
ipv6_only_sock
(
sk
))
return
1
;
if
(
sk2
->
family
==
AF_INET6
&&
ipv6_addr_any
(
&
inet6_sk
(
sk2
)
->
rcv_saddr
)
&&
!
(
ipv6_only_sock
(
sk2
)
&&
addr_type
==
IPV6_ADDR_MAPPED
))
return
1
;
if
(
addr_type
==
IPV6_ADDR_ANY
&&
(
!
ipv6_only_sock
(
sk
)
||
!
(
sk2
->
family
==
AF_INET6
?
ipv6_addr_type
(
&
inet6_sk
(
sk2
)
->
rcv_saddr
)
==
IPV6_ADDR_MAPPED
:
1
)))
return
1
;
if
(
sk2
->
family
==
AF_INET6
&&
!
ipv6_addr_cmp
(
&
np
->
rcv_saddr
,
(
sk2
->
state
!=
TCP_TIME_WAIT
?
&
inet6_sk
(
sk2
)
->
rcv_saddr
:
&
((
struct
tcp_tw_bucket
*
)
sk
)
->
v6_rcv_saddr
)))
return
1
;
if
(
addr_type
==
IPV6_ADDR_MAPPED
&&
!
ipv6_only_sock
(
sk2
)
&&
(
!
inet_sk
(
sk2
)
->
rcv_saddr
||
!
inet_sk
(
sk
)
->
rcv_saddr
||
inet_sk
(
sk
)
->
rcv_saddr
==
inet_sk
(
sk2
)
->
rcv_saddr
))
return
1
;
return
0
;
}
static
inline
int
tcp_v6_bind_conflict
(
struct
sock
*
sk
,
...
...
@@ -612,6 +636,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
SOCK_DEBUG
(
sk
,
"connect: ipv4 mapped
\n
"
);
if
(
__ipv6_only_sock
(
sk
))
return
-
ENETUNREACH
;
sin
.
sin_family
=
AF_INET
;
sin
.
sin_port
=
usin
->
sin6_port
;
sin
.
sin_addr
.
s_addr
=
usin
->
sin6_addr
.
s6_addr32
[
3
];
...
...
net/ipv6/udp.c
View file @
524354b4
...
...
@@ -11,6 +11,9 @@
*
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
* Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
* a single port at the same time.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -50,16 +53,41 @@
struct
udp_mib
udp_stats_in6
[
NR_CPUS
*
2
];
/* XXX This is identical to tcp_ipv6.c:ipv6_rcv_saddr_equal, put
* XXX it somewhere common. -DaveM
*/
static
__inline__
int
udv6_rcv_saddr_equal
(
struct
sock
*
sk
,
struct
sock
*
sk2
)
{
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
int
addr_type
=
ipv6_addr_type
(
&
np
->
rcv_saddr
);
return
!
inet_sk
(
sk2
)
->
rcv_saddr
||
addr_type
==
IPV6_ADDR_ANY
||
(
sk2
->
family
==
AF_INET6
&&
!
ipv6_addr_cmp
(
&
np
->
rcv_saddr
,
&
inet6_sk
(
sk2
)
->
rcv_saddr
))
||
(
addr_type
==
IPV6_ADDR_MAPPED
&&
sk2
->
family
==
AF_INET
&&
inet_sk
(
sk
)
->
rcv_saddr
==
inet_sk
(
sk2
)
->
rcv_saddr
);
if
(
!
inet_sk
(
sk2
)
->
rcv_saddr
&&
!
ipv6_only_sock
(
sk
))
return
1
;
if
(
sk2
->
family
==
AF_INET6
&&
ipv6_addr_any
(
&
inet6_sk
(
sk2
)
->
rcv_saddr
)
&&
!
(
ipv6_only_sock
(
sk2
)
&&
addr_type
==
IPV6_ADDR_MAPPED
))
return
1
;
if
(
addr_type
==
IPV6_ADDR_ANY
&&
(
!
ipv6_only_sock
(
sk
)
||
!
(
sk2
->
family
==
AF_INET6
?
(
ipv6_addr_type
(
&
inet6_sk
(
sk2
)
->
rcv_saddr
)
==
IPV6_ADDR_MAPPED
)
:
1
)))
return
1
;
if
(
sk2
->
family
==
AF_INET6
&&
!
ipv6_addr_cmp
(
&
inet6_sk
(
sk
)
->
rcv_saddr
,
&
inet6_sk
(
sk2
)
->
rcv_saddr
))
return
1
;
if
(
addr_type
==
IPV6_ADDR_MAPPED
&&
!
ipv6_only_sock
(
sk2
)
&&
(
!
inet_sk
(
sk2
)
->
rcv_saddr
||
!
inet_sk
(
sk
)
->
rcv_saddr
||
inet_sk
(
sk
)
->
rcv_saddr
==
inet_sk
(
sk2
)
->
rcv_saddr
))
return
1
;
return
0
;
}
/* Grrr, addr_type already calculated by caller, but I don't want
...
...
@@ -228,6 +256,8 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
int
err
;
if
(
usin
->
sin6_family
==
AF_INET
)
{
if
(
__ipv6_only_sock
(
sk
))
return
-
EAFNOSUPPORT
;
err
=
udp_connect
(
sk
,
uaddr
,
addr_len
);
goto
ipv4_connected
;
}
...
...
@@ -263,6 +293,9 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if
(
addr_type
==
IPV6_ADDR_MAPPED
)
{
struct
sockaddr_in
sin
;
if
(
__ipv6_only_sock
(
sk
))
return
-
ENETUNREACH
;
sin
.
sin_family
=
AF_INET
;
sin
.
sin_addr
.
s_addr
=
daddr
->
s6_addr32
[
3
];
sin
.
sin_port
=
usin
->
sin6_port
;
...
...
@@ -793,8 +826,11 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
fl
.
oif
=
0
;
if
(
sin6
)
{
if
(
sin6
->
sin6_family
==
AF_INET
)
if
(
sin6
->
sin6_family
==
AF_INET
)
{
if
(
__ipv6_only_sock
(
sk
))
return
-
ENETUNREACH
;
return
udp_sendmsg
(
iocb
,
sk
,
msg
,
ulen
);
}
if
(
addr_len
<
SIN6_LEN_RFC2133
)
return
-
EINVAL
;
...
...
@@ -841,6 +877,9 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
if
(
addr_type
==
IPV6_ADDR_MAPPED
)
{
struct
sockaddr_in
sin
;
if
(
__ipv6_only_sock
(
sk
))
return
-
ENETUNREACH
;
sin
.
sin_family
=
AF_INET
;
sin
.
sin_addr
.
s_addr
=
daddr
->
s6_addr32
[
3
];
sin
.
sin_port
=
udh
.
uh
.
dest
;
...
...
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